summaryrefslogtreecommitdiff
path: root/vcl/unx/generic
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/generic')
-rw-r--r--vcl/unx/generic/app/i18n_cb.cxx658
-rw-r--r--vcl/unx/generic/app/i18n_ic.cxx783
-rw-r--r--vcl/unx/generic/app/i18n_im.cxx621
-rw-r--r--vcl/unx/generic/app/i18n_keysym.cxx368
-rw-r--r--vcl/unx/generic/app/i18n_status.cxx735
-rw-r--r--vcl/unx/generic/app/i18n_wrp.cxx262
-rw-r--r--vcl/unx/generic/app/i18n_xkb.cxx165
-rw-r--r--vcl/unx/generic/app/keysymnames.cxx692
-rw-r--r--vcl/unx/generic/app/randrwrapper.cxx363
-rw-r--r--vcl/unx/generic/app/saldata.cxx875
-rw-r--r--vcl/unx/generic/app/saldisp.cxx3535
-rw-r--r--vcl/unx/generic/app/salinst.cxx455
-rw-r--r--vcl/unx/generic/app/salsys.cxx229
-rw-r--r--vcl/unx/generic/app/saltimer.cxx98
-rw-r--r--vcl/unx/generic/app/sm.cxx806
-rw-r--r--vcl/unx/generic/app/soicon.cxx118
-rw-r--r--vcl/unx/generic/app/wmadaptor.cxx2551
-rw-r--r--vcl/unx/generic/desktopdetect/desktopdetector.cxx356
-rw-r--r--vcl/unx/generic/dtrans/X11_clipboard.cxx296
-rw-r--r--vcl/unx/generic/dtrans/X11_clipboard.hxx150
-rw-r--r--vcl/unx/generic/dtrans/X11_dndcontext.cxx141
-rw-r--r--vcl/unx/generic/dtrans/X11_dndcontext.hxx107
-rw-r--r--vcl/unx/generic/dtrans/X11_droptarget.cxx231
-rw-r--r--vcl/unx/generic/dtrans/X11_selection.cxx4193
-rw-r--r--vcl/unx/generic/dtrans/X11_selection.hxx533
-rw-r--r--vcl/unx/generic/dtrans/X11_service.cxx144
-rw-r--r--vcl/unx/generic/dtrans/X11_transferable.cxx136
-rw-r--r--vcl/unx/generic/dtrans/X11_transferable.hxx73
-rw-r--r--vcl/unx/generic/dtrans/bmp.cxx742
-rw-r--r--vcl/unx/generic/dtrans/bmp.hxx108
-rw-r--r--vcl/unx/generic/dtrans/config.cxx151
-rw-r--r--vcl/unx/generic/dtrans/copydata_curs.h45
-rw-r--r--vcl/unx/generic/dtrans/copydata_mask.h45
-rw-r--r--vcl/unx/generic/dtrans/linkdata_curs.h45
-rw-r--r--vcl/unx/generic/dtrans/linkdata_mask.h45
-rw-r--r--vcl/unx/generic/dtrans/movedata_curs.h45
-rw-r--r--vcl/unx/generic/dtrans/movedata_mask.h45
-rw-r--r--vcl/unx/generic/dtrans/nodrop_curs.h45
-rw-r--r--vcl/unx/generic/dtrans/nodrop_mask.h45
-rw-r--r--vcl/unx/generic/fontmanager/adobeenc.tab1087
-rwxr-xr-xvcl/unx/generic/fontmanager/afm_keyword_list62
-rw-r--r--vcl/unx/generic/fontmanager/fontcache.cxx817
-rw-r--r--vcl/unx/generic/fontmanager/fontconfig.cxx1444
-rw-r--r--vcl/unx/generic/fontmanager/fontmanager.cxx4132
-rw-r--r--vcl/unx/generic/fontmanager/helper.cxx411
-rw-r--r--vcl/unx/generic/fontmanager/parseAFM.cxx1492
-rw-r--r--vcl/unx/generic/fontmanager/parseAFM.hxx337
-rw-r--r--vcl/unx/generic/gdi/cdeint.cxx247
-rw-r--r--vcl/unx/generic/gdi/dtint.cxx143
-rw-r--r--vcl/unx/generic/gdi/dtsetenum.hxx149
-rw-r--r--vcl/unx/generic/gdi/gcach_xpeer.cxx685
-rw-r--r--vcl/unx/generic/gdi/gcach_xpeer.hxx95
-rw-r--r--vcl/unx/generic/gdi/pspgraphics.cxx1504
-rw-r--r--vcl/unx/generic/gdi/salbmp.cxx1160
-rw-r--r--vcl/unx/generic/gdi/salcvt.cxx343
-rw-r--r--vcl/unx/generic/gdi/salcvt.hxx95
-rw-r--r--vcl/unx/generic/gdi/salgdi.cxx1247
-rw-r--r--vcl/unx/generic/gdi/salgdi2.cxx1154
-rw-r--r--vcl/unx/generic/gdi/salgdi3.cxx1695
-rw-r--r--vcl/unx/generic/gdi/salprnpsp.cxx1489
-rw-r--r--vcl/unx/generic/gdi/salvd.cxx276
-rw-r--r--vcl/unx/generic/gdi/xrender_peer.cxx246
-rw-r--r--vcl/unx/generic/gdi/xrender_peer.hxx380
-rw-r--r--vcl/unx/generic/plugadapt/salplug.cxx309
-rw-r--r--vcl/unx/generic/printer/cupsmgr.cxx1181
-rw-r--r--vcl/unx/generic/printer/jobdata.cxx267
-rw-r--r--vcl/unx/generic/printer/ppdparser.cxx2187
-rw-r--r--vcl/unx/generic/printer/printerinfomanager.cxx1438
-rw-r--r--vcl/unx/generic/printergfx/bitmap_gfx.cxx735
-rw-r--r--vcl/unx/generic/printergfx/common_gfx.cxx1287
-rw-r--r--vcl/unx/generic/printergfx/glyphset.cxx949
-rw-r--r--vcl/unx/generic/printergfx/glyphset.hxx137
-rw-r--r--vcl/unx/generic/printergfx/printerjob.cxx1212
-rw-r--r--vcl/unx/generic/printergfx/psheader.ps368
-rw-r--r--vcl/unx/generic/printergfx/psputil.cxx271
-rw-r--r--vcl/unx/generic/printergfx/psputil.hxx80
-rw-r--r--vcl/unx/generic/printergfx/text_gfx.cxx865
-rw-r--r--vcl/unx/generic/window/FWS.cxx282
-rw-r--r--vcl/unx/generic/window/FWS.hxx66
-rw-r--r--vcl/unx/generic/window/salframe.cxx4567
-rw-r--r--vcl/unx/generic/window/salobj.cxx569
81 files changed, 58495 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..92429e63c91e
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_cb.cxx
@@ -0,0 +1,658 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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
+ {
+ // 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
+sal_uInt16*
+Preedit_FeedbackToSAL ( XIMFeedback* pfeedback, int nlength, std::vector<sal_uInt16>& rSalAttr )
+{
+ sal_uInt16 *psalattr;
+ sal_uInt16 nval;
+ sal_uInt16 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 (sal_uInt16*)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;
+
+ }
+ // 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;
+
+ // 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 */ )
+ 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;
+
+ // 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();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/i18n_ic.cxx b/vcl/unx/generic/app/i18n_ic.cxx
new file mode 100644
index 000000000000..8a8b5d620cb6
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_ic.cxx
@@ -0,0 +1,783 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 = sal_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 || defined OPENBSD || defined DRAGONFLY
+ if ( mpPreeditAttributes != NULL )
+#endif
+ mpAttributes = XVaAddToNestedList( mpAttributes,
+ const_cast<char*>(XNPreeditAttributes), (XPointer)mpPreeditAttributes );
+ }
+ if ( mnStatusStyle != XIMStatusNone )
+ {
+#if defined LINUX || defined FREEBSD || defined NETBSD || defined OPENBSD || defined DRAGONFLY
+ 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 )
+{
+ mnPreeditStyle = 0;
+ mnStatusStyle = 0;
+
+ if ( pIMStyles != NULL )
+ {
+ int nBestScore = 0;
+ int nActualScore = 0;
+
+ // 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( sal_uInt16 /*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 );
+ }
+ }
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/i18n_im.cxx b/vcl/unx/generic/app/i18n_im.cxx
new file mode 100644
index 000000000000..5d30d74455ae
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_im.cxx
@@ -0,0 +1,621 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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;
+}
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/i18n_keysym.cxx b/vcl/unx/generic/app/i18n_keysym.cxx
new file mode 100644
index 000000000000..2e2005f1a874
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_keysym.cxx
@@ -0,0 +1,368 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/i18n_status.cxx b/vcl/unx/generic/app/i18n_status.cxx
new file mode 100644
index 000000000000..8cae9d12eedd
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_status.cxx
@@ -0,0 +1,735 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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;
+
+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;
+ sal_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( sal_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( sal_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( sal_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( sal_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();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/i18n_wrp.cxx b/vcl/unx/generic/app/i18n_wrp.cxx
new file mode 100644
index 000000000000..981dc390e278
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_wrp.cxx
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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);
+}
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/i18n_xkb.cxx b/vcl/unx/generic/app/i18n_xkb.cxx
new file mode 100644
index 000000000000..cb93f48b6bd7
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_xkb.cxx
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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__
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/keysymnames.cxx b/vcl/unx/generic/app/keysymnames.cxx
new file mode 100644
index 000000000000..0615a2d44450
--- /dev/null
+++ b/vcl/unx/generic/app/keysymnames.cxx
@@ -0,0 +1,692 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 !defined(SOLARIS) && !defined(AIX)
+#include <tools/prex.h>
+#include <X11/XKBlib.h>
+#include <tools/postx.h>
+#endif
+
+#include <unx/saldisp.hxx>
+#include <X11/keysym.h>
+#include <sal/macros.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, SAL_N_ELEMENTS(aImplReplacements_German) },
+ { "Germany4", aImplReplacements_German, SAL_N_ELEMENTS(aImplReplacements_German) },
+ { "France5", aImplReplacements_French, SAL_N_ELEMENTS(aImplReplacements_French) },
+ { "France6", aImplReplacements_French, SAL_N_ELEMENTS(aImplReplacements_French) },
+ { "France_x86", aImplReplacements_French, SAL_N_ELEMENTS(aImplReplacements_French) },
+ { "Italy5", aImplReplacements_Italian, SAL_N_ELEMENTS(aImplReplacements_Italian) },
+ { "Italy5-Hobo", aImplReplacements_Italian, SAL_N_ELEMENTS(aImplReplacements_Italian) },
+ { "Italy4", aImplReplacements_Italian, SAL_N_ELEMENTS(aImplReplacements_Italian) },
+ { "Italy6", aImplReplacements_Italian, SAL_N_ELEMENTS(aImplReplacements_Italian) },
+ { "Italy_x86", aImplReplacements_Italian, SAL_N_ELEMENTS(aImplReplacements_Italian) },
+ { "Netherland4", aImplReplacements_Dutch, SAL_N_ELEMENTS(aImplReplacements_Dutch) },
+ { "Netherland5", aImplReplacements_Dutch, SAL_N_ELEMENTS(aImplReplacements_Dutch) },
+ { "Netherland5-Hobo", aImplReplacements_Dutch, SAL_N_ELEMENTS(aImplReplacements_Dutch) },
+ { "Netherland6", aImplReplacements_Dutch, SAL_N_ELEMENTS(aImplReplacements_Dutch) },
+ { "Netherland_x86", aImplReplacements_Dutch, SAL_N_ELEMENTS(aImplReplacements_Dutch) },
+ { "Norway5", aImplReplacements_Norwegian, SAL_N_ELEMENTS(aImplReplacements_Norwegian) },
+ { "Norway5-Hobo", aImplReplacements_Norwegian, SAL_N_ELEMENTS(aImplReplacements_Norwegian) },
+ { "Norway4", aImplReplacements_Norwegian, SAL_N_ELEMENTS(aImplReplacements_Norwegian) },
+ { "Norway6", aImplReplacements_Norwegian, SAL_N_ELEMENTS(aImplReplacements_Norwegian) },
+ { "Norway_x86", aImplReplacements_Norwegian, SAL_N_ELEMENTS(aImplReplacements_Norwegian) },
+ { "Portugal5", aImplReplacements_Portuguese, SAL_N_ELEMENTS(aImplReplacements_Portuguese) },
+ { "Portugal5-Hobo", aImplReplacements_Portuguese, SAL_N_ELEMENTS(aImplReplacements_Portuguese) },
+ { "Portugal4", aImplReplacements_Portuguese, SAL_N_ELEMENTS(aImplReplacements_Portuguese) },
+ { "Portugal6", aImplReplacements_Portuguese, SAL_N_ELEMENTS(aImplReplacements_Portuguese) },
+ { "Portugal_x86", aImplReplacements_Portuguese, SAL_N_ELEMENTS(aImplReplacements_Portuguese) },
+ { "Spain5", aImplReplacements_Spanish, SAL_N_ELEMENTS(aImplReplacements_Spanish) },
+ { "Spain5-Hobo", aImplReplacements_Spanish, SAL_N_ELEMENTS(aImplReplacements_Spanish) },
+ { "Spain4", aImplReplacements_Spanish, SAL_N_ELEMENTS(aImplReplacements_Spanish) },
+ { "Spain6", aImplReplacements_Spanish, SAL_N_ELEMENTS(aImplReplacements_Spanish) },
+ { "Spain_x86", aImplReplacements_Spanish, SAL_N_ELEMENTS(aImplReplacements_Spanish) },
+ { "Sweden5", aImplReplacements_Swedish, SAL_N_ELEMENTS(aImplReplacements_Swedish) },
+ { "Sweden5-Hobo", aImplReplacements_Swedish, SAL_N_ELEMENTS(aImplReplacements_Swedish) },
+ { "Sweden4", aImplReplacements_Swedish, SAL_N_ELEMENTS(aImplReplacements_Swedish) },
+ { "Sweden6", aImplReplacements_Swedish, SAL_N_ELEMENTS(aImplReplacements_Swedish) },
+ { "Sweden_x86", aImplReplacements_Swedish, SAL_N_ELEMENTS(aImplReplacements_Swedish) },
+#endif
+ { "U.S. English", aImplReplacements_English, SAL_N_ELEMENTS(aImplReplacements_English) },
+ { "United Kingdom", aImplReplacements_English, SAL_N_ELEMENTS(aImplReplacements_English) },
+ // Germany, German
+ { "German", aImplReplacements_German, SAL_N_ELEMENTS(aImplReplacements_German) },
+ { "France", aImplReplacements_French, SAL_N_ELEMENTS(aImplReplacements_French) },
+ { "French", aImplReplacements_French, SAL_N_ELEMENTS(aImplReplacements_French) },
+ // Italy, Italian
+ { "Ital", aImplReplacements_Italian, SAL_N_ELEMENTS(aImplReplacements_Italian) },
+ // Norway, Norwegian
+ { "Norw", aImplReplacements_Norwegian, SAL_N_ELEMENTS(aImplReplacements_Norwegian) },
+ // Portugal, Portuguese
+ { "Portu", aImplReplacements_Portuguese, SAL_N_ELEMENTS(aImplReplacements_Portuguese) },
+ { "Spain", aImplReplacements_Spanish, SAL_N_ELEMENTS(aImplReplacements_Spanish) },
+ { "Spanish", aImplReplacements_Spanish, SAL_N_ELEMENTS(aImplReplacements_Spanish) },
+ // Sweden, Swedish
+ { "Swed", aImplReplacements_Swedish, SAL_N_ELEMENTS(aImplReplacements_Swedish) },
+ { "Netherland", aImplReplacements_Dutch, SAL_N_ELEMENTS(aImplReplacements_Dutch) },
+ { "Dutch", aImplReplacements_Dutch, SAL_N_ELEMENTS(aImplReplacements_Dutch) },
+ // Turkish, Turkey
+ { "Turk", aImplReplacements_Turkish, SAL_N_ELEMENTS(aImplReplacements_Turkish) },
+ // Russian, Russia
+ { "Russia", aImplReplacements_Russian, SAL_N_ELEMENTS(aImplReplacements_Russian) },
+ { "English", aImplReplacements_English, SAL_N_ELEMENTS(aImplReplacements_English) }
+ };
+
+ String getKeysymReplacementName( const char* pKeyboard, KeySym nSymbol )
+ {
+ for( unsigned int n = 0; n < SAL_N_ELEMENTS(aKeyboards); 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 = SAL_N_ELEMENTS(aImplReplacements_English); 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() )
+ {
+#if defined(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);
+ }
+ }
+#elif !defined(AIX)
+ 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();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/randrwrapper.cxx b/vcl/unx/generic/app/randrwrapper.cxx
new file mode 100644
index 000000000000..316bde14a83a
--- /dev/null
+++ b/vcl/unx/generic/app/randrwrapper.cxx
@@ -0,0 +1,363 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/saldata.cxx b/vcl/unx/generic/app/saldata.cxx
new file mode 100644
index 000000000000..233582c07f6e
--- /dev/null
+++ b/vcl/unx/generic/app/saldata.cxx
@@ -0,0 +1,875 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <osl/process.h>
+#include <osl/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 <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();
+}
+
+const rtl::OUString& X11SalData::GetLocalHostName()
+{
+ if (!maLocalHostName.getLength())
+ osl_getLocalHostname( &maLocalHostName.pData );
+ return maLocalHostName;
+}
+
+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?
+
+ sal_uInt32 nParams = osl_getCommandArgCount();
+ rtl::OUString aParam;
+ rtl::OString aDisplay;
+ for (sal_uInt16 i=0; i<nParams; i++)
+ {
+ osl_getCommandArg(i, &aParam.pData);
+ if (aParam.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("-display")))
+ {
+ osl_getCommandArg(i+1, &aParam.pData);
+ 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( ! HasXErrorOccurred() );
+ 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 occurred 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();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/saldisp.cxx b/vcl/unx/generic/app/saldisp.cxx
new file mode 100644
index 000000000000..5f94db2f1b37
--- /dev/null
+++ b/vcl/unx/generic/app/saldisp.cxx
@@ -0,0 +1,3535 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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) || defined(AIX)
+#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/XKBlib.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>
+#include <osl/mutex.h>
+#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 vcl_sal;
+
+using ::rtl::OUString;
+
+// -=-= #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 sal_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 sal_False;
+
+ rVI = *pInfos;
+ XFree( pInfos );
+
+ DBG_ASSERT( rVI.visualid == nVID,
+ "sal_GetVisualInfo: could not get correct visual by visualId" );
+ return sal_True;
+}
+
+// ---------------------------------------------------------------------------
+
+// check wether displaystring is in format N.M or N. or just N
+// with N and M beeing natural numbers
+static sal_Bool
+sal_IsDisplayNumber( const char *pDisplayString )
+{
+ if ( ! isdigit(*pDisplayString) )
+ return sal_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 sal_Bool
+sal_EqualHosts( const OUString& Host1, const OUString& Host2)
+{
+ oslSocketAddr pHostAddr1;
+ oslSocketAddr pHostAddr2;
+ sal_Bool bEqualAddress = sal_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 ) ? sal_True : sal_False;
+
+ if( pHostAddr1 )
+ osl_destroySocketAddr( pHostAddr1 );
+ if( pHostAddr2 )
+ osl_destroySocketAddr( pHostAddr2 );
+
+ return bEqualAddress;
+}
+
+static sal_Bool
+sal_IsLocalDisplay( Display *pDisplay )
+{
+ const char *pDisplayString = DisplayString( pDisplay );
+
+ // no string, no idea
+ if ( pDisplayString == NULL || pDisplayString[ 0 ] == '\0')
+ return sal_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
+ sal_Bool bEqual = sal_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
+
+sal_Bool SalDisplay::IsLocal()
+{
+ if ( ! mbLocalIsValid )
+ {
+ bLocal_ = sal_IsLocalDisplay( pDisp_ );
+ mbLocalIsValid = sal_True;
+ }
+ return (sal_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 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+sal_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++ )
+ {
+ sal_Bool bUsable = sal_False;
+ int nTrueColor = 1;
+
+ if ( pVInfos[i].screen != nScreen )
+ {
+ bUsable = sal_False;
+ }
+ else
+ if( pVInfos[i].c_class == TrueColor )
+ {
+ nTrueColor = 2048;
+ if( pVInfos[i].depth == 24 )
+ bUsable = sal_True;
+#ifdef sal_TrueCOLOR8
+ else if( pVInfos[i].depth == 8 )
+ {
+ nTrueColor = -1; // strongly discourage 8 bit true color
+ bUsable = sal_True;
+ }
+#endif
+#ifdef sal_TrueCOLOR15
+ else if( pVInfos[i].depth == 15 )
+ bUsable = sal_True;
+#endif
+#ifdef sal_TrueCOLOR16
+ else if( pVInfos[i].depth == 16 )
+ bUsable = sal_True;
+#endif
+#ifdef sal_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 = sal_True;
+ }
+#endif
+ }
+ else if( pVInfos[i].c_class == PseudoColor )
+ {
+ if( pVInfos[i].depth <= 8 )
+ bUsable = sal_True;
+#ifdef PSEUDOCOLOR12
+ else if( pVInfos[i].depth == 12 )
+ bUsable = sal_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;
+
+ int result;
+
+ GetSalData()->m_pInstance->GetYieldMutex()->acquire();
+ result = pDisplay->IsEvent();
+ GetSalData()->m_pInstance->GetYieldMutex()->release();
+ return result;
+}
+static int DisplayQueue( int
+#ifdef DBG_UTIL
+fd
+#endif
+, SalX11Display *pDisplay )
+{
+ DBG_ASSERT( ConnectionNumber( pDisplay->GetDisplay() ) == fd,
+ "wrong fd in DisplayHasEvent" );
+ int result;
+
+ GetSalData()->m_pInstance->GetYieldMutex()->acquire();
+ result = XEventsQueued( pDisplay->GetDisplay(),
+ QueuedAfterReading );
+ GetSalData()->m_pInstance->GetYieldMutex()->release();
+
+ return result;
+}
+static int DisplayYield( int
+#ifdef DBG_UTIL
+fd
+#endif
+, SalX11Display *pDisplay )
+{
+ DBG_ASSERT( ConnectionNumber( pDisplay->GetDisplay() ) == fd,
+ "wrong fd in DisplayHasEvent" );
+
+ GetSalData()->m_pInstance->GetYieldMutex()->acquire();
+ pDisplay->Yield();
+ GetSalData()->m_pInstance->GetYieldMutex()->release();
+ return sal_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
+ );
+
+ rtl::OString aExec(rtl::OUStringToOString(SessionManagerClient::getExecName(), osl_getThreadTextEncoding()));
+ const char* argv[2];
+ argv[0] = "/bin/sh";
+ argv[1] = aExec.getStr();
+ 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 );
+ // PowerPC Solaris 2.5 (XSun 3500) Bug: GXor = GXnop
+ 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,
+ reinterpret_cast<const char*>(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_ = sal_False; /* dont care, initialize later by
+ calling SalDisplay::IsLocal() */
+ mbLocalIsValid = sal_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 || \
+ defined NETBSD || defined OPENBSD || defined DRAGONFLY
+ 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 || defined NETBSD || defined OPENBSD || \
+ defined DRAGONFLY
+ // 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
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+namespace {
+
+bool InitXkb(Display* dpy)
+{
+ int nOpcode, nEvent, nError;
+ int nXkbMajor = XkbMajorVersion;
+ int nXkbMinor = XkbMinorVersion;
+
+ if (!XkbLibraryVersion(&nXkbMajor, &nXkbMinor))
+ return false;
+
+ return XkbQueryExtension(
+ dpy, &nOpcode, &nEvent, &nError, &nXkbMajor, &nXkbMinor);
+}
+
+unsigned int GetKeySymMask(Display* dpy, KeySym nKeySym)
+{
+ int nMask = 0;
+ XModifierKeymap* pXmkMap = XGetModifierMapping(dpy);
+ KeyCode nKeyCode = XKeysymToKeycode(dpy, nKeySym);
+ if (nKeyCode == NoSymbol)
+ return 0;
+
+ for (int i = 0; i < 8; ++i)
+ {
+ KeyCode nThisKeyCode = pXmkMap->modifiermap[pXmkMap->max_keypermod*i];
+ if (nThisKeyCode == nKeyCode)
+ nMask = 1 << i;
+ }
+ XFreeModifiermap(pXmkMap);
+ return nMask;
+}
+
+}
+
+void SalDisplay::SimulateKeyPress( sal_uInt16 nKeyCode )
+{
+ if (nKeyCode == KEY_CAPSLOCK)
+ {
+ Display* dpy = GetDisplay();
+ if (!InitXkb(dpy))
+ return;
+
+ unsigned int nMask = GetKeySymMask(dpy, XK_Caps_Lock);
+ XkbStateRec xkbState;
+ XkbGetState(dpy, XkbUseCoreKbd, &xkbState);
+ unsigned int nCapsLockState = xkbState.locked_mods & nMask;
+ if (nCapsLockState)
+ XkbLockModifiers (dpy, XkbUseCoreKbd, nMask, 0);
+ else
+ XkbLockModifiers (dpy, XkbUseCoreKbd, nMask, nMask);
+ }
+}
+
+sal_uInt16 SalDisplay::GetIndicatorState() const
+{
+ unsigned int _state = 0;
+ sal_uInt16 nState = 0;
+ XkbGetIndicatorState(pDisp_, XkbUseCoreKbd, &_state);
+
+ if ((_state & 0x00000001))
+ nState |= INDICATOR_CAPSLOCK;
+ if ((_state & 0x00000002))
+ nState |= INDICATOR_NUMLOCK;
+ if ((_state & 0x00000004))
+ nState |= INDICATOR_SCROLLLOCK;
+
+ return nState;
+}
+
+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( sal_uInt16 nKeyCode ) const
+{
+ String aStrMap;
+ String aCustomKeyName;
+
+ 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;
+ case KEY_BRACKETLEFT:
+ aCustomKeyName = '[';
+ break;
+ case KEY_BRACKETRIGHT:
+ aCustomKeyName = ']';
+ break;
+ case KEY_SEMICOLON:
+ aCustomKeyName = ';';
+ break;
+
+ default:
+ nKeySym = 0;
+ break;
+ }
+
+ if( nKeySym )
+ {
+ String aKeyName = GetKeyNameFromKeySym( nKeySym );
+ if( aKeyName.Len() )
+ {
+ if( aStrMap.Len() )
+ aStrMap += '+';
+ aStrMap += aKeyName;
+ }
+ else
+ aStrMap.Erase();
+ }
+ else if (aCustomKeyName.Len())
+ {
+ // For semicolumn, bracket left and bracket right, it's better to use
+ // their keys than their names. (fdo#32891)
+ if (aStrMap.Len())
+ aStrMap += '+';
+ aStrMap += aCustomKeyName;
+ }
+ else
+ aStrMap.Erase();
+
+ return aStrMap;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#ifndef IsISOKey
+#define IsISOKey( n ) (0x0000FE00==((n)&0xFFFFFF00))
+#endif
+
+sal_uInt16 SalDisplay::GetKeyCode( KeySym keysym, char*pcPrintable ) const
+{
+ sal_uInt16 nKey = 0;
+
+ if( XK_a <= keysym && XK_z >= keysym )
+ nKey = (sal_uInt16)(KEY_A + (keysym - XK_a));
+ else if( XK_A <= keysym && XK_Z >= keysym )
+ nKey = (sal_uInt16)(KEY_A + (keysym - XK_A));
+ else if( XK_0 <= keysym && XK_9 >= keysym )
+ nKey = (sal_uInt16)(KEY_0 + (keysym - XK_0));
+ else if( IsModifierKey( keysym ) )
+ ;
+ else if( IsKeypadKey( keysym ) )
+ {
+ if( (keysym >= XK_KP_0) && (keysym <= XK_KP_9) )
+ {
+ nKey = (sal_uInt16)(KEY_0 + (keysym - XK_KP_0));
+ *pcPrintable = '0' + nKey - KEY_0;
+ }
+ else if( IsPFKey( keysym ) )
+ nKey = (sal_uInt16)(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 = (sal_uInt16)(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 = (sal_uInt16)(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;
+ }
+ }
+ 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_bracketleft:
+ nKey = KEY_BRACKETLEFT;
+ *pcPrintable = '[';
+ break;
+ case XK_bracketright:
+ nKey = KEY_BRACKETRIGHT;
+ *pcPrintable = ']';
+ break;
+ case XK_semicolon:
+ nKey = KEY_SEMICOLON;
+ *pcPrintable = ';';
+ 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:
+ /* 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_ ), \
+ reinterpret_cast<const char*>(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;
+
+ // #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;
+
+ // #i20119# Paintbrush tool
+ case POINTER_PAINTBRUSH :
+ MAKE_CURSOR( paintbrush_ );
+ break;
+
+ default:
+ OSL_FAIL("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 )
+{
+ static const char* pEnv = getenv( "SAL_NO_MOUSEGRABS" );
+
+ if( !pCapture )
+ {
+ m_pCapture = NULL;
+ if( !pEnv || !*pEnv )
+ XUngrabPointer( GetDisplay(), CurrentTime );
+ XFlush( GetDisplay() );
+ return 0;
+ }
+
+ m_pCapture = NULL;
+
+ // FIXME: get rid of X11SalFrame
+ const SystemEnvData* pEnvData = pCapture->GetSystemData();
+ if( !pEnv || !*pEnv )
+ {
+ 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, sal_uInt16 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, sal_uInt16 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" );
+ }
+}
+
+sal_Bool SalX11Display::IsEvent()
+{
+ sal_Bool bRet = sal_False;
+
+ if( osl_acquireMutex( hEventGuard_ ) )
+ {
+ if( m_aUserEvents.begin() != m_aUserEvents.end() )
+ bRet = sal_True;
+ osl_releaseMutex( hEventGuard_ );
+ }
+
+ if( bRet || XEventsQueued( pDisp_, QueuedAlready ) )
+ return sal_True;
+
+ XFlush( pDisp_ );
+ return sal_False;
+}
+
+bool SalDisplay::DispatchInternalEvent()
+{
+ SalFrame* pFrame = NULL;
+ void* pData = NULL;
+ sal_uInt16 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() ==
+ osl::Thread::getCurrentIdentifier(),
+ "will crash soon since solar mutex not locked in SalDisplay::Yield" );
+
+ XNextEvent( pDisp_, &aEvent );
+
+ Dispatch( &aEvent );
+
+#ifdef DBG_UTIL
+ if( pXLib_->HasXErrorOccurred() )
+ {
+ XFlush( pDisp_ );
+ PrintEvent( "SalDisplay::Yield (WasXError)", &aEvent );
+ }
+#endif
+ pXLib_->ResetXErrorOccurred();
+}
+
+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()) );
+}
+
+void SalDisplay::addXineramaScreenUnique( int i, 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_aXineramaScreenIndexMap[i] = n;
+ m_aXineramaScreens[n].SetSize( Size( i_nWidth, i_nHeight ) );
+ }
+ return;
+ }
+ }
+ m_aXineramaScreenIndexMap[i] = m_aXineramaScreens.size();
+ m_aXineramaScreens.push_back( Rectangle( Point( i_nX, i_nY ), Size( i_nWidth, i_nHeight ) ) );
+}
+
+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>();
+ m_aXineramaScreenIndexMap = std::vector<int>(nFramebuffers);
+ for( int i = 0; i < nFramebuffers; i++ )
+ addXineramaScreenUnique( i, 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>();
+ m_aXineramaScreenIndexMap = std::vector<int>(nFramebuffers);
+ for( int i = 0; i < nFramebuffers; i++ )
+ {
+ addXineramaScreenUnique( i, 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 {
+ OSL_FAIL( "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_ = otherSalRGB;
+ else if( blue_mask == 0xFF00 )
+ if( green_mask == 0xFF )
+ eRGBMode_ = RBG;
+ else
+ eRGBMode_ = otherSalRGB;
+ else
+ eRGBMode_ = otherSalRGB;
+ else if( green_mask == 0xFF0000 )
+ if( red_mask == 0xFF00 )
+ if( blue_mask == 0xFF )
+ eRGBMode_ = GRB;
+ else
+ eRGBMode_ = otherSalRGB;
+ else if( blue_mask == 0xFF00 )
+ if( red_mask == 0xFF )
+ eRGBMode_ = GBR;
+ else
+ eRGBMode_ = otherSalRGB;
+ else
+ eRGBMode_ = otherSalRGB;
+ else if( blue_mask == 0xFF0000 )
+ if( red_mask == 0xFF00 )
+ if( green_mask == 0xFF )
+ eRGBMode_ = BRG;
+ else
+ eRGBMode_ = otherSalRGB;
+ else if( green_mask == 0xFF00 )
+ if( red_mask == 0xFF )
+ eRGBMode_ = BGR;
+ else
+ eRGBMode_ = otherSalRGB;
+ else
+ eRGBMode_ = otherSalRGB;
+ else
+ eRGBMode_ = otherSalRGB;
+ else
+ eRGBMode_ = otherSalRGB;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+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
+
+sal_Bool SalVisual::Convert( int &n0, int &n1, int &n2, int &n3 )
+{
+ int n;
+
+ switch( GetMode() )
+ {
+ case otherSalRGB:
+ return sal_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 sal_True;
+}
+
+sal_Bool SalVisual::Convert( int &n0, int &n1, int &n2 )
+{
+ int n;
+
+ switch( GetMode() )
+ {
+ case otherSalRGB:
+ return sal_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 sal_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( otherSalRGB != 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( otherSalRGB != 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, 0xFF );
+ GetXPixels( aColor, 0x00, 0xFF, 0x00 );
+ GetXPixels( aColor, 0x00, 0xFF, 0xFF );
+
+ // standard colors: 7 * 2 = 14
+ 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 ); // Blue 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( sal_uInt16 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 sal_uInt16 sal_Lookup( const std::vector<SalColor>& rPalette,
+ int r, int g, int b,
+ Pixel nUsed )
+{
+ sal_uInt16 nPixel = 0;
+ int nBest = ColorDiff( rPalette[0], r, g, b );
+
+ for( sal_uInt16 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<sal_uInt16>(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 sal_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 );
+}
+
+sal_Bool SalColormap::GetXPixels( XColor &rColor,
+ int r,
+ int g,
+ int b ) const
+{
+ if( !GetXPixel( rColor, r, g, b ) )
+ return sal_False;
+ if( rColor.pixel & 1 )
+ return sal_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
+ sal_uInt16 r = SALCOLOR_RED ( nSalColor );
+ sal_uInt16 g = SALCOLOR_GREEN( nSalColor );
+ sal_uInt16 b = SALCOLOR_BLUE ( nSalColor );
+ return m_aLookupTable[ (((r+8)/17) << 8)
+ + (((g+8)/17) << 4)
+ + ((b+8)/17) ];
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/salinst.cxx b/vcl/unx/generic/app/salinst.cxx
new file mode 100644
index 000000000000..7233225f4d9b
--- /dev/null
+++ b/vcl/unx/generic/app/salinst.cxx
@@ -0,0 +1,455 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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"
+#include <sal/macros.h>
+
+// -------------------------------------------------------------------------
+//
+// SalYieldMutex
+//
+// -------------------------------------------------------------------------
+
+SalYieldMutex::SalYieldMutex()
+{
+ mnCount = 0;
+ mnThreadId = 0;
+ ::tools::SolarMutex::SetSolarMutex( this );
+}
+
+void SalYieldMutex::acquire()
+{
+ SolarMutexObject::acquire();
+ mnThreadId = osl::Thread::getCurrentIdentifier();
+ mnCount++;
+}
+
+void SalYieldMutex::release()
+{
+ if ( mnThreadId == osl::Thread::getCurrentIdentifier() )
+ {
+ if ( mnCount == 1 )
+ mnThreadId = 0;
+ mnCount--;
+ }
+ SolarMutexObject::release();
+}
+
+sal_Bool SalYieldMutex::tryToAcquire()
+{
+ if ( SolarMutexObject::tryToAcquire() )
+ {
+ mnThreadId = osl::Thread::getCurrentIdentifier();
+ mnCount++;
+ return True;
+ }
+ else
+ return False;
+}
+
+//----------------------------------------------------------------------------
+
+// -=-= SalInstance =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// plugin factory function
+extern "C"
+{
+ VCLPLUG_GEN_PUBLIC 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
+{
+ sal_uInt16 nType;
+ sal_Bool bRet;
+};
+
+extern "C" {
+Bool ImplPredicateEvent( Display *, XEvent *pEvent, char *pData )
+{
+ PredicateReturn *pPre = (PredicateReturn *)pData;
+
+ if ( pPre->bRet )
+ return False;
+
+ sal_uInt16 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 = sal_True;
+
+ return False;
+}
+}
+
+bool X11SalInstance::AnyInput(sal_uInt16 nType)
+{
+ X11SalData *pSalData = GetX11SalData();
+ Display *pDisplay = pSalData->GetDisplay()->GetDisplay();
+ sal_Bool bRet = sal_False;
+
+ if( (nType & INPUT_TIMER) &&
+ pSalData->GetDisplay()->GetXLib()->CheckTimeout( false ) )
+ {
+ bRet = sal_True;
+ }
+ else if (XPending(pDisplay) )
+ {
+ PredicateReturn aInput;
+ XEvent aEvent;
+
+ aInput.bRet = sal_False;
+ aInput.nType = nType;
+
+ XCheckIfEvent(pDisplay, &aEvent, ImplPredicateEvent,
+ (char *)&aInput );
+
+ bRet = aInput.bRet;
+ }
+ return bRet;
+}
+
+osl::SolarMutex* X11SalInstance::GetYieldMutex()
+{
+ return mpSalYieldMutex;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong X11SalInstance::ReleaseYieldMutex()
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ if ( pYieldMutex->GetThreadId() ==
+ osl::Thread::getCurrentIdentifier() )
+ {
+ sal_uLong nCount = pYieldMutex->GetAcquireCount();
+ sal_uLong n = nCount;
+ while ( n )
+ {
+ pYieldMutex->release();
+ n--;
+ }
+
+ return nCount;
+ }
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::AcquireYieldMutex( sal_uLong nCount )
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ while ( nCount )
+ {
+ pYieldMutex->acquire();
+ nCount--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool X11SalInstance::CheckYieldMutex()
+{
+ bool bRet = true;
+
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ if ( pYieldMutex->GetThreadId() != osl::Thread::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, sal_uLong nSalFrameStyle )
+{
+ SalFrame *pFrame = new X11SalFrame( pParent, nSalFrameStyle );
+
+ return pFrame;
+}
+
+SalFrame* X11SalInstance::CreateChildFrame( SystemParentData* pParentData, sal_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 < SAL_N_ELEMENTS(pCommands); 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);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/salsys.cxx b/vcl/unx/generic/app/salsys.cxx
new file mode 100644
index 000000000000..c5f7174e3d4c
--- /dev/null
+++ b/vcl/unx/generic/app/salsys.cxx
@@ -0,0 +1,229 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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();
+
+ sal_uInt16 nButton = 0;
+ for( std::list< String >::const_iterator it = rButtons.begin(); it != rButtons.end(); ++it )
+ {
+ aWarn.AddButton( *it, nButton+1, nButton == (sal_uInt16)nDefButton ? BUTTONDIALOG_DEFBUTTON : 0 );
+ nButton++;
+ }
+ aWarn.SetFocusButton( (sal_uInt16)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;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/saltimer.cxx b/vcl/unx/generic/app/saltimer.cxx
new file mode 100644
index 000000000000..98d6ccde5943
--- /dev/null
+++ b/vcl/unx/generic/app/saltimer.cxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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( sal_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( sal_uLong nMS )
+{
+ GetX11SalData()->GetLib()->StartTimer( nMS );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/sm.cxx b/vcl/unx/generic/app/sm.cxx
new file mode 100644
index 000000000000..ac2682df4510
--- /dev/null
+++ b/vcl/unx/generic/app/sm.cxx
@@ -0,0 +1,806 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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();
+ SessionManagerClient::open();
+ 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 sal_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;
+sal_Bool ICEConnectionObserver::bIsWatching = sal_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 )
+ {
+ rtl::OString aExec(rtl::OUStringToOString(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.getLength()+1;
+ pSmProps[ 0 ].vals->value = strdup( aExec.getStr() );
+
+ 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.getLength()+1;
+ pSmProps[ 1 ].vals->value = strdup( aExec.getStr() );
+
+ 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.getLength()+1;
+ pSmProps[ 2 ].vals[0].value = strdup( aExec.getStr() );
+ 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;
+ }
+ sal_uIntPtr nStateVal = shutdown ? 0xffffffff : 0x0;
+ Application::PostUserEvent( STATIC_LINK( (void*)nStateVal, 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();
+ }
+}
+
+
+rtl::OUString SessionManagerClient::getExecName()
+{
+ rtl::OUString aExec, aSysExec;
+ osl_getExecutableFile( &aExec.pData );
+ osl_getSystemPathFromFileURL( aExec.pData, &aSysExec.pData );
+
+ int nPos = aSysExec.indexOf( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".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 = sal_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 = sal_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
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/soicon.cxx b/vcl/unx/generic/app/soicon.cxx
new file mode 100644
index 000000000000..1557b064977e
--- /dev/null
+++ b/vcl/unx/generic/app/soicon.cxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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>
+
+
+sal_Bool SelectAppIconPixmap( SalDisplay *pDisplay, int nScreen,sal_uInt16 nIcon, sal_uInt16 iconSize,
+ Pixmap& icon_pixmap, Pixmap& icon_mask)
+{
+ if( ! ImplGetResMgr() )
+ return sal_False;
+
+ sal_uInt16 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 sal_False;
+
+ BitmapEx aIcon( ResId(nIconSizeOffset + nIcon, *ImplGetResMgr()));
+ if( sal_True == aIcon.IsEmpty() )
+ return sal_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 sal_True;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/app/wmadaptor.cxx b/vcl/unx/generic/app/wmadaptor.cxx
new file mode 100644
index 000000000000..ad9b5ee22d6c
--- /dev/null
+++ b/vcl/unx/generic/app/wmadaptor.cxx
@@ -0,0 +1,2551 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <sal/macros.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,
+ SAL_N_ELEMENTS( aProtocolTab ),
+ 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()->HasXErrorOccurred()
+ )
+ {
+ 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,
+ SAL_N_ELEMENTS( aProtocolTab ),
+ 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()->HasXErrorOccurred()
+ )
+ {
+ 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 < SAL_N_ELEMENTS( aAtomTab ); 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(RTL_CONSTASCII_USTRINGPARAM("_"));
+ 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 );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/desktopdetect/desktopdetector.cxx b/vcl/unx/generic/desktopdetect/desktopdetector.cxx
new file mode 100644
index 000000000000..568507822c1e
--- /dev/null
+++ b/vcl/unx/generic/desktopdetect/desktopdetector.cxx
@@ -0,0 +1,356 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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/svunx.h>
+#include <tools/prex.h>
+#include <X11/Xatom.h>
+#include <tools/postx.h>
+
+#include "rtl/ustrbuf.hxx"
+#include "osl/module.h"
+#include "osl/process.h"
+#include "osl/thread.h"
+
+#include "vclpluginapi.h"
+
+#include <unistd.h>
+#include <string.h>
+
+using ::rtl::OUString;
+using ::rtl::OString;
+enum {
+ DESKTOP_NONE = 0,
+ DESKTOP_UNKNOWN,
+ DESKTOP_GNOME,
+ DESKTOP_KDE,
+ DESKTOP_KDE4,
+ DESKTOP_CDE
+};
+
+static const char * desktop_strings[] = { "none", "unknown", "GNOME", "KDE", "KDE4", "CDE" };
+
+static bool is_gnome_desktop( Display* pDisplay )
+{
+ bool ret = false;
+
+ // warning: these checks are coincidental, GNOME does not
+ // explicitly advertise itself
+
+ if ( NULL != getenv( "GNOME_DESKTOP_SESSION_ID" ) )
+ ret = true;
+
+ if( ! ret )
+ {
+ Atom nAtom1 = XInternAtom( pDisplay, "GNOME_SM_PROXY", True );
+ Atom nAtom2 = XInternAtom( pDisplay, "NAUTILUS_DESKTOP_WINDOW_ID", True );
+ if( nAtom1 || nAtom2 )
+ {
+ int nProperties = 0;
+ Atom* pProperties = XListProperties( pDisplay, DefaultRootWindow( pDisplay ), &nProperties );
+ if( pProperties && nProperties )
+ {
+ for( int i = 0; i < nProperties; i++ )
+ if( pProperties[ i ] == nAtom1 ||
+ pProperties[ i ] == nAtom2 )
+ {
+ ret = true;
+ }
+ XFree( pProperties );
+ }
+ }
+ }
+
+ if( ! ret )
+ {
+ Atom nUTFAtom = XInternAtom( pDisplay, "UTF8_STRING", True );
+ Atom nNetWMNameAtom = XInternAtom( pDisplay, "_NET_WM_NAME", True );
+ if( nUTFAtom && nNetWMNameAtom )
+ {
+ // another, more expensive check: search for a gnome-panel
+ XLIB_Window aRoot, aParent, *pChildren = NULL;
+ unsigned int nChildren = 0;
+ XQueryTree( pDisplay, DefaultRootWindow( pDisplay ),
+ &aRoot, &aParent, &pChildren, &nChildren );
+ if( pChildren && nChildren )
+ {
+ for( unsigned int i = 0; i < nChildren && ! ret; i++ )
+ {
+ Atom nType = None;
+ int nFormat = 0;
+ unsigned long nItems = 0, nBytes = 0;
+ unsigned char* pProp = NULL;
+ XGetWindowProperty( pDisplay,
+ pChildren[i],
+ nNetWMNameAtom,
+ 0, 8,
+ False,
+ nUTFAtom,
+ &nType,
+ &nFormat,
+ &nItems,
+ &nBytes,
+ &pProp );
+ if( pProp && nType == nUTFAtom )
+ {
+ OString aWMName( (sal_Char*)pProp );
+ if( aWMName.equalsIgnoreAsciiCase( "gnome-panel" ) )
+ ret = true;
+ }
+ if( pProp )
+ XFree( pProp );
+ }
+ XFree( pChildren );
+ }
+ }
+ }
+
+ return ret;
+}
+
+static bool bWasXError = false;
+
+static inline bool WasXError()
+{
+ bool bRet = bWasXError;
+ bWasXError = false;
+ return bRet;
+}
+
+extern "C"
+{
+ static int autodect_error_handler( Display*, XErrorEvent* )
+ {
+ bWasXError = true;
+ return 0;
+ }
+
+ typedef int(* XErrorHandler)(Display*,XErrorEvent*);
+}
+
+static int KDEVersion( Display* pDisplay )
+{
+ int nRet = 0;
+
+ Atom nFullSession = XInternAtom( pDisplay, "KDE_FULL_SESSION", True );
+ Atom nKDEVersion = XInternAtom( pDisplay, "KDE_SESSION_VERSION", True );
+
+ if( nFullSession )
+ {
+ if( !nKDEVersion )
+ return 3;
+
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+ XGetWindowProperty( pDisplay,
+ DefaultRootWindow( pDisplay ),
+ nKDEVersion,
+ 0, 1,
+ False,
+ AnyPropertyType,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty );
+ if( !WasXError() && nItems != 0 && pProperty )
+ {
+ nRet = *reinterpret_cast< sal_Int32* >( pProperty );
+ }
+ if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ return nRet;
+}
+
+static bool is_kde_desktop( Display* pDisplay )
+{
+ if ( NULL != getenv( "KDE_FULL_SESSION" ) )
+ {
+ const char *pVer = getenv( "KDE_SESSION_VERSION" );
+ if ( !pVer || pVer[0] == '0' )
+ {
+ return true; // does not exist => KDE3
+ }
+
+ rtl::OUString aVer( RTL_CONSTASCII_USTRINGPARAM( "3" ) );
+ if ( aVer.equalsIgnoreAsciiCaseAscii( pVer ) )
+ {
+ return true;
+ }
+ }
+
+ if ( KDEVersion( pDisplay ) == 3 )
+ return true;
+
+ return false;
+}
+
+static bool is_kde4_desktop( Display* pDisplay )
+{
+ if ( NULL != getenv( "KDE_FULL_SESSION" ) )
+ {
+ rtl::OUString aVer( RTL_CONSTASCII_USTRINGPARAM( "4" ) );
+
+ const char *pVer = getenv( "KDE_SESSION_VERSION" );
+ if ( pVer && aVer.equalsIgnoreAsciiCaseAscii( pVer ) )
+ return true;
+ }
+
+ if ( KDEVersion( pDisplay ) == 4 )
+ return true;
+
+ return false;
+}
+
+static bool is_cde_desktop( Display* pDisplay )
+{
+ void* pLibrary = NULL;
+
+ Atom nDtAtom = XInternAtom( pDisplay, "_DT_WM_READY", True );
+ OUString aPathName( RTL_CONSTASCII_USTRINGPARAM( "file:///usr/dt/lib/libDtSvc.so" ) );
+ if( nDtAtom && ( pLibrary = osl_loadModule( aPathName.pData, SAL_LOADMODULE_DEFAULT ) ) )
+ {
+ osl_unloadModule( (oslModule)pLibrary );
+ return true;
+ }
+
+ return false;
+}
+
+
+extern "C"
+{
+
+DESKTOP_DETECTOR_PUBLIC rtl::OUString get_desktop_environment()
+{
+ rtl::OUStringBuffer aRet( 8 );
+ static const char *pOverride = getenv( "OOO_FORCE_DESKTOP" );
+
+ if ( pOverride && *pOverride )
+ {
+ OString aOver( pOverride );
+
+ if ( aOver.equalsIgnoreAsciiCase( "cde" ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_CDE] );
+ if ( aOver.equalsIgnoreAsciiCase( "kde4" ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_KDE4] );
+ if ( aOver.equalsIgnoreAsciiCase( "gnome" ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_GNOME] );
+ if ( aOver.equalsIgnoreAsciiCase( "kde" ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_KDE] );
+ if ( aOver.equalsIgnoreAsciiCase( "none" ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_UNKNOWN] );
+ }
+
+ if( aRet.getLength() == 0 )
+ {
+ // get display to connect to
+ const char* pDisplayStr = getenv( "DISPLAY" );
+
+ const char* pUsePlugin = getenv( "SAL_USE_VCLPLUGIN" );
+
+ if (pUsePlugin && (strcmp(pUsePlugin, "svp") == 0))
+ pDisplayStr = NULL;
+ else
+ {
+ int nParams = osl_getCommandArgCount();
+ OUString aParam;
+ OString aBParm;
+ for( int i = 0; i < nParams; i++ )
+ {
+ osl_getCommandArg( i, &aParam.pData );
+ if( aParam.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "-headless" ) ) ||
+ aParam.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "--headless" ) ) )
+ {
+ pDisplayStr = NULL;
+ break;
+ }
+ if( i < nParams-1 && (aParam.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "-display" ) ) || aParam.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "--display" ) )) )
+ {
+ osl_getCommandArg( i+1, &aParam.pData );
+ aBParm = OUStringToOString( aParam, osl_getThreadTextEncoding() );
+ pDisplayStr = aBParm.getStr();
+ break;
+ }
+ }
+ }
+
+ // no server at all
+ if( ! pDisplayStr || !*pDisplayStr )
+ aRet.appendAscii( desktop_strings[DESKTOP_NONE] );
+ else
+ {
+ /* #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();
+
+ Display* pDisplay = XOpenDisplay( pDisplayStr );
+ if( pDisplay )
+ {
+ XErrorHandler pOldHdl = XSetErrorHandler( autodect_error_handler );
+
+ if ( is_kde4_desktop( pDisplay ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_KDE4] );
+ else if ( is_gnome_desktop( pDisplay ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_GNOME] );
+ else if ( is_cde_desktop( pDisplay ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_CDE] );
+ else if ( is_kde_desktop( pDisplay ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_KDE] );
+ else
+ aRet.appendAscii( desktop_strings[DESKTOP_UNKNOWN] );
+
+ // set the default handler again
+ XSetErrorHandler( pOldHdl );
+
+ XCloseDisplay( pDisplay );
+ }
+ }
+ }
+
+ return aRet.makeStringAndClear();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_clipboard.cxx b/vcl/unx/generic/dtrans/X11_clipboard.cxx
new file mode 100644
index 000000000000..4f1934397397
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_clipboard.cxx
@@ -0,0 +1,296 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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/Xatom.h>
+#include <X11_clipboard.hxx>
+#include <X11_transferable.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/datatransfer/clipboard/RenderingCapabilities.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <uno/dispatcher.h> // declaration of generic uno interface
+#include <uno/mapping.hxx> // mapping stuff
+#include <cppuhelper/factory.hxx>
+#include <rtl/tencinfo.h>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::awt;
+using namespace cppu;
+using namespace osl;
+using namespace x11;
+
+using ::rtl::OUString;
+
+X11Clipboard::X11Clipboard( SelectionManager& rManager, Atom aSelection ) :
+ ::cppu::WeakComponentImplHelper4<
+ ::com::sun::star::datatransfer::clipboard::XClipboardEx,
+ ::com::sun::star::datatransfer::clipboard::XClipboardNotifier,
+ ::com::sun::star::lang::XServiceInfo,
+ ::com::sun::star::lang::XInitialization
+ >( rManager.getMutex() ),
+
+ m_rSelectionManager( rManager ),
+ m_xSelectionManager( & rManager ),
+ m_aSelection( aSelection )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "creating instance of X11Clipboard (this=%p)\n", this );
+#endif
+
+ if( m_aSelection != None )
+ {
+ m_rSelectionManager.registerHandler( m_aSelection, *this );
+ }
+ else
+ {
+ m_rSelectionManager.registerHandler( XA_PRIMARY, *this );
+ m_rSelectionManager.registerHandler( m_rSelectionManager.getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) ), *this );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+X11Clipboard::~X11Clipboard()
+{
+ MutexGuard aGuard( *Mutex::getGlobalMutex() );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "shutting down instance of X11Clipboard (this=%p, Selecttion=\"%s\")\n", this, OUStringToOString( m_rSelectionManager.getString( m_aSelection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ if( m_aSelection != None )
+ m_rSelectionManager.deregisterHandler( m_aSelection );
+ else
+ {
+ m_rSelectionManager.deregisterHandler( XA_PRIMARY );
+ m_rSelectionManager.deregisterHandler( m_rSelectionManager.getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) ) );
+ }
+}
+
+
+// ------------------------------------------------------------------------
+
+void X11Clipboard::fireChangedContentsEvent()
+{
+ ClearableMutexGuard aGuard( m_rSelectionManager.getMutex() );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "X11Clipboard::fireChangedContentsEvent for %s (%" SAL_PRI_SIZET "u listeners)\n",
+ OUStringToOString( m_rSelectionManager.getString( m_aSelection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(), m_aListeners.size() );
+#endif
+ ::std::list< Reference< XClipboardListener > > listeners( m_aListeners );
+ aGuard.clear();
+
+ ClipboardEvent aEvent( static_cast<OWeakObject*>(this), m_aContents);
+ while( listeners.begin() != listeners.end() )
+ {
+ if( listeners.front().is() )
+ listeners.front()->changedContents(aEvent);
+ listeners.pop_front();
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void X11Clipboard::clearContents()
+{
+ ClearableMutexGuard aGuard(m_rSelectionManager.getMutex());
+ // protect against deletion during outside call
+ Reference< XClipboard > xThis( static_cast<XClipboard*>(this));
+ // copy member references on stack so they can be called
+ // without having the mutex
+ Reference< XClipboardOwner > xOwner( m_aOwner );
+ Reference< XTransferable > xTrans( m_aContents );
+ // clear members
+ m_aOwner.clear();
+ m_aContents.clear();
+
+ // release the mutex
+ aGuard.clear();
+
+ // inform previous owner of lost ownership
+ if ( xOwner.is() )
+ xOwner->lostOwnership(xThis, m_aContents);
+}
+
+// ------------------------------------------------------------------------
+
+Reference< XTransferable > SAL_CALL X11Clipboard::getContents()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard(m_rSelectionManager.getMutex());
+
+ if( ! m_aContents.is() )
+ m_aContents = new X11Transferable( SelectionManager::get(), static_cast< OWeakObject* >(this), m_aSelection );
+ return m_aContents;
+}
+
+// ------------------------------------------------------------------------
+
+void SAL_CALL X11Clipboard::setContents(
+ const Reference< XTransferable >& xTrans,
+ const Reference< XClipboardOwner >& xClipboardOwner )
+ throw(RuntimeException)
+{
+ // remember old values for callbacks before setting the new ones.
+ ClearableMutexGuard aGuard(m_rSelectionManager.getMutex());
+
+ Reference< XClipboardOwner > oldOwner( m_aOwner );
+ m_aOwner = xClipboardOwner;
+
+ Reference< XTransferable > oldContents( m_aContents );
+ m_aContents = xTrans;
+
+ aGuard.clear();
+
+ // for now request ownership for both selections
+ if( m_aSelection != None )
+ m_rSelectionManager.requestOwnership( m_aSelection );
+ else
+ {
+ m_rSelectionManager.requestOwnership( XA_PRIMARY );
+ m_rSelectionManager.requestOwnership( m_rSelectionManager.getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) ) );
+ }
+
+ // notify old owner on loss of ownership
+ if( oldOwner.is() )
+ oldOwner->lostOwnership(static_cast < XClipboard * > (this), oldContents);
+
+ // notify all listeners on content changes
+ fireChangedContentsEvent();
+}
+
+// ------------------------------------------------------------------------
+
+OUString SAL_CALL X11Clipboard::getName()
+ throw(RuntimeException)
+{
+ return m_rSelectionManager.getString( m_aSelection );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Int8 SAL_CALL X11Clipboard::getRenderingCapabilities()
+ throw(RuntimeException)
+{
+ return RenderingCapabilities::Delayed;
+}
+
+
+// ------------------------------------------------------------------------
+void SAL_CALL X11Clipboard::addClipboardListener( const Reference< XClipboardListener >& listener )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( m_rSelectionManager.getMutex() );
+ m_aListeners.push_back( listener );
+}
+
+// ------------------------------------------------------------------------
+
+void SAL_CALL X11Clipboard::removeClipboardListener( const Reference< XClipboardListener >& listener )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( m_rSelectionManager.getMutex() );
+ m_aListeners.remove( listener );
+}
+
+
+// ------------------------------------------------------------------------
+
+Reference< XTransferable > X11Clipboard::getTransferable()
+{
+ return getContents();
+}
+
+// ------------------------------------------------------------------------
+
+void X11Clipboard::clearTransferable()
+{
+ clearContents();
+}
+
+// ------------------------------------------------------------------------
+
+void X11Clipboard::fireContentsChanged()
+{
+ fireChangedContentsEvent();
+}
+
+// ------------------------------------------------------------------------
+
+Reference< XInterface > X11Clipboard::getReference() throw()
+{
+ return Reference< XInterface >( static_cast< OWeakObject* >(this) );
+}
+
+// ------------------------------------------------------------------------
+
+OUString SAL_CALL X11Clipboard::getImplementationName( )
+ throw(RuntimeException)
+{
+ return OUString(RTL_CONSTASCII_USTRINGPARAM(X11_CLIPBOARD_IMPLEMENTATION_NAME));
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool SAL_CALL X11Clipboard::supportsService( const OUString& ServiceName )
+ throw(RuntimeException)
+{
+ Sequence < OUString > SupportedServicesNames = X11Clipboard_getSupportedServiceNames();
+
+ for ( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
+ if (SupportedServicesNames[n].compareTo(ServiceName) == 0)
+ return sal_True;
+
+ return sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+void SAL_CALL X11Clipboard::initialize( const Sequence< Any >& ) throw( ::com::sun::star::uno::Exception )
+{
+}
+
+// ------------------------------------------------------------------------
+
+Sequence< OUString > SAL_CALL X11Clipboard::getSupportedServiceNames( )
+ throw(RuntimeException)
+{
+ return X11Clipboard_getSupportedServiceNames();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_clipboard.hxx b/vcl/unx/generic/dtrans/X11_clipboard.hxx
new file mode 100644
index 000000000000..73240d8715e6
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_clipboard.hxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _DTRANS_X11_CLIPBOARD_HXX_
+#define _DTRANS_X11_CLIPBOARD_HXX_
+
+#include <X11_selection.hxx>
+
+#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
+
+#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
+#include <cppuhelper/compbase4.hxx>
+
+// ------------------------------------------------------------------------
+
+#define X11_CLIPBOARD_IMPLEMENTATION_NAME "com.sun.star.datatransfer.X11ClipboardSupport"
+
+namespace x11 {
+
+ class X11Clipboard :
+ public ::cppu::WeakComponentImplHelper4 <
+ ::com::sun::star::datatransfer::clipboard::XClipboardEx,
+ ::com::sun::star::datatransfer::clipboard::XClipboardNotifier,
+ ::com::sun::star::lang::XServiceInfo,
+ ::com::sun::star::lang::XInitialization
+ >,
+ public SelectionAdaptor
+ {
+ com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > m_aContents;
+ com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner > m_aOwner;
+
+ SelectionManager& m_rSelectionManager;
+ com::sun::star::uno::Reference< ::com::sun::star::lang::XInitialization > m_xSelectionManager;
+ ::std::list< com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener > > m_aListeners;
+ Atom m_aSelection;
+
+ protected:
+
+
+ friend class SelectionManager;
+ friend class X11_Transferable;
+
+ void fireChangedContentsEvent();
+ void clearContents();
+
+ public:
+
+ X11Clipboard( SelectionManager& rManager, Atom aSelection );
+ virtual ~X11Clipboard();
+
+ static X11Clipboard* get( const ::rtl::OUString& rDisplayName, Atom aSelection );
+
+ /*
+ * XInitialization
+ */
+ virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception );
+
+ /*
+ * XServiceInfo
+ */
+
+ virtual ::rtl::OUString SAL_CALL getImplementationName( )
+ throw(RuntimeException);
+
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName )
+ throw(RuntimeException);
+
+ virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( )
+ throw(RuntimeException);
+
+ /*
+ * XClipboard
+ */
+
+ virtual com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > SAL_CALL getContents()
+ throw(RuntimeException);
+
+ virtual void SAL_CALL setContents(
+ const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTrans,
+ const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner )
+ throw(RuntimeException);
+
+ virtual ::rtl::OUString SAL_CALL getName()
+ throw(RuntimeException);
+
+ /*
+ * XClipboardEx
+ */
+
+ virtual sal_Int8 SAL_CALL getRenderingCapabilities()
+ throw(RuntimeException);
+
+ /*
+ * XClipboardNotifier
+ */
+ virtual void SAL_CALL addClipboardListener(
+ const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener )
+ throw(RuntimeException);
+
+ virtual void SAL_CALL removeClipboardListener(
+ const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener )
+ throw(RuntimeException);
+
+ /*
+ * SelectionAdaptor
+ */
+ virtual com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable();
+ virtual void clearTransferable();
+ virtual void fireContentsChanged();
+ virtual com::sun::star::uno::Reference< XInterface > getReference() throw();
+ };
+
+// ------------------------------------------------------------------------
+
+ Sequence< ::rtl::OUString > SAL_CALL X11Clipboard_getSupportedServiceNames();
+ com::sun::star::uno::Reference< XInterface > SAL_CALL X11Clipboard_createInstance(
+ const com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xMultiServiceFactory);
+
+// ------------------------------------------------------------------------
+
+} // namepspace
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_dndcontext.cxx b/vcl/unx/generic/dtrans/X11_dndcontext.cxx
new file mode 100644
index 000000000000..988dce430a51
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_dndcontext.cxx
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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_dndcontext.hxx>
+#include <X11_selection.hxx>
+
+using namespace cppu;
+using namespace x11;
+
+/*
+ * DropTargetDropContext
+ */
+
+DropTargetDropContext::DropTargetDropContext(
+ XLIB_Window aDropWindow,
+ XLIB_Time aTimestamp,
+ SelectionManager& rManager ) :
+ m_aDropWindow( aDropWindow ),
+ m_nTimestamp( aTimestamp ),
+ m_rManager( rManager ),
+ m_xManagerRef( static_cast< OWeakObject* >(&rManager) )
+{
+}
+
+DropTargetDropContext::~DropTargetDropContext()
+{
+}
+
+void DropTargetDropContext::acceptDrop( sal_Int8 dragOperation ) throw()
+{
+ m_rManager.accept( dragOperation, m_aDropWindow, m_nTimestamp );
+}
+
+void DropTargetDropContext::rejectDrop() throw()
+{
+ m_rManager.reject( m_aDropWindow, m_nTimestamp );
+}
+
+void DropTargetDropContext::dropComplete( sal_Bool success ) throw()
+{
+ m_rManager.dropComplete( success, m_aDropWindow, m_nTimestamp );
+}
+
+
+/*
+ * DropTargetDragContext
+ */
+
+DropTargetDragContext::DropTargetDragContext(
+ XLIB_Window aDropWindow,
+ XLIB_Time aTimestamp,
+ SelectionManager& rManager ) :
+ m_aDropWindow( aDropWindow ),
+ m_nTimestamp( aTimestamp ),
+ m_rManager( rManager ),
+ m_xManagerRef( static_cast< OWeakObject* >(&rManager) )
+{
+}
+
+DropTargetDragContext::~DropTargetDragContext()
+{
+}
+
+void DropTargetDragContext::acceptDrag( sal_Int8 dragOperation ) throw()
+{
+ m_rManager.accept( dragOperation, m_aDropWindow, m_nTimestamp );
+}
+
+void DropTargetDragContext::rejectDrag() throw()
+{
+ m_rManager.reject( m_aDropWindow, m_nTimestamp );
+}
+
+/*
+ * DragSourceContext
+ */
+
+DragSourceContext::DragSourceContext(
+ XLIB_Window aDropWindow,
+ XLIB_Time aTimestamp,
+ SelectionManager& rManager ) :
+ m_aDropWindow( aDropWindow ),
+ m_nTimestamp( aTimestamp ),
+ m_rManager( rManager ),
+ m_xManagerRef( static_cast< OWeakObject* >(&rManager) )
+{
+}
+
+DragSourceContext::~DragSourceContext()
+{
+}
+
+sal_Int32 DragSourceContext::getCurrentCursor() throw()
+{
+ return m_rManager.getCurrentCursor();
+}
+
+void DragSourceContext::setCursor( sal_Int32 cursorId ) throw()
+{
+ m_rManager.setCursor( cursorId, m_aDropWindow, m_nTimestamp );
+}
+
+void DragSourceContext::setImage( sal_Int32 imageId ) throw()
+{
+ m_rManager.setImage( imageId, m_aDropWindow, m_nTimestamp );
+}
+
+void DragSourceContext::transferablesFlavorsChanged() throw()
+{
+ m_rManager.transferablesFlavorsChanged();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_dndcontext.hxx b/vcl/unx/generic/dtrans/X11_dndcontext.hxx
new file mode 100644
index 000000000000..bca708eb24c7
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_dndcontext.hxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _DTRANS_X11_DNDCONTEXT_HXX
+#define _DTRANS_X11_DNDCONTEXT_HXX
+
+#include <com/sun/star/datatransfer/dnd/XDragSourceContext.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDropContext.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+#include "tools/prex.h"
+#include <X11/Xlib.h>
+#include "tools/postx.h"
+
+using namespace com::sun::star::uno;
+
+namespace x11 {
+
+ class SelectionManager;
+
+ class DropTargetDropContext :
+ public ::cppu::WeakImplHelper1<
+ ::com::sun::star::datatransfer::dnd::XDropTargetDropContext
+ >
+ {
+ XLIB_Window m_aDropWindow;
+ XLIB_Time m_nTimestamp;
+ SelectionManager& m_rManager;
+ com::sun::star::uno::Reference< XInterface > m_xManagerRef;
+ public:
+ DropTargetDropContext( XLIB_Window, XLIB_Time, SelectionManager& );
+ virtual ~DropTargetDropContext();
+
+ // XDropTargetDropContext
+ virtual void SAL_CALL acceptDrop( sal_Int8 dragOperation ) throw();
+ virtual void SAL_CALL rejectDrop() throw();
+ virtual void SAL_CALL dropComplete( sal_Bool success ) throw();
+ };
+
+ class DropTargetDragContext :
+ public ::cppu::WeakImplHelper1<
+ ::com::sun::star::datatransfer::dnd::XDropTargetDragContext
+ >
+ {
+ XLIB_Window m_aDropWindow;
+ XLIB_Time m_nTimestamp;
+ SelectionManager& m_rManager;
+ com::sun::star::uno::Reference< XInterface > m_xManagerRef;
+ public:
+ DropTargetDragContext( XLIB_Window, XLIB_Time, SelectionManager& );
+ virtual ~DropTargetDragContext();
+
+ // XDropTargetDragContext
+ virtual void SAL_CALL acceptDrag( sal_Int8 dragOperation ) throw();
+ virtual void SAL_CALL rejectDrag() throw();
+ };
+
+ class DragSourceContext :
+ public ::cppu::WeakImplHelper1<
+ ::com::sun::star::datatransfer::dnd::XDragSourceContext
+ >
+ {
+ XLIB_Window m_aDropWindow;
+ XLIB_Time m_nTimestamp;
+ SelectionManager& m_rManager;
+ com::sun::star::uno::Reference< XInterface > m_xManagerRef;
+ public:
+ DragSourceContext( XLIB_Window, XLIB_Time, SelectionManager& );
+ virtual ~DragSourceContext();
+
+ // XDragSourceContext
+ virtual sal_Int32 SAL_CALL getCurrentCursor() throw();
+ virtual void SAL_CALL setCursor( sal_Int32 cursorId ) throw();
+ virtual void SAL_CALL setImage( sal_Int32 imageId ) throw();
+ virtual void SAL_CALL transferablesFlavorsChanged() throw();
+ };
+} // namespace
+
+#endif // _DTRANS_X11_DNDCONTEXT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_droptarget.cxx b/vcl/unx/generic/dtrans/X11_droptarget.cxx
new file mode 100644
index 000000000000..d72c5c4c7eeb
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_droptarget.cxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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_selection.hxx>
+
+using namespace x11;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::awt;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::dnd;
+
+using ::rtl::OUString;
+
+DropTarget::DropTarget() :
+ ::cppu::WeakComponentImplHelper3<
+ XDropTarget,
+ XInitialization,
+ XServiceInfo
+ >( m_aMutex ),
+ m_bActive( false ),
+ m_nDefaultActions( 0 ),
+ m_aTargetWindow( None ),
+ m_pSelectionManager( NULL )
+{
+}
+
+DropTarget::~DropTarget()
+{
+ if( m_pSelectionManager )
+ m_pSelectionManager->deregisterDropTarget( m_aTargetWindow );
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception )
+{
+ if( arguments.getLength() > 1 )
+ {
+ OUString aDisplayName;
+ Reference< XDisplayConnection > xConn;
+ arguments.getConstArray()[0] >>= xConn;
+ if( xConn.is() )
+ {
+ Any aIdentifier;
+ aIdentifier >>= aDisplayName;
+ }
+
+ m_pSelectionManager = &SelectionManager::get( aDisplayName );
+ m_xSelectionManager = static_cast< XDragSource* >(m_pSelectionManager);
+ m_pSelectionManager->initialize( arguments );
+
+ if( m_pSelectionManager->getDisplay() ) // #136582# sanity check
+ {
+ sal_Size aWindow = None;
+ arguments.getConstArray()[1] >>= aWindow;
+ m_pSelectionManager->registerDropTarget( aWindow, this );
+ m_aTargetWindow = aWindow;
+ m_bActive = true;
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::addDropTargetListener( const Reference< XDropTargetListener >& xListener ) throw()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
+
+ m_aListeners.push_back( xListener );
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::removeDropTargetListener( const Reference< XDropTargetListener >& xListener ) throw()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
+
+ m_aListeners.remove( xListener );
+}
+
+// --------------------------------------------------------------------------
+
+sal_Bool DropTarget::isActive() throw()
+{
+ return m_bActive;
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::setActive( sal_Bool active ) throw()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
+
+ m_bActive = active;
+}
+
+// --------------------------------------------------------------------------
+
+sal_Int8 DropTarget::getDefaultActions() throw()
+{
+ return m_nDefaultActions;
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::setDefaultActions( sal_Int8 actions ) throw()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
+
+ m_nDefaultActions = actions;
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::drop( const DropTargetDropEvent& dtde ) throw()
+{
+ osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
+ std::list< Reference< XDropTargetListener > > aListeners( m_aListeners );
+ aGuard.clear();
+
+ for( std::list< Reference< XDropTargetListener > >::iterator it = aListeners.begin(); it!= aListeners.end(); ++it )
+ {
+ (*it)->drop( dtde );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::dragEnter( const DropTargetDragEnterEvent& dtde ) throw()
+{
+ osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
+ std::list< Reference< XDropTargetListener > > aListeners( m_aListeners );
+ aGuard.clear();
+
+ for( std::list< Reference< XDropTargetListener > >::iterator it = aListeners.begin(); it!= aListeners.end(); ++it )
+ {
+ (*it)->dragEnter( dtde );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::dragExit( const DropTargetEvent& dte ) throw()
+{
+ osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
+ std::list< Reference< XDropTargetListener > > aListeners( m_aListeners );
+ aGuard.clear();
+
+ for( std::list< Reference< XDropTargetListener > >::iterator it = aListeners.begin(); it!= aListeners.end(); ++it )
+ {
+ (*it)->dragExit( dte );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::dragOver( const DropTargetDragEvent& dtde ) throw()
+{
+ osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
+ std::list< Reference< XDropTargetListener > > aListeners( m_aListeners );
+ aGuard.clear();
+
+ for( std::list< Reference< XDropTargetListener > >::iterator it = aListeners.begin(); it!= aListeners.end(); ++it )
+ {
+ (*it)->dragOver( dtde );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+/*
+ * XServiceInfo
+ */
+
+// ------------------------------------------------------------------------
+
+OUString DropTarget::getImplementationName() throw()
+{
+ return OUString(RTL_CONSTASCII_USTRINGPARAM(XDND_DROPTARGET_IMPLEMENTATION_NAME));
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool DropTarget::supportsService( const OUString& ServiceName ) throw()
+{
+ Sequence < OUString > SupportedServicesNames = Xdnd_dropTarget_getSupportedServiceNames();
+
+ for ( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
+ if (SupportedServicesNames[n].compareTo(ServiceName) == 0)
+ return sal_True;
+
+ return sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+Sequence< OUString > DropTarget::getSupportedServiceNames() throw()
+{
+ return Xdnd_dropTarget_getSupportedServiceNames();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_selection.cxx b/vcl/unx/generic/dtrans/X11_selection.cxx
new file mode 100644
index 000000000000..facc134b3b56
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_selection.cxx
@@ -0,0 +1,4193 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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/saldisp.hxx"
+#include "unx/saldata.hxx"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "tools/prex.h"
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/Xutil.h>
+#include "tools/postx.h"
+#if defined(LINUX) || defined(NETBSD) || defined (FREEBSD) || defined(OPENBSD)
+#include <sys/poll.h>
+#else
+#include <poll.h>
+#endif
+#include <sal/alloca.h>
+#include <sal/macros.h>
+
+#include <X11_selection.hxx>
+#include <X11_clipboard.hxx>
+#include <X11_transferable.hxx>
+#include <X11_dndcontext.hxx>
+#include <bmp.hxx>
+
+#include "vcl/svapp.hxx"
+
+// pointer bitmaps
+#include <copydata_curs.h>
+#include <copydata_mask.h>
+#include <movedata_curs.h>
+#include <movedata_mask.h>
+#include <linkdata_curs.h>
+#include <linkdata_mask.h>
+#include <nodrop_curs.h>
+#include <nodrop_mask.h>
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/awt/MouseEvent.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <rtl/tencinfo.h>
+#include <osl/process.h>
+
+#include <comphelper/processfactory.hxx>
+#include <osl/mutex.hxx>
+
+#define DRAG_EVENT_MASK ButtonPressMask |\
+ ButtonReleaseMask |\
+ PointerMotionMask |\
+ EnterWindowMask |\
+ LeaveWindowMask
+
+namespace {
+
+namespace css = com::sun::star;
+
+}
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::awt;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::frame;
+using namespace cppu;
+
+using namespace x11;
+
+using ::rtl::OUString;
+using ::rtl::OUStringHash;
+using ::rtl::OStringToOUString;
+
+// stubs to satisfy solaris compiler's rather rigid linking warning
+extern "C"
+{
+ static void call_SelectionManager_run( void * pMgr )
+ {
+ SelectionManager::run( pMgr );
+ }
+
+ static void call_SelectionManager_runDragExecute( void * pMgr )
+ {
+ SelectionManager::runDragExecute( pMgr );
+ }
+}
+
+
+static const long nXdndProtocolRevision = 5;
+
+// mapping between mime types (or what the office thinks of mime types)
+// and X convention types
+struct NativeTypeEntry
+{
+ Atom nAtom;
+ const char* pType; // Mime encoding on our side
+ const char* pNativeType; // string corresponding to nAtom for the case of nAtom being uninitialized
+ int nFormat; // the corresponding format
+};
+
+// the convention for Xdnd is mime types as specified by the corresponding
+// RFC's with the addition that text/plain without charset tag contains iso8859-1
+// sadly some applications (e.g. gtk) do not honor the mimetype only rule,
+// so for compatibility add UTF8_STRING
+static NativeTypeEntry aXdndConversionTab[] =
+{
+ { 0, "text/plain;charset=iso8859-1", "text/plain", 8 },
+ { 0, "text/plain;charset=utf-8", "UTF8_STRING", 8 }
+};
+
+// for clipboard and primary selections there is only a convention for text
+// that the encoding name of the text is taken as type in all capitalized letters
+static NativeTypeEntry aNativeConversionTab[] =
+{
+ { 0, "text/plain;charset=utf-16", "ISO10646-1", 16 },
+ { 0, "text/plain;charset=utf-8", "UTF8_STRING", 8 },
+ { 0, "text/plain;charset=utf-8", "UTF-8", 8 },
+ { 0, "text/plain;charset=utf-8", "text/plain;charset=UTF-8", 8 },
+ // ISO encodings
+ { 0, "text/plain;charset=iso8859-2", "ISO8859-2", 8 },
+ { 0, "text/plain;charset=iso8859-3", "ISO8859-3", 8 },
+ { 0, "text/plain;charset=iso8859-4", "ISO8859-4", 8 },
+ { 0, "text/plain;charset=iso8859-5", "ISO8859-5", 8 },
+ { 0, "text/plain;charset=iso8859-6", "ISO8859-6", 8 },
+ { 0, "text/plain;charset=iso8859-7", "ISO8859-7", 8 },
+ { 0, "text/plain;charset=iso8859-8", "ISO8859-8", 8 },
+ { 0, "text/plain;charset=iso8859-9", "ISO8859-9", 8 },
+ { 0, "text/plain;charset=iso8859-10", "ISO8859-10", 8 },
+ { 0, "text/plain;charset=iso8859-13", "ISO8859-13", 8 },
+ { 0, "text/plain;charset=iso8859-14", "ISO8859-14", 8 },
+ { 0, "text/plain;charset=iso8859-15", "ISO8859-15", 8 },
+ // asian encodings
+ { 0, "text/plain;charset=jisx0201.1976-0", "JISX0201.1976-0", 8 },
+ { 0, "text/plain;charset=jisx0208.1983-0", "JISX0208.1983-0", 8 },
+ { 0, "text/plain;charset=jisx0208.1990-0", "JISX0208.1990-0", 8 },
+ { 0, "text/plain;charset=jisx0212.1990-0", "JISX0212.1990-0", 8 },
+ { 0, "text/plain;charset=gb2312.1980-0", "GB2312.1980-0", 8 },
+ { 0, "text/plain;charset=ksc5601.1992-0", "KSC5601.1992-0", 8 },
+ // eastern european encodings
+ { 0, "text/plain;charset=koi8-r", "KOI8-R", 8 },
+ { 0, "text/plain;charset=koi8-u", "KOI8-U", 8 },
+ // String (== iso8859-1)
+ { XA_STRING, "text/plain;charset=iso8859-1", "STRING", 8 },
+ // special for compound text
+ { 0, "text/plain;charset=compound_text", "COMPOUND_TEXT", 8 },
+
+ // PIXMAP
+ { XA_PIXMAP, "image/bmp", "PIXMAP", 32 }
+};
+
+rtl_TextEncoding x11::getTextPlainEncoding( const OUString& rMimeType )
+{
+ rtl_TextEncoding aEncoding = RTL_TEXTENCODING_DONTKNOW;
+ OUString aMimeType( rMimeType.toAsciiLowerCase() );
+ sal_Int32 nIndex = 0;
+ if( aMimeType.getToken( 0, ';', nIndex ).equalsAsciiL( "text/plain" , 10 ) )
+ {
+ if( aMimeType.getLength() == 10 ) // only "text/plain"
+ aEncoding = RTL_TEXTENCODING_ISO_8859_1;
+ else
+ {
+ while( nIndex != -1 )
+ {
+ OUString aToken = aMimeType.getToken( 0, ';', nIndex );
+ sal_Int32 nPos = 0;
+ if( aToken.getToken( 0, '=', nPos ).equalsAsciiL( "charset", 7 ) )
+ {
+ OString aEncToken = OUStringToOString( aToken.getToken( 0, '=', nPos ), RTL_TEXTENCODING_ISO_8859_1 );
+ aEncoding = rtl_getTextEncodingFromUnixCharset( aEncToken.getStr() );
+ if( aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ {
+ if( aEncToken.equalsIgnoreAsciiCase( "utf-8" ) )
+ aEncoding = RTL_TEXTENCODING_UTF8;
+ }
+ if( aEncoding != RTL_TEXTENCODING_DONTKNOW )
+ break;
+ }
+ }
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ if( aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ fprintf( stderr, "getTextPlainEncoding( %s ) failed\n", OUStringToOString( rMimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ return aEncoding;
+}
+
+// ------------------------------------------------------------------------
+
+::boost::unordered_map< OUString, SelectionManager*, OUStringHash >& SelectionManager::getInstances()
+{
+ static ::boost::unordered_map< OUString, SelectionManager*, OUStringHash > aInstances;
+ return aInstances;
+}
+
+// ------------------------------------------------------------------------
+
+SelectionManager::SelectionManager() :
+ m_nIncrementalThreshold( 15*1024 ),
+ m_pDisplay( NULL ),
+ m_aThread( NULL ),
+ m_aDragExecuteThread( NULL ),
+ m_aWindow( None ),
+ m_nSelectionTimeout( 0 ),
+ m_nSelectionTimestamp( CurrentTime ),
+ m_bDropEnterSent( true ),
+ m_aCurrentDropWindow( None ),
+ m_nDropTime( None ),
+ m_nLastDropAction( 0 ),
+ m_nLastX( 0 ),
+ m_nLastY( 0 ),
+ m_nDropTimestamp( 0 ),
+ m_bDropWaitingForCompletion( false ),
+ m_aDropWindow( None ),
+ m_aDropProxy( None ),
+ m_aDragSourceWindow( None ),
+ m_nLastDragX( 0 ),
+ m_nLastDragY( 0 ),
+ m_nNoPosX( 0 ),
+ m_nNoPosY( 0 ),
+ m_nNoPosWidth( 0 ),
+ m_nNoPosHeight( 0 ),
+ m_nDragButton( 0 ),
+ m_nUserDragAction( 0 ),
+ m_nTargetAcceptAction( 0 ),
+ m_nSourceActions( 0 ),
+ m_bLastDropAccepted( false ),
+ m_bDropSuccess( false ),
+ m_bDropSent( false ),
+ m_bWaitingForPrimaryConversion( false ),
+ m_nDragTimestamp( None ),
+ m_aMoveCursor( None ),
+ m_aCopyCursor( None ),
+ m_aLinkCursor( None ),
+ m_aNoneCursor( None ),
+ m_aCurrentCursor( None ),
+ m_nCurrentProtocolVersion( nXdndProtocolRevision ),
+ m_nCLIPBOARDAtom( None ),
+ m_nTARGETSAtom( None ),
+ m_nTIMESTAMPAtom( None ),
+ m_nTEXTAtom( None ),
+ m_nINCRAtom( None ),
+ m_nCOMPOUNDAtom( None ),
+ m_nMULTIPLEAtom( None ),
+ m_nUTF16Atom( None ),
+ m_nImageBmpAtom( None ),
+ m_nXdndAware( None ),
+ m_nXdndEnter( None ),
+ m_nXdndLeave( None ),
+ m_nXdndPosition( None ),
+ m_nXdndStatus( None ),
+ m_nXdndDrop( None ),
+ m_nXdndFinished( None ),
+ m_nXdndSelection( None ),
+ m_nXdndTypeList( None ),
+ m_nXdndProxy( None ),
+ m_nXdndActionCopy( None ),
+ m_nXdndActionMove( None ),
+ m_nXdndActionLink( None ),
+ m_nXdndActionAsk( None ),
+ m_nXdndActionPrivate( None ),
+ m_bShutDown( false )
+{
+ m_aDropEnterEvent.data.l[0] = None;
+ m_aDragRunning.reset();
+}
+
+XLIB_Cursor SelectionManager::createCursor( const unsigned char* pPointerData, const unsigned char* pMaskData, int width, int height, int hotX, int hotY )
+{
+ Pixmap aPointer;
+ Pixmap aMask;
+ XColor aBlack, aWhite;
+
+ aBlack.pixel = BlackPixel( m_pDisplay, 0 );
+ aBlack.red = aBlack.green = aBlack.blue = 0;
+ aBlack.flags = DoRed | DoGreen | DoBlue;
+
+ aWhite.pixel = WhitePixel( m_pDisplay, 0 );
+ aWhite.red = aWhite.green = aWhite.blue = 0xffff;
+ aWhite.flags = DoRed | DoGreen | DoBlue;
+
+ aPointer =
+ XCreateBitmapFromData( m_pDisplay,
+ m_aWindow,
+ reinterpret_cast<const char*>(pPointerData),
+ width,
+ height );
+ aMask
+ = XCreateBitmapFromData( m_pDisplay,
+ m_aWindow,
+ reinterpret_cast<const char*>(pMaskData),
+ width,
+ height );
+ XLIB_Cursor aCursor =
+ XCreatePixmapCursor( m_pDisplay, aPointer, aMask,
+ &aBlack, &aWhite,
+ hotX,
+ hotY );
+ XFreePixmap( m_pDisplay, aPointer );
+ XFreePixmap( m_pDisplay, aMask );
+
+ return aCursor;
+}
+
+void SelectionManager::initialize( const Sequence< Any >& arguments ) throw (::com::sun::star::uno::Exception)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ if( ! m_xDisplayConnection.is() )
+ {
+ /*
+ * first argument must be a ::com::sun::star::awt::XDisplayConnection
+ * from this we will get the XEvents of the vcl event loop by
+ * registering us as XEventHandler on it.
+ *
+ * implementor's note:
+ * FIXME:
+ * finally the clipboard and XDND service is back in the module it belongs
+ * now cleanup and sharing of resources with the normal vcl event loop
+ * needs to be added. The display used whould be that of the normal event loop
+ * and synchronization should be done via the SolarMutex.
+ */
+ if( arguments.getLength() > 0 )
+ arguments.getConstArray()[0] >>= m_xDisplayConnection;
+ if( ! m_xDisplayConnection.is() )
+ {
+ }
+ else
+ m_xDisplayConnection->addEventHandler( Any(), this, ~0 );
+ }
+
+ if( !m_xBitmapConverter.is() )
+ {
+ if( arguments.getLength() > 2 )
+ arguments.getConstArray()[2] >>= m_xBitmapConverter;
+ }
+
+ OUString aParam;
+ if( ! m_pDisplay )
+ {
+ OUString aUDisplay;
+ if( m_xDisplayConnection.is() )
+ {
+ Any aIdentifier;
+ aIdentifier = m_xDisplayConnection->getIdentifier();
+ aIdentifier >>= aUDisplay;
+ }
+
+ OString aDisplayName( OUStringToOString( aUDisplay, RTL_TEXTENCODING_ISO_8859_1 ) );
+
+ m_pDisplay = XOpenDisplay( aDisplayName.getLength() ? aDisplayName.getStr() : NULL );
+
+ if( m_pDisplay )
+ {
+#ifdef SYNCHRONIZE
+ XSynchronize( m_pDisplay, True );
+#endif
+ // clipboard selection
+ m_nCLIPBOARDAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) );
+
+ // special targets
+ m_nTARGETSAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("TARGETS")) );
+ m_nTIMESTAMPAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("TIMESTAMP")) );
+ m_nTEXTAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("TEXT")) );
+ m_nINCRAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("INCR")) );
+ m_nCOMPOUNDAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("COMPOUND_TEXT")) );
+ m_nMULTIPLEAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("MULTIPLE")) );
+ m_nUTF16Atom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("ISO10646-1")) );
+ m_nImageBmpAtom = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("image/bmp")) );
+
+ // Atoms for Xdnd protocol
+ m_nXdndAware = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndAware")) );
+ m_nXdndEnter = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndEnter")) );
+ m_nXdndLeave = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndLeave")) );
+ m_nXdndPosition = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndPosition")) );
+ m_nXdndStatus = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndStatus")) );
+ m_nXdndDrop = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndDrop")) );
+ m_nXdndFinished = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndFinished")) );
+ m_nXdndSelection = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndSelection")) );
+ m_nXdndTypeList = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndTypeList")) );
+ m_nXdndProxy = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndProxy")) );
+ m_nXdndActionCopy = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndActionCopy")) );
+ m_nXdndActionMove = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndActionMove")) );
+ m_nXdndActionLink = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndActionLink")) );
+ m_nXdndActionAsk = getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndActionAsk")) );
+ m_nXdndActionPrivate= getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("XdndActionPrivate")) );
+
+ // initialize map with member none
+ m_aAtomToString[ 0 ]= OUString(RTL_CONSTASCII_USTRINGPARAM("None"));
+ m_aAtomToString[ XA_PRIMARY ] = OUString(RTL_CONSTASCII_USTRINGPARAM("PRIMARY"));
+
+ // create a (invisible) message window
+ m_aWindow = XCreateSimpleWindow( m_pDisplay, DefaultRootWindow( m_pDisplay ),
+ 10, 10, 10, 10, 0, 0, 1 );
+
+ // initialize threshold for incremetal transfers
+ // ICCCM says it should be smaller that the max request size
+ // which in turn is guaranteed to be at least 16k bytes
+ m_nIncrementalThreshold = XMaxRequestSize( m_pDisplay ) - 1024;
+
+ if( m_aWindow )
+ {
+ // initialize default cursors
+ m_aMoveCursor = createCursor( movedata_curs_bits,
+ movedata_mask_bits,
+ movedata_curs_width,
+ movedata_curs_height,
+ movedata_curs_x_hot,
+ movedata_curs_y_hot );
+ m_aCopyCursor = createCursor( copydata_curs_bits,
+ copydata_mask_bits,
+ copydata_curs_width,
+ copydata_curs_height,
+ copydata_curs_x_hot,
+ copydata_curs_y_hot );
+ m_aLinkCursor = createCursor( linkdata_curs_bits,
+ linkdata_mask_bits,
+ linkdata_curs_width,
+ linkdata_curs_height,
+ linkdata_curs_x_hot,
+ linkdata_curs_y_hot );
+ m_aNoneCursor = createCursor( nodrop_curs_bits,
+ nodrop_mask_bits,
+ nodrop_curs_width,
+ nodrop_curs_height,
+ nodrop_curs_x_hot,
+ nodrop_curs_y_hot );
+
+
+
+
+ // just interested in SelectionClear/Notify/Request and PropertyChange
+ XSelectInput( m_pDisplay, m_aWindow, PropertyChangeMask );
+ // create the transferable for Drag operations
+ m_xDropTransferable = new X11Transferable( *this, static_cast< OWeakObject* >(this), m_nXdndSelection );
+ registerHandler( m_nXdndSelection, *this );
+
+ m_aThread = osl_createSuspendedThread( call_SelectionManager_run, this );
+ if( m_aThread )
+ osl_resumeThread( m_aThread );
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "SelectionManager::initialize: creation of dispatch thread failed !\n" );
+#endif
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+SelectionManager::~SelectionManager()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SelectionManager::~SelectionManager (%s)\n", m_pDisplay ? DisplayString(m_pDisplay) : "no display" );
+#endif
+ {
+ osl::MutexGuard aGuard( *osl::Mutex::getGlobalMutex() );
+
+ ::boost::unordered_map< OUString, SelectionManager*, OUStringHash >::iterator it;
+ for( it = getInstances().begin(); it != getInstances().end(); ++it )
+ if( it->second == this )
+ {
+ getInstances().erase( it );
+ break;
+ }
+ }
+
+ if( m_aThread )
+ {
+ osl_terminateThread( m_aThread );
+ osl_joinWithThread( m_aThread );
+ osl_destroyThread( m_aThread );
+ }
+
+ if( m_aDragExecuteThread )
+ {
+ osl_terminateThread( m_aDragExecuteThread );
+ osl_joinWithThread( m_aDragExecuteThread );
+ m_aDragExecuteThread = NULL;
+ // thread handle is freed in dragDoDispatch()
+ }
+
+ osl::MutexGuard aGuard(m_aMutex);
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "shutting down SelectionManager\n" );
+#endif
+
+ if( m_xDisplayConnection.is() )
+ {
+ m_xDisplayConnection->removeEventHandler( Any(), this );
+ m_xDisplayConnection.clear();
+ }
+
+ if( m_pDisplay )
+ {
+ deregisterHandler( m_nXdndSelection );
+ // destroy message window
+ if( m_aWindow )
+ XDestroyWindow( m_pDisplay, m_aWindow );
+ // release cursors
+ if (m_aMoveCursor != None)
+ XFreeCursor(m_pDisplay, m_aMoveCursor);
+ if (m_aCopyCursor != None)
+ XFreeCursor(m_pDisplay, m_aCopyCursor);
+ if (m_aLinkCursor != None)
+ XFreeCursor(m_pDisplay, m_aLinkCursor);
+ if (m_aNoneCursor != None)
+ XFreeCursor(m_pDisplay, m_aNoneCursor);
+
+ // paranoia setting, the drag thread should have
+ // done that already
+ XUngrabPointer( m_pDisplay, CurrentTime );
+ XUngrabKeyboard( m_pDisplay, CurrentTime );
+
+ XCloseDisplay( m_pDisplay );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+SelectionAdaptor* SelectionManager::getAdaptor( Atom selection )
+{
+ ::boost::unordered_map< Atom, Selection* >::iterator it =
+ m_aSelections.find( selection );
+ return it != m_aSelections.end() ? it->second->m_pAdaptor : NULL;
+}
+
+// ------------------------------------------------------------------------
+
+OUString SelectionManager::convertFromCompound( const char* pText, int nLen )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+ OUString aRet;
+ if( nLen < 0 )
+ nLen = strlen( pText );
+
+ char** pTextList = NULL;
+ int nTexts = 0;
+
+ XTextProperty aProp;
+ aProp.value = (unsigned char*)pText;
+ aProp.encoding = m_nCOMPOUNDAtom;
+ aProp.format = 8;
+ aProp.nitems = nLen;
+ XmbTextPropertyToTextList( m_pDisplay,
+ &aProp,
+ &pTextList,
+ &nTexts );
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ for( int i = 0; i < nTexts; i++ )
+ aRet += OStringToOUString( pTextList[i], aEncoding );
+
+ if( pTextList )
+ XFreeStringList( pTextList );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+OString SelectionManager::convertToCompound( const OUString& rText )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+ XTextProperty aProp;
+ aProp.value = NULL;
+ aProp.encoding = XA_STRING;
+ aProp.format = 8;
+ aProp.nitems = 0;
+
+ OString aRet( rText.getStr(), rText.getLength(), osl_getThreadTextEncoding() );
+ char* pT = const_cast<char*>(aRet.getStr());
+
+ XmbTextListToTextProperty( m_pDisplay,
+ &pT,
+ 1,
+ XCompoundTextStyle,
+ &aProp );
+ if( aProp.value )
+ {
+ aRet = (char*)aProp.value;
+ XFree( aProp.value );
+#ifdef SOLARIS
+ /*
+ * for currently unknown reasons XmbTextListToTextProperty on Solaris returns
+ * no data in ISO8859-n encodings (at least for n = 1, 15)
+ * in these encodings the directly converted text does the
+ * trick, also.
+ */
+ if( ! aRet.getLength() && rText.getLength() )
+ aRet = OUStringToOString( rText, osl_getThreadTextEncoding() );
+#endif
+ }
+ else
+ aRet = OString();
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::convertData(
+ const css::uno::Reference< XTransferable >& xTransferable,
+ Atom nType,
+ Atom nSelection,
+ int& rFormat,
+ Sequence< sal_Int8 >& rData )
+{
+ bool bSuccess = false;
+
+ if( ! xTransferable.is() )
+ return bSuccess;
+
+ try
+ {
+
+ DataFlavor aFlavor;
+ aFlavor.MimeType = convertTypeFromNative( nType, nSelection, rFormat );
+
+ sal_Int32 nIndex = 0;
+ if( aFlavor.MimeType.getToken( 0, ';', nIndex ).compareToAscii( "text/plain" ) == 0 )
+ {
+ if( aFlavor.MimeType.getToken( 0, ';', nIndex ).compareToAscii( "charset=utf-16" ) == 0 )
+ aFlavor.DataType = getCppuType( (OUString *) 0 );
+ else
+ aFlavor.DataType = getCppuType( (Sequence< sal_Int8 >*)0 );
+ }
+ else
+ aFlavor.DataType = getCppuType( (Sequence< sal_Int8 >*)0 );
+
+ if( xTransferable->isDataFlavorSupported( aFlavor ) )
+ {
+ Any aValue( xTransferable->getTransferData( aFlavor ) );
+ if( aValue.getValueTypeClass() == TypeClass_STRING )
+ {
+ OUString aString;
+ aValue >>= aString;
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aString.getStr(), aString.getLength() * sizeof( sal_Unicode ) );
+ bSuccess = true;
+ }
+ else if( aValue.getValueType() == getCppuType( (Sequence< sal_Int8 >*)0 ) )
+ {
+ aValue >>= rData;
+ bSuccess = true;
+ }
+ }
+ else if( aFlavor.MimeType.compareToAscii( "text/plain", 10 ) == 0 )
+ {
+ rtl_TextEncoding aEncoding = RTL_TEXTENCODING_DONTKNOW;
+ bool bCompoundText = false;
+ if( nType == m_nCOMPOUNDAtom )
+ bCompoundText = true;
+ else
+ aEncoding = getTextPlainEncoding( aFlavor.MimeType );
+ if( aEncoding != RTL_TEXTENCODING_DONTKNOW || bCompoundText )
+ {
+ aFlavor.MimeType = OUString(RTL_CONSTASCII_USTRINGPARAM("text/plain;charset=utf-16"));
+ aFlavor.DataType = getCppuType( (OUString *) 0 );
+ if( xTransferable->isDataFlavorSupported( aFlavor ) )
+ {
+ Any aValue( xTransferable->getTransferData( aFlavor ) );
+ OUString aString;
+ aValue >>= aString;
+ OString aByteString( bCompoundText ? convertToCompound( aString ) : OUStringToOString( aString, aEncoding ) );
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aByteString.getStr(), aByteString.getLength() * sizeof( sal_Char ) );
+ bSuccess = true;
+ }
+ }
+ }
+ }
+ // various exceptions possible ... which all lead to a failed conversion
+ // so simplify here to a catch all
+ catch(...)
+ {
+ }
+
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+SelectionManager& SelectionManager::get( const OUString& rDisplayName )
+{
+ osl::MutexGuard aGuard( *osl::Mutex::getGlobalMutex() );
+
+ OUString aDisplayName( rDisplayName );
+ if( ! aDisplayName.getLength() )
+ aDisplayName = OStringToOUString( getenv( "DISPLAY" ), RTL_TEXTENCODING_ISO_8859_1 );
+ SelectionManager* pInstance = NULL;
+
+ ::boost::unordered_map< OUString, SelectionManager*, OUStringHash >::iterator it = getInstances().find( aDisplayName );
+ if( it != getInstances().end() )
+ pInstance = it->second;
+ else pInstance = getInstances()[ aDisplayName ] = new SelectionManager();
+
+ return *pInstance;
+}
+
+// ------------------------------------------------------------------------
+
+const OUString& SelectionManager::getString( Atom aAtom )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ ::boost::unordered_map< Atom, OUString >::const_iterator it;
+ if( ( it = m_aAtomToString.find( aAtom ) ) == m_aAtomToString.end() )
+ {
+ static OUString aEmpty;
+ char* pAtom = m_pDisplay ? XGetAtomName( m_pDisplay, aAtom ) : NULL;
+ if( ! pAtom )
+ return aEmpty;
+ OUString aString( OStringToOUString( pAtom, RTL_TEXTENCODING_ISO_8859_1 ) );
+ XFree( pAtom );
+ m_aStringToAtom[ aString ] = aAtom;
+ m_aAtomToString[ aAtom ] = aString;
+ }
+ return m_aAtomToString[ aAtom ];
+}
+
+// ------------------------------------------------------------------------
+
+Atom SelectionManager::getAtom( const OUString& rString )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ ::boost::unordered_map< OUString, Atom, OUStringHash >::const_iterator it;
+ if( ( it = m_aStringToAtom.find( rString ) ) == m_aStringToAtom.end() )
+ {
+ static Atom nNoDisplayAtoms = 1;
+ Atom aAtom = m_pDisplay ? XInternAtom( m_pDisplay, OUStringToOString( rString, RTL_TEXTENCODING_ISO_8859_1 ), False ) : nNoDisplayAtoms++;
+ m_aStringToAtom[ rString ] = aAtom;
+ m_aAtomToString[ aAtom ] = rString;
+ }
+ return m_aStringToAtom[ rString ];
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::requestOwnership( Atom selection )
+{
+ bool bSuccess = false;
+ if( m_pDisplay && m_aWindow )
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ SelectionAdaptor* pAdaptor = getAdaptor( selection );
+ if( pAdaptor )
+ {
+ XSetSelectionOwner( m_pDisplay, selection, m_aWindow, CurrentTime );
+ if( XGetSelectionOwner( m_pDisplay, selection ) == m_aWindow )
+ bSuccess = true;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s ownership for selection %s\n",
+ bSuccess ? "acquired" : "failed to acquire",
+ OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ Selection* pSel = m_aSelections[ selection ];
+ pSel->m_bOwner = bSuccess;
+ delete pSel->m_pPixmap;
+ pSel->m_pPixmap = NULL;
+ pSel->m_nOrigTimestamp = m_nSelectionTimestamp;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "no adaptor for selection %s\n",
+ OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+
+ if( pAdaptor->getTransferable().is() )
+ {
+ Sequence< DataFlavor > aTypes = pAdaptor->getTransferable()->getTransferDataFlavors();
+ for( int i = 0; i < aTypes.getLength(); i++ )
+ {
+ fprintf( stderr, " %s\n", OUStringToOString( aTypes.getConstArray()[i].MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ }
+ }
+#endif
+ }
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::convertTypeToNative( const OUString& rType, Atom selection, int& rFormat, ::std::list< Atom >& rConversions, bool bPushFront )
+{
+ NativeTypeEntry* pTab = selection == m_nXdndSelection ? aXdndConversionTab : aNativeConversionTab;
+ int nTabEntries = selection == m_nXdndSelection ? SAL_N_ELEMENTS(aXdndConversionTab) : SAL_N_ELEMENTS(aNativeConversionTab);
+
+ OString aType( OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ) );
+ rFormat = 0;
+ for( int i = 0; i < nTabEntries; i++ )
+ {
+ if( aType.equalsIgnoreAsciiCase( pTab[i].pType ) )
+ {
+ if( ! pTab[i].nAtom )
+ pTab[i].nAtom = getAtom( OStringToOUString( pTab[i].pNativeType, RTL_TEXTENCODING_ISO_8859_1 ) );
+ rFormat = pTab[i].nFormat;
+ if( bPushFront )
+ rConversions.push_front( pTab[i].nAtom );
+ else
+ rConversions.push_back( pTab[i].nAtom );
+ if( pTab[i].nFormat == XA_PIXMAP )
+ {
+ if( bPushFront )
+ {
+ rConversions.push_front( XA_VISUALID );
+ rConversions.push_front( XA_COLORMAP );
+ }
+ else
+ {
+ rConversions.push_back( XA_VISUALID );
+ rConversions.push_back( XA_COLORMAP );
+ }
+ }
+ }
+ }
+ if( ! rFormat )
+ rFormat = 8; // byte buffer
+ if( bPushFront )
+ rConversions.push_front( getAtom( rType ) );
+ else
+ rConversions.push_back( getAtom( rType ) );
+};
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::getNativeTypeList( const Sequence< DataFlavor >& rTypes, std::list< Atom >& rOutTypeList, Atom targetselection )
+{
+ rOutTypeList.clear();
+
+ int nFormat;
+ int nFlavors = rTypes.getLength();
+ const DataFlavor* pFlavors = rTypes.getConstArray();
+ bool bHaveText = false;
+ for( int i = 0; i < nFlavors; i++ )
+ {
+ if( pFlavors[i].MimeType.compareToAscii( "text/plain", 10 ) == 0)
+ bHaveText = true;
+ else
+ convertTypeToNative( pFlavors[i].MimeType, targetselection, nFormat, rOutTypeList );
+ }
+ if( bHaveText )
+ {
+ if( targetselection != m_nXdndSelection )
+ {
+ // only mimetypes should go into Xdnd type list
+ rOutTypeList.push_front( XA_STRING );
+ rOutTypeList.push_front( m_nCOMPOUNDAtom );
+ }
+ convertTypeToNative( OUString(RTL_CONSTASCII_USTRINGPARAM("text/plain;charset=utf-8")), targetselection, nFormat, rOutTypeList, true );
+ }
+ if( targetselection != m_nXdndSelection )
+ rOutTypeList.push_back( m_nMULTIPLEAtom );
+}
+
+// ------------------------------------------------------------------------
+
+OUString SelectionManager::convertTypeFromNative( Atom nType, Atom selection, int& rFormat )
+{
+ NativeTypeEntry* pTab = (selection == m_nXdndSelection) ? aXdndConversionTab : aNativeConversionTab;
+ int nTabEntries = (selection == m_nXdndSelection) ? SAL_N_ELEMENTS(aXdndConversionTab) : SAL_N_ELEMENTS(aNativeConversionTab);
+
+ for( int i = 0; i < nTabEntries; i++ )
+ {
+ if( ! pTab[i].nAtom )
+ pTab[i].nAtom = getAtom( OStringToOUString( pTab[i].pNativeType, RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( nType == pTab[i].nAtom )
+ {
+ rFormat = pTab[i].nFormat;
+ return OStringToOUString( pTab[i].pType, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ }
+ rFormat = 8;
+ return getString( nType );
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::getPasteData( Atom selection, Atom type, Sequence< sal_Int8 >& rData )
+{
+ osl::ResettableMutexGuard aGuard(m_aMutex);
+ ::boost::unordered_map< Atom, Selection* >::iterator it;
+ bool bSuccess = false;
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString aSelection( getString( selection ) );
+ OUString aType( getString( type ) );
+ fprintf( stderr, "getPasteData( %s, native: %s )\n",
+ OUStringToOString( aSelection, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( aType, RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+
+ if( ! m_pDisplay )
+ return false;
+
+ it = m_aSelections.find( selection );
+ if( it == m_aSelections.end() )
+ return false;
+
+ XLIB_Window aSelectionOwner = XGetSelectionOwner( m_pDisplay, selection );
+ if( aSelectionOwner == None )
+ return false;
+ if( aSelectionOwner == m_aWindow )
+ {
+ // probably bad timing led us here
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Innere Nabelschau\n" );
+#endif
+ return false;
+ }
+
+ // ICCCM recommends to destroy property before convert request unless
+ // parameters are transported; we do only in case of MULTIPLE,
+ // so destroy property unless target is MULTIPLE
+ if( type != m_nMULTIPLEAtom )
+ XDeleteProperty( m_pDisplay, m_aWindow, selection );
+
+ XConvertSelection( m_pDisplay, selection, type, selection, m_aWindow, selection == m_nXdndSelection ? m_nDropTime : CurrentTime );
+ it->second->m_eState = Selection::WaitingForResponse;
+ it->second->m_aRequestedType = type;
+ it->second->m_aData = Sequence< sal_Int8 >();
+ it->second->m_aDataArrived.reset();
+ // really start the request; if we don't flush the
+ // queue the request won't leave it because there are no more
+ // X calls after this until the data arrived or timeout
+ XFlush( m_pDisplay );
+
+ // do a reschedule
+ struct timeval tv_last, tv_current;
+ gettimeofday( &tv_last, NULL );
+ tv_current = tv_last;
+
+ XEvent aEvent;
+ do
+ {
+ bool bAdjustTime = false;
+ {
+ bool bHandle = false;
+
+ if( XCheckTypedEvent( m_pDisplay,
+ PropertyNotify,
+ &aEvent
+ ) )
+ {
+ bHandle = true;
+ if( aEvent.xproperty.window == m_aWindow
+ && aEvent.xproperty.atom == selection )
+ bAdjustTime = true;
+ }
+ else
+ if( XCheckTypedEvent( m_pDisplay,
+ SelectionClear,
+ &aEvent
+ ) )
+ {
+ bHandle = true;
+ }
+ else
+ if( XCheckTypedEvent( m_pDisplay,
+ SelectionRequest,
+ &aEvent
+ ) )
+ bHandle = true;
+ else
+ if( XCheckTypedEvent( m_pDisplay,
+ SelectionNotify,
+ &aEvent
+ ) )
+ {
+ bHandle = true;
+ if( aEvent.xselection.selection == selection
+ && ( aEvent.xselection.requestor == m_aWindow ||
+ aEvent.xselection.requestor == m_aCurrentDropWindow )
+ )
+ bAdjustTime = true;
+ }
+ else
+ {
+ TimeValue aTVal;
+ aTVal.Seconds = 0;
+ aTVal.Nanosec = 100000000;
+ aGuard.clear();
+ osl_waitThread( &aTVal );
+ aGuard.reset();
+ }
+ if( bHandle )
+ {
+ aGuard.clear();
+ handleXEvent( aEvent );
+ aGuard.reset();
+ }
+ }
+ gettimeofday( &tv_current, NULL );
+ if( bAdjustTime )
+ tv_last = tv_current;
+ } while( ! it->second->m_aDataArrived.check() && (tv_current.tv_sec - tv_last.tv_sec) < getSelectionTimeout() );
+
+#if OSL_DEBUG_LEVEL > 1
+ if( (tv_current.tv_sec - tv_last.tv_sec) > getSelectionTimeout() )
+ fprintf( stderr, "timed out\n" );
+#endif
+ if( it->second->m_aDataArrived.check() &&
+ it->second->m_aData.getLength() )
+ {
+ rData = it->second->m_aData;
+ bSuccess = true;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "conversion unsuccessfull\n" );
+#endif
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::getPasteData( Atom selection, const ::rtl::OUString& rType, Sequence< sal_Int8 >& rData )
+{
+ bool bSuccess = false;
+
+ ::boost::unordered_map< Atom, Selection* >::iterator it;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ it = m_aSelections.find( selection );
+ if( it == m_aSelections.end() )
+ return false;
+ }
+
+ if( it->second->m_aTypes.getLength() == 0 )
+ {
+ Sequence< DataFlavor > aFlavors;
+ getPasteDataTypes( selection, aFlavors );
+ if( it->second->m_aTypes.getLength() == 0 )
+ return false;
+ }
+
+ const Sequence< DataFlavor >& rTypes( it->second->m_aTypes );
+ const std::vector< Atom >& rNativeTypes( it->second->m_aNativeTypes );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "getPasteData( \"%s\", \"%s\" )\n",
+ OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+
+ if( rType.equalsAsciiL( "text/plain;charset=utf-16", 25 ) )
+ {
+ // lets see if we have UTF16 else try to find something convertible
+ if( it->second->m_aTypes.getLength() && ! it->second->m_bHaveUTF16 )
+ {
+ Sequence< sal_Int8 > aData;
+ if( it->second->m_aUTF8Type != None &&
+ getPasteData( selection,
+ it->second->m_aUTF8Type,
+ aData )
+ )
+ {
+ OUString aRet( (const sal_Char*)aData.getConstArray(), aData.getLength(), RTL_TEXTENCODING_UTF8 );
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aRet.getStr(), (aRet.getLength()+1)*sizeof( sal_Unicode ) );
+ bSuccess = true;
+ }
+ else if( it->second->m_bHaveCompound &&
+ getPasteData( selection,
+ m_nCOMPOUNDAtom,
+ aData )
+ )
+ {
+ OUString aRet( convertFromCompound( (const char*)aData.getConstArray(), aData.getLength() ) );
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aRet.getStr(), (aRet.getLength()+1)*sizeof( sal_Unicode ) );
+ bSuccess = true;
+ }
+ else
+ {
+ for( int i = 0; i < rTypes.getLength(); i++ )
+ {
+ rtl_TextEncoding aEncoding = getTextPlainEncoding( rTypes.getConstArray()[i].MimeType );
+ if( aEncoding != RTL_TEXTENCODING_DONTKNOW &&
+ aEncoding != RTL_TEXTENCODING_UNICODE &&
+ getPasteData( selection,
+ rNativeTypes[i],
+ aData )
+ )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "using \"%s\" instead of \"%s\"\n",
+ OUStringToOString( rTypes.getConstArray()[i].MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+ OString aConvert( (sal_Char*)aData.getConstArray(), aData.getLength() );
+ OUString aUTF( OStringToOUString( aConvert, aEncoding ) );
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aUTF.getStr(), (aUTF.getLength()+1)*sizeof( sal_Unicode ) );
+ bSuccess = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if( rType.equalsAsciiL( "image/bmp", 9 ) )
+ {
+ // #i83376# try if someone has the data in image/bmp already before
+ // doing the PIXMAP stuff (e.g. the gimp has this)
+ bSuccess = getPasteData( selection, m_nImageBmpAtom, rData );
+ #if OSL_DEBUG_LEVEL > 1
+ if( bSuccess )
+ fprintf( stderr, "got %d bytes of image/bmp\n", (int)rData.getLength() );
+ #endif
+ if( ! bSuccess )
+ {
+ Pixmap aPixmap = None;
+ Colormap aColormap = None;
+
+ // prepare property for MULTIPLE request
+ Sequence< sal_Int8 > aData;
+ Atom pTypes[4] = { XA_PIXMAP, XA_PIXMAP,
+ XA_COLORMAP, XA_COLORMAP };
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ XChangeProperty( m_pDisplay,
+ m_aWindow,
+ selection,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char*)pTypes,
+ 4 );
+ }
+
+ // try MULTIPLE request
+ if( getPasteData( selection, m_nMULTIPLEAtom, aData ) )
+ {
+ Atom* pReturnedTypes = (Atom*)aData.getArray();
+ if( pReturnedTypes[0] == XA_PIXMAP && pReturnedTypes[1] == XA_PIXMAP )
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ Atom type = None;
+ int format = 0;
+ unsigned long nItems = 0;
+ unsigned long nBytes = 0;
+ unsigned char* pReturn = NULL;
+ XGetWindowProperty( m_pDisplay, m_aWindow, XA_PIXMAP, 0, 1, True, XA_PIXMAP, &type, &format, &nItems, &nBytes, &pReturn );
+ if( pReturn )
+ {
+ if( type == XA_PIXMAP )
+ aPixmap = *(Pixmap*)pReturn;
+ XFree( pReturn );
+ pReturn = NULL;
+ if( pReturnedTypes[2] == XA_COLORMAP && pReturnedTypes[3] == XA_COLORMAP )
+ {
+ XGetWindowProperty( m_pDisplay, m_aWindow, XA_COLORMAP, 0, 1, True, XA_COLORMAP, &type, &format, &nItems, &nBytes, &pReturn );
+ if( pReturn )
+ {
+ if( type == XA_COLORMAP )
+ aColormap = *(Colormap*)pReturn;
+ XFree( pReturn );
+ }
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ {
+ fprintf( stderr, "could not get PIXMAP property: type=%s, format=%d, items=%ld, bytes=%ld, ret=0x%p\n", OUStringToOString( getString( type ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(), format, nItems, nBytes, pReturn );
+ }
+ #endif
+ }
+ }
+
+ if( aPixmap == None )
+ {
+ // perhaps two normal requests will work
+ if( getPasteData( selection, XA_PIXMAP, aData ) )
+ {
+ aPixmap = *(Pixmap*)aData.getArray();
+ if( aColormap == None && getPasteData( selection, XA_COLORMAP, aData ) )
+ aColormap = *(Colormap*)aData.getArray();
+ }
+ }
+
+ // convert data if possible
+ if( aPixmap != None )
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ sal_Int32 nOutSize = 0;
+ sal_uInt8* pBytes = X11_getBmpFromPixmap( m_pDisplay, aPixmap, aColormap, nOutSize );
+ if( pBytes && nOutSize )
+ {
+ rData = Sequence< sal_Int8 >( nOutSize );
+ memcpy( rData.getArray(), pBytes, nOutSize );
+ X11_freeBmp( pBytes );
+ bSuccess = true;
+ }
+ }
+ }
+ }
+
+ if( ! bSuccess )
+ {
+ int nFormat;
+ ::std::list< Atom > aTypes;
+ convertTypeToNative( rType, selection, nFormat, aTypes );
+ ::std::list< Atom >::const_iterator type_it;
+ Atom nSelectedType = None;
+ for( type_it = aTypes.begin(); type_it != aTypes.end() && nSelectedType == None; ++type_it )
+ {
+ for( unsigned int i = 0; i < rNativeTypes.size() && nSelectedType == None; i++ )
+ if( rNativeTypes[i] == *type_it )
+ nSelectedType = *type_it;
+ }
+ if( nSelectedType != None )
+ bSuccess = getPasteData( selection, nSelectedType, rData );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "getPasteData for selection %s and data type %s returns %s, returned sequence has length %" SAL_PRIdINT32 "\n",
+ OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ bSuccess ? "true" : "false",
+ rData.getLength()
+ );
+#endif
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::getPasteDataTypes( Atom selection, Sequence< DataFlavor >& rTypes )
+{
+ ::boost::unordered_map< Atom, Selection* >::iterator it;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ it = m_aSelections.find( selection );
+ if( it != m_aSelections.end() &&
+ it->second->m_aTypes.getLength() &&
+ abs( it->second->m_nLastTimestamp - time( NULL ) ) < 2
+ )
+ {
+ rTypes = it->second->m_aTypes;
+ return true;
+ }
+ }
+
+ bool bSuccess = false;
+ bool bHaveUTF16 = false;
+ Atom aUTF8Type = None;
+ bool bHaveCompound = false;
+ bool bHaveText = false;
+ Sequence< sal_Int8 > aAtoms;
+
+ if( selection == m_nXdndSelection )
+ {
+ // xdnd sends first three types with XdndEnter
+ // if more than three types are supported then the XDndTypeList
+ // property on the source window is used
+ if( m_aDropEnterEvent.data.l[0] && m_aCurrentDropWindow )
+ {
+ if( m_aDropEnterEvent.data.l[1] & 1 )
+ {
+ const unsigned int atomcount = 256;
+ // more than three types; look in property
+ osl::MutexGuard aGuard(m_aMutex);
+
+ Atom nType;
+ int nFormat;
+ unsigned long nItems, nBytes;
+ unsigned char* pBytes = NULL;
+
+ XGetWindowProperty( m_pDisplay, m_aDropEnterEvent.data.l[0],
+ m_nXdndTypeList, 0, atomcount, False,
+ XA_ATOM,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "have %ld data types in XdndTypeList\n", nItems );
+#endif
+ if( nItems == atomcount && nBytes > 0 )
+ {
+ // wow ... more than 256 types !
+ aAtoms.realloc( sizeof( Atom )*atomcount+nBytes );
+ memcpy( aAtoms.getArray(), pBytes, sizeof( Atom )*atomcount );
+ XFree( pBytes );
+ pBytes = NULL;
+ XGetWindowProperty( m_pDisplay, m_aDropEnterEvent.data.l[0],
+ m_nXdndTypeList, atomcount, nBytes/sizeof(Atom),
+ False, XA_ATOM,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+ {
+ memcpy( aAtoms.getArray()+atomcount*sizeof(Atom), pBytes, nItems*sizeof(Atom) );
+ XFree( pBytes );
+ }
+ }
+ else
+ {
+ aAtoms.realloc( sizeof(Atom)*nItems );
+ memcpy( aAtoms.getArray(), pBytes, nItems*sizeof(Atom) );
+ XFree( pBytes );
+ }
+ }
+ else
+ {
+ // one to three types
+ int n = 0, i;
+ for( i = 0; i < 3; i++ )
+ if( m_aDropEnterEvent.data.l[2+i] )
+ n++;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "have %d data types in XdndEnter\n", n );
+#endif
+ aAtoms.realloc( sizeof(Atom)*n );
+ for( i = 0, n = 0; i < 3; i++ )
+ if( m_aDropEnterEvent.data.l[2+i] )
+ ((Atom*)aAtoms.getArray())[n++] = m_aDropEnterEvent.data.l[2+i];
+ }
+ }
+ }
+ // get data of type TARGETS
+ else if( ! getPasteData( selection, m_nTARGETSAtom, aAtoms ) )
+ aAtoms = Sequence< sal_Int8 >();
+
+ std::vector< Atom > aNativeTypes;
+ if( aAtoms.getLength() )
+ {
+ sal_Int32 nAtoms = aAtoms.getLength() / sizeof(Atom);
+ Atom* pAtoms = (Atom*)aAtoms.getArray();
+ rTypes.realloc( nAtoms );
+ aNativeTypes.resize( nAtoms );
+ DataFlavor* pFlavors = rTypes.getArray();
+ sal_Int32 nNativeTypesIndex = 0;
+ while( nAtoms-- )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ if( *pAtoms && *pAtoms < 0x01000000 )
+ fprintf( stderr, "native type: %s\n", OUStringToOString( getString( *pAtoms ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ if( *pAtoms == m_nCOMPOUNDAtom )
+ bHaveText = bHaveCompound = true;
+ else if( *pAtoms && *pAtoms < 0x01000000 )
+ {
+ int nFormat;
+ pFlavors->MimeType = convertTypeFromNative( *pAtoms, selection, nFormat );
+ pFlavors->DataType = getCppuType( (Sequence< sal_Int8 >*)0 );
+ sal_Int32 nIndex = 0;
+ if( pFlavors->MimeType.getToken( 0, ';', nIndex ).equalsAsciiL( "text/plain", 10 ) )
+ {
+ OUString aToken(pFlavors->MimeType.getToken( 0, ';', nIndex ));
+ // omit text/plain;charset=unicode since it is not well defined
+ if( aToken.compareToAscii( "charset=unicode" ) == 0 )
+ {
+ pAtoms++;
+ continue;
+ }
+ bHaveText = true;
+ if( aToken.compareToAscii( "charset=utf-16" ) == 0 )
+ {
+ bHaveUTF16 = true;
+ pFlavors->DataType = getCppuType( (OUString*)0 );
+ }
+ else if( aToken.compareToAscii( "charset=utf-8" ) == 0 )
+ {
+ aUTF8Type = *pAtoms;
+ }
+ }
+ pFlavors++;
+ aNativeTypes[ nNativeTypesIndex ] = *pAtoms;
+ nNativeTypesIndex++;
+ }
+ pAtoms++;
+ }
+ if( (pFlavors - rTypes.getArray()) < rTypes.getLength() )
+ rTypes.realloc(pFlavors - rTypes.getArray());
+ bSuccess = rTypes.getLength() ? true : false;
+ if( bHaveText && ! bHaveUTF16 )
+ {
+ int i = 0;
+
+ int nNewFlavors = rTypes.getLength()+1;
+ Sequence< DataFlavor > aTemp( nNewFlavors );
+ for( i = 0; i < nNewFlavors-1; i++ )
+ aTemp.getArray()[i+1] = rTypes.getConstArray()[i];
+ aTemp.getArray()[0].MimeType = OUString(RTL_CONSTASCII_USTRINGPARAM("text/plain;charset=utf-16"));
+ aTemp.getArray()[0].DataType = getCppuType( (OUString*)0 );
+ rTypes = aTemp;
+
+ std::vector< Atom > aNativeTemp( nNewFlavors );
+ for( i = 0; i < nNewFlavors-1; i++ )
+ aNativeTemp[ i + 1 ] = aNativeTypes[ i ];
+ aNativeTemp[0] = None;
+ aNativeTypes = aNativeTemp;
+ }
+ }
+
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ it = m_aSelections.find( selection );
+ if( it != m_aSelections.end() )
+ {
+ if( bSuccess )
+ {
+ it->second->m_aTypes = rTypes;
+ it->second->m_aNativeTypes = aNativeTypes;
+ it->second->m_nLastTimestamp = time( NULL );
+ it->second->m_bHaveUTF16 = bHaveUTF16;
+ it->second->m_aUTF8Type = aUTF8Type;
+ it->second->m_bHaveCompound = bHaveCompound;
+ }
+ else
+ {
+ it->second->m_aTypes = Sequence< DataFlavor >();
+ it->second->m_aNativeTypes = std::vector< Atom >();
+ it->second->m_nLastTimestamp = 0;
+ it->second->m_bHaveUTF16 = false;
+ it->second->m_aUTF8Type = None;
+ it->second->m_bHaveCompound = false;
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ {
+ fprintf( stderr, "SelectionManager::getPasteDataTypes( %s ) = %s\n", OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(), bSuccess ? "true" : "false" );
+ for( int i = 0; i < rTypes.getLength(); i++ )
+ fprintf( stderr, "type: %s\n", OUStringToOString( rTypes.getConstArray()[i].MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ }
+#endif
+
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+PixmapHolder* SelectionManager::getPixmapHolder( Atom selection )
+{
+ boost::unordered_map< Atom, Selection* >::const_iterator it = m_aSelections.find( selection );
+ if( it == m_aSelections.end() )
+ return NULL;
+ if( ! it->second->m_pPixmap )
+ it->second->m_pPixmap = new PixmapHolder( m_pDisplay );
+ return it->second->m_pPixmap;
+}
+
+static sal_Size GetTrueFormatSize(int nFormat)
+{
+ // http://mail.gnome.org/archives/wm-spec-list/2003-March/msg00067.html
+ return nFormat == 32 ? sizeof(long) : nFormat/8;
+}
+
+bool SelectionManager::sendData( SelectionAdaptor* pAdaptor,
+ XLIB_Window requestor,
+ Atom target,
+ Atom property,
+ Atom selection )
+{
+ osl::ResettableMutexGuard aGuard( m_aMutex );
+
+ // handle targets related to image/bmp
+ if( target == XA_COLORMAP || target == XA_PIXMAP || target == XA_BITMAP || target == XA_VISUALID )
+ {
+ PixmapHolder* pPixmap = getPixmapHolder( selection );
+ if( ! pPixmap ) return false;
+ XID nValue = None;
+
+ // handle colormap request
+ if( target == XA_COLORMAP )
+ nValue = (XID)pPixmap->getColormap();
+ else if( target == XA_VISUALID )
+ nValue = (XID)pPixmap->getVisualID();
+ else if( target == XA_PIXMAP || target == XA_BITMAP )
+ {
+ nValue = (XID)pPixmap->getPixmap();
+ if( nValue == None )
+ {
+ // first conversion
+ Sequence< sal_Int8 > aData;
+ int nFormat;
+ aGuard.clear();
+ bool bConverted = convertData( pAdaptor->getTransferable(), target, selection, nFormat, aData );
+ aGuard.reset();
+ if( bConverted )
+ {
+ // get pixmap again since clearing the guard could have invalidated
+ // the pixmap in another thread
+ pPixmap = getPixmapHolder( selection );
+ // conversion succeeded, so aData contains image/bmp now
+ if( pPixmap->needsConversion( (const sal_uInt8*)aData.getConstArray() )
+ && m_xBitmapConverter.is() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "trying bitmap conversion\n" );
+#endif
+ css::uno::Reference<XBitmap> xBM( new BmpTransporter( aData ) );
+ Sequence<Any> aArgs(2), aOutArgs;
+ Sequence<sal_Int16> aOutIndex;
+ aArgs.getArray()[0] = makeAny( xBM );
+ aArgs.getArray()[1] = makeAny( (sal_uInt16)pPixmap->getDepth() );
+ aGuard.clear();
+ try
+ {
+ Any aResult =
+ m_xBitmapConverter->invoke( OUString(RTL_CONSTASCII_USTRINGPARAM("convert-bitmap-depth")),
+ aArgs, aOutIndex, aOutArgs );
+ if( aResult >>= xBM )
+ aData = xBM->getDIB();
+ }
+ catch(...)
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "exception in bitmap converter\n" );
+#endif
+ }
+ aGuard.reset();
+ }
+ // get pixmap again since clearing the guard could have invalidated
+ // the pixmap in another thread
+ pPixmap = getPixmapHolder( selection );
+ nValue = (XID)pPixmap->setBitmapData( (const sal_uInt8*)aData.getConstArray() );
+ }
+ if( nValue == None )
+ return false;
+ }
+ if( target == XA_BITMAP )
+ nValue = (XID)pPixmap->getBitmap();
+ }
+
+ XChangeProperty( m_pDisplay,
+ requestor,
+ property,
+ target,
+ 32,
+ PropModeReplace,
+ (const unsigned char*)&nValue,
+ 1);
+ return true;
+ }
+
+ /*
+ * special target TEXT allows us to transfer
+ * the data in an encoding of our choice
+ * COMPOUND_TEXT will work with most applications
+ */
+ if( target == m_nTEXTAtom )
+ target = m_nCOMPOUNDAtom;
+
+ Sequence< sal_Int8 > aData;
+ int nFormat;
+ aGuard.clear();
+ bool bConverted = convertData( pAdaptor->getTransferable(), target, selection, nFormat, aData );
+ aGuard.reset();
+ if( bConverted )
+ {
+ // conversion succeeded
+ if( aData.getLength() > m_nIncrementalThreshold )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "using INCR protocol\n" );
+ boost::unordered_map< XLIB_Window, boost::unordered_map< Atom, IncrementalTransfer > >::const_iterator win_it = m_aIncrementals.find( requestor );
+ if( win_it != m_aIncrementals.end() )
+ {
+ boost::unordered_map< Atom, IncrementalTransfer >::const_iterator inc_it = win_it->second.find( property );
+ if( inc_it != win_it->second.end() )
+ {
+ const IncrementalTransfer& rInc = inc_it->second;
+ fprintf( stderr, "premature end and new start for INCR transfer for window 0x%lx, property %s, type %s\n",
+ rInc.m_aRequestor,
+ OUStringToOString( getString( rInc.m_aProperty ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( rInc.m_aTarget ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+ }
+ }
+#endif
+
+ // insert IncrementalTransfer
+ IncrementalTransfer& rInc = m_aIncrementals[ requestor ][ property ];
+ rInc.m_aData = aData;
+ rInc.m_nBufferPos = 0;
+ rInc.m_aRequestor = requestor;
+ rInc.m_aProperty = property;
+ rInc.m_aTarget = target;
+ rInc.m_nFormat = nFormat;
+ rInc.m_nTransferStartTime = time( NULL );
+
+ // use incr protocol, signal start to requestor
+ long nMinSize = m_nIncrementalThreshold;
+ XSelectInput( m_pDisplay, requestor, PropertyChangeMask );
+ XChangeProperty( m_pDisplay, requestor, property,
+ m_nINCRAtom, 32, PropModeReplace, (unsigned char*)&nMinSize, 1 );
+ XFlush( m_pDisplay );
+ }
+ else
+ {
+ sal_Size nUnitSize = GetTrueFormatSize(nFormat);
+ XChangeProperty( m_pDisplay,
+ requestor,
+ property,
+ target,
+ nFormat,
+ PropModeReplace,
+ (const unsigned char*)aData.getConstArray(),
+ aData.getLength()/nUnitSize );
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "convertData failed for type: %s \n",
+ OUStringToOString( convertTypeFromNative( target, selection, nFormat ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ return bConverted;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleSelectionRequest( XSelectionRequestEvent& rRequest )
+{
+ osl::ResettableMutexGuard aGuard( m_aMutex );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "handleSelectionRequest for selection %s and target %s\n",
+ OUStringToOString( getString( rRequest.selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( rRequest.target ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+
+ XEvent aNotify;
+
+ aNotify.type = SelectionNotify;
+ aNotify.xselection.display = rRequest.display;
+ aNotify.xselection.send_event = True;
+ aNotify.xselection.requestor = rRequest.requestor;
+ aNotify.xselection.selection = rRequest.selection;
+ aNotify.xselection.time = rRequest.time;
+ aNotify.xselection.target = rRequest.target;
+ aNotify.xselection.property = None;
+
+ SelectionAdaptor* pAdaptor = getAdaptor( rRequest.selection );
+ // ensure that we still own that selection
+ if( pAdaptor &&
+ XGetSelectionOwner( m_pDisplay, rRequest.selection ) == m_aWindow )
+ {
+ css::uno::Reference< XTransferable > xTrans( pAdaptor->getTransferable() );
+ if( rRequest.target == m_nTARGETSAtom )
+ {
+ // someone requests our types
+ if( xTrans.is() )
+ {
+ aGuard.clear();
+ Sequence< DataFlavor > aFlavors = xTrans->getTransferDataFlavors();
+ aGuard.reset();
+
+ ::std::list< Atom > aConversions;
+ getNativeTypeList( aFlavors, aConversions, rRequest.selection );
+
+ int i, nTypes = aConversions.size();
+ Atom* pTypes = (Atom*)alloca( nTypes * sizeof( Atom ) );
+ std::list< Atom >::const_iterator it;
+ for( i = 0, it = aConversions.begin(); i < nTypes; i++, ++it )
+ pTypes[i] = *it;
+ XChangeProperty( m_pDisplay, rRequest.requestor, rRequest.property,
+ XA_ATOM, 32, PropModeReplace, (const unsigned char*)pTypes, nTypes );
+ aNotify.xselection.property = rRequest.property;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "sending type list:\n" );
+ for( int k = 0; k < nTypes; k++ )
+ fprintf( stderr, " %s\n", pTypes[k] ? XGetAtomName( m_pDisplay, pTypes[k] ) : "<None>" );
+#endif
+ }
+ }
+ else if( rRequest.target == m_nTIMESTAMPAtom )
+ {
+ long nTimeStamp = (long)m_aSelections[rRequest.selection]->m_nOrigTimestamp;
+ XChangeProperty( m_pDisplay, rRequest.requestor, rRequest.property,
+ XA_INTEGER, 32, PropModeReplace, (const unsigned char*)&nTimeStamp, 1 );
+ aNotify.xselection.property = rRequest.property;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "sending timestamp: %d\n", (int)nTimeStamp );
+#endif
+ }
+ else
+ {
+ bool bEventSuccess = false;
+ if( rRequest.target == m_nMULTIPLEAtom )
+ {
+ // get all targets
+ Atom nType = None;
+ int nFormat = 0;
+ unsigned long nItems = 0, nBytes = 0;
+ unsigned char* pData = NULL;
+
+ // get number of atoms
+ XGetWindowProperty( m_pDisplay,
+ rRequest.requestor,
+ rRequest.property,
+ 0, 0,
+ False,
+ AnyPropertyType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+ if( nFormat == 32 && nBytes/4 )
+ {
+ if( pData ) // ?? should not happen
+ {
+ XFree( pData );
+ pData = NULL;
+ }
+ XGetWindowProperty( m_pDisplay,
+ rRequest.requestor,
+ rRequest.property,
+ 0, nBytes/4,
+ False,
+ nType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+ if( pData && nItems )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %ld atoms in MULTIPLE request\n", nItems );
+#endif
+ bEventSuccess = true;
+ bool bResetAtoms = false;
+ Atom* pAtoms = (Atom*)pData;
+ aGuard.clear();
+ for( unsigned int i = 0; i < nItems; i += 2 )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, " %s => %s: ",
+ OUStringToOString( getString( pAtoms[i] ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( pAtoms[i+1] ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ bool bSuccess = sendData( pAdaptor, rRequest.requestor, pAtoms[i], pAtoms[i+1], rRequest.selection );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s\n", bSuccess ? "succeeded" : "failed" );
+#endif
+ if( ! bSuccess )
+ {
+ pAtoms[i] = None;
+ bResetAtoms = true;
+ }
+ }
+ aGuard.reset();
+ if( bResetAtoms )
+ XChangeProperty( m_pDisplay,
+ rRequest.requestor,
+ rRequest.property,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ pData,
+ nBytes/4 );
+ }
+ if( pData )
+ XFree( pData );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ {
+ fprintf( stderr, "could not get type list from \"%s\" of type \"%s\" on requestor 0x%lx, requestor has properties:",
+ OUStringToOString( getString( rRequest.property ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( nType ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ rRequest.requestor );
+ int nProps = 0;
+ Atom* pProps = XListProperties( m_pDisplay, rRequest.requestor, &nProps );
+ if( pProps )
+ {
+ for( int i = 0; i < nProps; i++ )
+ fprintf( stderr, " \"%s\"", OUStringToOString( getString( pProps[i]), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ XFree( pProps );
+ }
+ }
+#endif
+ }
+ else
+ {
+ aGuard.clear();
+ bEventSuccess = sendData( pAdaptor, rRequest.requestor, rRequest.target, rRequest.property, rRequest.selection );
+ aGuard.reset();
+ }
+ if( bEventSuccess )
+ {
+ aNotify.xselection.target = rRequest.target;
+ aNotify.xselection.property = rRequest.property;
+ }
+ }
+ aGuard.clear();
+ xTrans.clear();
+ aGuard.reset();
+ }
+ XSendEvent( m_pDisplay, rRequest.requestor, False, 0, &aNotify );
+
+ if( rRequest.selection == XA_PRIMARY &&
+ m_bWaitingForPrimaryConversion &&
+ m_xDragSourceListener.is() )
+ {
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, rRequest.time, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ if( aNotify.xselection.property != None )
+ {
+ dsde.DropAction = DNDConstants::ACTION_COPY;
+ dsde.DropSuccess = sal_True;
+ }
+ else
+ {
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ }
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ if( xListener.is() )
+ xListener->dragDropEnd( dsde );
+ }
+
+ // we handled the event in any case by answering
+ return true;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleReceivePropertyNotify( XPropertyEvent& rNotify )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+ // data we requested arrived
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "handleReceivePropertyNotify for property %s\n",
+ OUStringToOString( getString( rNotify.atom ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ bool bHandled = false;
+
+ ::boost::unordered_map< Atom, Selection* >::iterator it =
+ m_aSelections.find( rNotify.atom );
+ if( it != m_aSelections.end() &&
+ rNotify.state == PropertyNewValue &&
+ ( it->second->m_eState == Selection::WaitingForResponse ||
+ it->second->m_eState == Selection::WaitingForData ||
+ it->second->m_eState == Selection::IncrementalTransfer
+ )
+ )
+ {
+ // MULTIPLE requests are only complete after selection notify
+ if( it->second->m_aRequestedType == m_nMULTIPLEAtom &&
+ ( it->second->m_eState == Selection::WaitingForResponse ||
+ it->second->m_eState == Selection::WaitingForData ) )
+ return false;
+
+ bHandled = true;
+
+ Atom nType = None;
+ int nFormat = 0;
+ unsigned long nItems = 0, nBytes = 0;
+ unsigned char* pData = NULL;
+
+ // get type and length
+ XGetWindowProperty( m_pDisplay,
+ rNotify.window,
+ rNotify.atom,
+ 0, 0,
+ False,
+ AnyPropertyType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %ld bytes data of type %s and format %d, items = %ld\n",
+ nBytes,
+ OUStringToOString( getString( nType ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ nFormat, nItems );
+#endif
+ if( pData )
+ {
+ XFree( pData );
+ pData = NULL;
+ }
+
+ if( nType == m_nINCRAtom )
+ {
+ // start data transfer
+ XDeleteProperty( m_pDisplay, rNotify.window, rNotify.atom );
+ it->second->m_eState = Selection::IncrementalTransfer;
+ }
+ else if( nType != None )
+ {
+ XGetWindowProperty( m_pDisplay,
+ rNotify.window,
+ rNotify.atom,
+ 0, nBytes/4 +1,
+ True,
+ nType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "read %ld items data of type %s and format %d, %ld bytes left in property\n",
+ nItems,
+ OUStringToOString( getString( nType ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ nFormat, nBytes );
+#endif
+
+ sal_Size nUnitSize = GetTrueFormatSize(nFormat);
+
+ if( it->second->m_eState == Selection::WaitingForData ||
+ it->second->m_eState == Selection::WaitingForResponse )
+ {
+ // copy data
+ it->second->m_aData = Sequence< sal_Int8 >( (sal_Int8*)pData, nItems*nUnitSize );
+ it->second->m_eState = Selection::Inactive;
+ it->second->m_aDataArrived.set();
+ }
+ else if( it->second->m_eState == Selection::IncrementalTransfer )
+ {
+ if( nItems )
+ {
+ // append data
+ Sequence< sal_Int8 > aData( it->second->m_aData.getLength() + nItems*nUnitSize );
+ memcpy( aData.getArray(), it->second->m_aData.getArray(), it->second->m_aData.getLength() );
+ memcpy( aData.getArray() + it->second->m_aData.getLength(), pData, nItems*nUnitSize );
+ it->second->m_aData = aData;
+ }
+ else
+ {
+ it->second->m_eState = Selection::Inactive;
+ it->second->m_aDataArrived.set();
+ }
+ }
+ if( pData )
+ XFree( pData );
+ }
+ else if( it->second->m_eState == Selection::IncrementalTransfer )
+ {
+ it->second->m_eState = Selection::Inactive;
+ it->second->m_aDataArrived.set();
+ }
+ }
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleSendPropertyNotify( XPropertyEvent& rNotify )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ // ready for next part of a IncrementalTransfer
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "handleSendPropertyNotify for property %s (%s)\n",
+ OUStringToOString( getString( rNotify.atom ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ rNotify.state == PropertyNewValue ? "new value" : ( rNotify.state == PropertyDelete ? "deleted" : "unknown")
+ );
+#endif
+
+ bool bHandled = false;
+ // feed incrementals
+ if( rNotify.state == PropertyDelete )
+ {
+ boost::unordered_map< XLIB_Window, boost::unordered_map< Atom, IncrementalTransfer > >::iterator it;
+ it = m_aIncrementals.find( rNotify.window );
+ if( it != m_aIncrementals.end() )
+ {
+ bHandled = true;
+ int nCurrentTime = time( NULL );
+ boost::unordered_map< Atom, IncrementalTransfer >::iterator inc_it;
+ // throw out aborted transfers
+ std::list< Atom > aTimeouts;
+ for( inc_it = it->second.begin(); inc_it != it->second.end(); ++inc_it )
+ {
+ if( (nCurrentTime - inc_it->second.m_nTransferStartTime) > (getSelectionTimeout()+2) )
+ {
+ aTimeouts.push_back( inc_it->first );
+#if OSL_DEBUG_LEVEL > 1
+ const IncrementalTransfer& rInc = inc_it->second;
+ fprintf( stderr, "timeout on INCR transfer for window 0x%lx, property %s, type %s\n",
+ rInc.m_aRequestor,
+ OUStringToOString( getString( rInc.m_aProperty ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( rInc.m_aTarget ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+ }
+ }
+
+ while( aTimeouts.begin() != aTimeouts.end() )
+ {
+ // transfer broken, might even be a new client with the
+ // same window id
+ it->second.erase( aTimeouts.front() );
+ aTimeouts.pop_front();
+ }
+
+ inc_it = it->second.find( rNotify.atom );
+ if( inc_it != it->second.end() )
+ {
+ IncrementalTransfer& rInc = inc_it->second;
+
+ int nBytes = rInc.m_aData.getLength() - rInc.m_nBufferPos;
+ nBytes = (nBytes > m_nIncrementalThreshold) ? m_nIncrementalThreshold : nBytes;
+ if( nBytes < 0 ) // sanity check
+ nBytes = 0;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "pushing %d bytes: \"%.*s\"...\n",
+ nBytes, nBytes > 32 ? 32 : nBytes,
+ (const unsigned char*)rInc.m_aData.getConstArray()+rInc.m_nBufferPos );
+#endif
+
+ sal_Size nUnitSize = GetTrueFormatSize(rInc.m_nFormat);
+
+ XChangeProperty( m_pDisplay,
+ rInc.m_aRequestor,
+ rInc.m_aProperty,
+ rInc.m_aTarget,
+ rInc.m_nFormat,
+ PropModeReplace,
+ (const unsigned char*)rInc.m_aData.getConstArray()+rInc.m_nBufferPos,
+ nBytes/nUnitSize );
+ rInc.m_nBufferPos += nBytes;
+ rInc.m_nTransferStartTime = nCurrentTime;
+
+ if( nBytes == 0 ) // transfer finished
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "finished INCR transfer for window 0x%lx, property %s, type %s\n",
+ rInc.m_aRequestor,
+ OUStringToOString( getString( rInc.m_aProperty ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( rInc.m_aTarget ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+ it->second.erase( inc_it );
+ }
+
+ }
+ // eventually clean up the hash map
+ if( it->second.begin() == it->second.end() )
+ m_aIncrementals.erase( it );
+ }
+ }
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleSelectionNotify( XSelectionEvent& rNotify )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ bool bHandled = false;
+
+ // notification about success/failure of one of our conversion requests
+#if OSL_DEBUG_LEVEL > 1
+ OUString aSelection( getString( rNotify.selection ) );
+ OUString aProperty(RTL_CONSTASCII_USTRINGPARAM("None"));
+ if( rNotify.property )
+ aProperty = getString( rNotify.property );
+ fprintf( stderr, "handleSelectionNotify for selection %s and property %s (0x%lx)\n",
+ OUStringToOString( aSelection, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( aProperty, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ rNotify.property
+ );
+ if( rNotify.requestor != m_aWindow && rNotify.requestor != m_aCurrentDropWindow )
+ fprintf( stderr, "Warning: selection notify for unknown window 0x%lx\n", rNotify.requestor );
+#endif
+ ::boost::unordered_map< Atom, Selection* >::iterator it =
+ m_aSelections.find( rNotify.selection );
+ if (
+ (rNotify.requestor == m_aWindow || rNotify.requestor == m_aCurrentDropWindow) &&
+ it != m_aSelections.end() &&
+ (
+ (it->second->m_eState == Selection::WaitingForResponse) ||
+ (it->second->m_eState == Selection::WaitingForData)
+ )
+ )
+ {
+ bHandled = true;
+ if( it->second->m_aRequestedType == m_nMULTIPLEAtom )
+ {
+ Atom nType = None;
+ int nFormat = 0;
+ unsigned long nItems = 0, nBytes = 0;
+ unsigned char* pData = NULL;
+
+ // get type and length
+ XGetWindowProperty( m_pDisplay,
+ rNotify.requestor,
+ rNotify.property,
+ 0, 256,
+ False,
+ AnyPropertyType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+ if( nBytes ) // HUGE request !!!
+ {
+ if( pData )
+ XFree( pData );
+ XGetWindowProperty( m_pDisplay,
+ rNotify.requestor,
+ rNotify.property,
+ 0, 256+(nBytes+3)/4,
+ False,
+ AnyPropertyType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+ }
+ it->second->m_eState = Selection::Inactive;
+ sal_Size nUnitSize = GetTrueFormatSize(nFormat);
+ it->second->m_aData = Sequence< sal_Int8 >((sal_Int8*)pData, nItems * nUnitSize);
+ it->second->m_aDataArrived.set();
+ if( pData )
+ XFree( pData );
+ }
+ // WaitingForData can actually happen; some
+ // applications (e.g. cmdtool on Solaris) first send
+ // a success and then cancel it. Weird !
+ else if( rNotify.property == None )
+ {
+ // conversion failed, stop transfer
+ it->second->m_eState = Selection::Inactive;
+ it->second->m_aData = Sequence< sal_Int8 >();
+ it->second->m_aDataArrived.set();
+ }
+ // get the bytes, by INCR if necessary
+ else
+ it->second->m_eState = Selection::WaitingForData;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else if( it != m_aSelections.end() )
+ fprintf( stderr, "Warning: selection in state %d\n", it->second->m_eState );
+#endif
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleDropEvent( XClientMessageEvent& rMessage )
+{
+ osl::ResettableMutexGuard aGuard(m_aMutex);
+
+ // handle drop related events
+ XLIB_Window aSource = rMessage.data.l[0];
+ XLIB_Window aTarget = rMessage.window;
+
+ bool bHandled = false;
+
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >::iterator it =
+ m_aDropTargets.find( aTarget );
+
+#if OSL_DEBUG_LEVEL > 1
+ if( rMessage.message_type == m_nXdndEnter ||
+ rMessage.message_type == m_nXdndLeave ||
+ rMessage.message_type == m_nXdndDrop ||
+ rMessage.message_type == m_nXdndPosition )
+ {
+ fprintf( stderr, "got drop event %s, ", OUStringToOString( getString( rMessage.message_type ), RTL_TEXTENCODING_ASCII_US).getStr() );
+ if( it == m_aDropTargets.end() )
+ fprintf( stderr, "but no target found\n" );
+ else if( ! it->second.m_pTarget->m_bActive )
+ fprintf( stderr, "but target is inactive\n" );
+ else if( m_aDropEnterEvent.data.l[0] != None && (XLIB_Window)m_aDropEnterEvent.data.l[0] != aSource )
+ fprintf( stderr, "but source 0x%lx is unknown (expected 0x%lx or 0)\n", aSource, m_aDropEnterEvent.data.l[0] );
+ else
+ fprintf( stderr, "processing.\n" );
+ }
+#endif
+
+ if( it != m_aDropTargets.end() && it->second.m_pTarget->m_bActive &&
+ m_bDropWaitingForCompletion && m_aDropEnterEvent.data.l[0] )
+ {
+ bHandled = true;
+ OSL_FAIL( "someone forgot to call dropComplete ?" );
+ // some listener forgot to call dropComplete in the last operation
+ // let us end it now and accept the new enter event
+ aGuard.clear();
+ dropComplete( sal_False, m_aCurrentDropWindow, m_nDropTime );
+ aGuard.reset();
+ }
+
+ if( it != m_aDropTargets.end() &&
+ it->second.m_pTarget->m_bActive &&
+ ( m_aDropEnterEvent.data.l[0] == None || XLIB_Window(m_aDropEnterEvent.data.l[0]) == aSource )
+ )
+ {
+ if( rMessage.message_type == m_nXdndEnter )
+ {
+ bHandled = true;
+ m_aDropEnterEvent = rMessage;
+ m_bDropEnterSent = false;
+ m_aCurrentDropWindow = aTarget;
+ m_nCurrentProtocolVersion = m_aDropEnterEvent.data.l[1] >> 24;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "received XdndEnter on 0x%lx\n", aTarget );
+#endif
+ }
+ else if(
+ rMessage.message_type == m_nXdndPosition &&
+ aSource == XLIB_Window(m_aDropEnterEvent.data.l[0])
+ )
+ {
+ bHandled = true;
+ m_nDropTime = m_nCurrentProtocolVersion > 0 ? rMessage.data.l[3] : CurrentTime;
+ if( ! m_bDropEnterSent )
+ m_nDropTimestamp = m_nDropTime;
+
+ XLIB_Window aChild;
+ XTranslateCoordinates( m_pDisplay,
+ it->second.m_aRootWindow,
+ it->first,
+ rMessage.data.l[2] >> 16,
+ rMessage.data.l[2] & 0xffff,
+ &m_nLastX, &m_nLastY,
+ &aChild );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "received XdndPosition on 0x%lx (%d, %d)\n", aTarget, m_nLastX, m_nLastY );
+#endif
+ DropTargetDragEnterEvent aEvent;
+ aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
+ aEvent.Context = new DropTargetDragContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ aEvent.LocationX = m_nLastX;
+ aEvent.LocationY = m_nLastY;
+ aEvent.SourceActions = m_nSourceActions;
+ if( m_nCurrentProtocolVersion < 2 )
+ aEvent.DropAction = DNDConstants::ACTION_COPY;
+ else if( Atom(rMessage.data.l[4]) == m_nXdndActionCopy )
+ aEvent.DropAction = DNDConstants::ACTION_COPY;
+ else if( Atom(rMessage.data.l[4]) == m_nXdndActionMove )
+ aEvent.DropAction = DNDConstants::ACTION_MOVE;
+ else if( Atom(rMessage.data.l[4]) == m_nXdndActionLink )
+ aEvent.DropAction = DNDConstants::ACTION_LINK;
+ else if( Atom(rMessage.data.l[4]) == m_nXdndActionAsk )
+ // currently no interface to implement ask
+ aEvent.DropAction = ~0;
+ else
+ aEvent.DropAction = DNDConstants::ACTION_NONE;
+
+ m_nLastDropAction = aEvent.DropAction;
+ if( ! m_bDropEnterSent )
+ {
+ m_bDropEnterSent = true;
+ aEvent.SupportedDataFlavors = m_xDropTransferable->getTransferDataFlavors();
+ aGuard.clear();
+ it->second->dragEnter( aEvent );
+ }
+ else
+ {
+ aGuard.clear();
+ it->second->dragOver( aEvent );
+ }
+ }
+ else if(
+ rMessage.message_type == m_nXdndLeave &&
+ aSource == XLIB_Window(m_aDropEnterEvent.data.l[0])
+ )
+ {
+ bHandled = true;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "received XdndLeave on 0x%lx\n", aTarget );
+#endif
+ DropTargetEvent aEvent;
+ aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
+ m_aDropEnterEvent.data.l[0] = None;
+ if( m_aCurrentDropWindow == aTarget )
+ m_aCurrentDropWindow = None;
+ m_nCurrentProtocolVersion = nXdndProtocolRevision;
+ aGuard.clear();
+ it->second->dragExit( aEvent );
+ }
+ else if(
+ rMessage.message_type == m_nXdndDrop &&
+ aSource == XLIB_Window(m_aDropEnterEvent.data.l[0])
+ )
+ {
+ bHandled = true;
+ m_nDropTime = m_nCurrentProtocolVersion > 0 ? rMessage.data.l[2] : CurrentTime;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "received XdndDrop on 0x%lx (%d, %d)\n", aTarget, m_nLastX, m_nLastY );
+#endif
+ if( m_bLastDropAccepted )
+ {
+ DropTargetDropEvent aEvent;
+ aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
+ aEvent.Context = new DropTargetDropContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ aEvent.LocationX = m_nLastX;
+ aEvent.LocationY = m_nLastY;
+ aEvent.DropAction = m_nLastDropAction;
+ // there is nothing corresponding to source supported actions
+ // every source can do link, copy and move
+ aEvent.SourceActions= m_nLastDropAction;
+ aEvent.Transferable = m_xDropTransferable;
+
+ m_bDropWaitingForCompletion = true;
+ aGuard.clear();
+ it->second->drop( aEvent );
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "XdndDrop canceled due to m_bLastDropAccepted = fale\n" );
+#endif
+ DropTargetEvent aEvent;
+ aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
+ aGuard.clear();
+ it->second->dragExit( aEvent );
+ // reset the drop status, notify source
+ dropComplete( sal_False, m_aCurrentDropWindow, m_nDropTime );
+ }
+ }
+ }
+ return bHandled;
+}
+
+/*
+ * methods for XDropTargetDropContext
+ */
+
+void SelectionManager::dropComplete( sal_Bool bSuccess, XLIB_Window aDropWindow, XLIB_Time )
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ if( aDropWindow == m_aCurrentDropWindow )
+ {
+ if( m_xDragSourceListener.is() )
+ {
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = getUserDragAction();
+ dsde.DropSuccess = bSuccess;
+ css::uno::Reference< XDragSourceListener > xListener = m_xDragSourceListener;
+ m_xDragSourceListener.clear();
+
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ }
+ else if( m_aDropEnterEvent.data.l[0] && m_aCurrentDropWindow )
+ {
+ XEvent aEvent;
+ aEvent.xclient.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = m_aDropEnterEvent.data.l[0];
+ aEvent.xclient.message_type = m_nXdndFinished;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = m_aCurrentDropWindow;
+ aEvent.xclient.data.l[1] = bSuccess ? 1 : 0;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ if( bSuccess )
+ {
+ if( m_nLastDropAction & DNDConstants::ACTION_MOVE )
+ aEvent.xclient.data.l[2] = m_nXdndActionMove;
+ else if( m_nLastDropAction & DNDConstants::ACTION_COPY )
+ aEvent.xclient.data.l[2] = m_nXdndActionCopy;
+ else if( m_nLastDropAction & DNDConstants::ACTION_LINK )
+ aEvent.xclient.data.l[2] = m_nXdndActionLink;
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Sending XdndFinished to 0x%lx\n",
+ m_aDropEnterEvent.data.l[0]
+ );
+#endif
+
+ XSendEvent( m_pDisplay, m_aDropEnterEvent.data.l[0],
+ False, NoEventMask, & aEvent );
+
+ m_aDropEnterEvent.data.l[0] = None;
+ m_aCurrentDropWindow = None;
+ m_nCurrentProtocolVersion = nXdndProtocolRevision;
+ }
+ m_bDropWaitingForCompletion = false;
+ }
+ else
+ OSL_FAIL( "dropComplete from invalid DropTargetDropContext" );
+}
+
+/*
+ * methods for XDropTargetDragContext
+ */
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::sendDragStatus( Atom nDropAction )
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ if( m_xDragSourceListener.is() )
+ {
+ sal_Int8 nNewDragAction;
+ if( nDropAction == m_nXdndActionMove )
+ nNewDragAction = DNDConstants::ACTION_MOVE;
+ else if( nDropAction == m_nXdndActionCopy )
+ nNewDragAction = DNDConstants::ACTION_COPY;
+ else if( nDropAction == m_nXdndActionLink )
+ nNewDragAction = DNDConstants::ACTION_LINK;
+ else
+ nNewDragAction = DNDConstants::ACTION_NONE;
+ nNewDragAction &= m_nSourceActions;
+
+ if( nNewDragAction != m_nTargetAcceptAction )
+ {
+ setCursor( getDefaultCursor( nNewDragAction ), m_aDropWindow, m_nDragTimestamp );
+ m_nTargetAcceptAction = nNewDragAction;
+ }
+
+ DragSourceDragEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = m_nSourceActions;
+ dsde.UserAction = getUserDragAction();
+
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ // caution: do not change anything after this
+ aGuard.clear();
+ if( xListener.is() )
+ xListener->dragOver( dsde );
+ }
+ else if( m_aDropEnterEvent.data.l[0] && m_aCurrentDropWindow )
+ {
+ XEvent aEvent;
+ aEvent.xclient.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = m_aDropEnterEvent.data.l[0];
+ aEvent.xclient.message_type = m_nXdndStatus;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = m_aCurrentDropWindow;
+ aEvent.xclient.data.l[1] = 2;
+ if( nDropAction == m_nXdndActionMove ||
+ nDropAction == m_nXdndActionLink ||
+ nDropAction == m_nXdndActionCopy )
+ aEvent.xclient.data.l[1] |= 1;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = m_nCurrentProtocolVersion > 1 ? nDropAction : 0;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Sending XdndStatus to 0x%lx with action %s\n",
+ m_aDropEnterEvent.data.l[0],
+ OUStringToOString( getString( nDropAction ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+
+ XSendEvent( m_pDisplay, m_aDropEnterEvent.data.l[0],
+ False, NoEventMask, & aEvent );
+ XFlush( m_pDisplay );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+sal_Int8 SelectionManager::getUserDragAction() const
+{
+ return (m_nTargetAcceptAction != DNDConstants::ACTION_DEFAULT) ? m_nTargetAcceptAction : m_nUserDragAction;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::updateDragAction( int modifierState )
+{
+ bool bRet = false;
+
+ sal_Int8 nNewDropAction = DNDConstants::ACTION_MOVE;
+ if( ( modifierState & ShiftMask ) && ! ( modifierState & ControlMask ) )
+ nNewDropAction = DNDConstants::ACTION_MOVE;
+ else if( ( modifierState & ControlMask ) && ! ( modifierState & ShiftMask ) )
+ nNewDropAction = DNDConstants::ACTION_COPY;
+ else if( ( modifierState & ShiftMask ) && ( modifierState & ControlMask ) )
+ nNewDropAction = DNDConstants::ACTION_LINK;
+ if( m_nCurrentProtocolVersion < 0 && m_aDropWindow != None )
+ nNewDropAction = DNDConstants::ACTION_COPY;
+ nNewDropAction &= m_nSourceActions;
+
+ if( ! ( modifierState & ( ControlMask | ShiftMask ) ) )
+ {
+ if( ! nNewDropAction )
+ {
+ // default to an action so the user does not have to press
+ // keys explicitly
+ if( m_nSourceActions & DNDConstants::ACTION_MOVE )
+ nNewDropAction = DNDConstants::ACTION_MOVE;
+ else if( m_nSourceActions & DNDConstants::ACTION_COPY )
+ nNewDropAction = DNDConstants::ACTION_COPY;
+ else if( m_nSourceActions & DNDConstants::ACTION_LINK )
+ nNewDropAction = DNDConstants::ACTION_LINK;
+ }
+ nNewDropAction |= DNDConstants::ACTION_DEFAULT;
+ }
+
+ if( nNewDropAction != m_nUserDragAction || m_nTargetAcceptAction != DNDConstants::ACTION_DEFAULT )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "updateDragAction: %x -> %x\n", (int)m_nUserDragAction, (int)nNewDropAction );
+#endif
+ bRet = true;
+ m_nUserDragAction = nNewDropAction;
+
+ DragSourceDragEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = m_nUserDragAction;
+ dsde.UserAction = m_nUserDragAction;
+ m_nTargetAcceptAction = DNDConstants::ACTION_DEFAULT; // invalidate last accept
+ m_xDragSourceListener->dropActionChanged( dsde );
+ }
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::sendDropPosition( bool bForce, XLIB_Time eventTime )
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ if( m_bDropSent )
+ return;
+
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >::const_iterator it =
+ m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() )
+ {
+ if( it->second.m_pTarget->m_bActive )
+ {
+ int x, y;
+ XLIB_Window aChild;
+ XTranslateCoordinates( m_pDisplay, it->second.m_aRootWindow, m_aDropWindow, m_nLastDragX, m_nLastDragY, &x, &y, &aChild );
+ DropTargetDragEvent dtde;
+ dtde.Source = static_cast< OWeakObject* >(it->second.m_pTarget );
+ dtde.Context = new DropTargetDragContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ dtde.LocationX = x;
+ dtde.LocationY = y;
+ dtde.DropAction = getUserDragAction();
+ dtde.SourceActions = m_nSourceActions;
+ aGuard.clear();
+ it->second->dragOver( dtde );
+ }
+ }
+ else if( bForce ||
+
+ m_nLastDragX < m_nNoPosX || m_nLastDragX >= m_nNoPosX+m_nNoPosWidth ||
+ m_nLastDragY < m_nNoPosY || m_nLastDragY >= m_nNoPosY+m_nNoPosHeight
+ )
+ {
+ // send XdndPosition
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndPosition;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ aEvent.xclient.data.l[1] = 0;
+ aEvent.xclient.data.l[2] = m_nLastDragX << 16 | (m_nLastDragY&0xffff);
+ aEvent.xclient.data.l[3] = eventTime;
+
+ if( m_nUserDragAction & DNDConstants::ACTION_COPY )
+ aEvent.xclient.data.l[4]=m_nXdndActionCopy;
+ else if( m_nUserDragAction & DNDConstants::ACTION_MOVE )
+ aEvent.xclient.data.l[4]=m_nXdndActionMove;
+ else if( m_nUserDragAction & DNDConstants::ACTION_LINK )
+ aEvent.xclient.data.l[4]=m_nXdndActionLink;
+ else
+ aEvent.xclient.data.l[4]=m_nXdndActionCopy;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ m_nNoPosX = m_nNoPosY = m_nNoPosWidth = m_nNoPosHeight = 0;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleDragEvent( XEvent& rMessage )
+{
+ if( ! m_xDragSourceListener.is() )
+ return false;
+
+ osl::ResettableMutexGuard aGuard(m_aMutex);
+
+ bool bHandled = false;
+
+ // for shortcut
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >::const_iterator it =
+ m_aDropTargets.find( m_aDropWindow );
+#if OSL_DEBUG_LEVEL > 1
+ switch( rMessage.type )
+ {
+ case ClientMessage:
+ fprintf( stderr, "handleDragEvent: %s\n", OUStringToOString( getString( rMessage.xclient.message_type ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ break;
+ case MotionNotify:
+ break;
+ case EnterNotify:
+ fprintf( stderr, "handleDragEvent: EnterNotify\n" );
+ break;
+ case LeaveNotify:
+ fprintf( stderr, "handleDragEvent: LeaveNotify\n" );
+ break;
+ case ButtonPress:
+ fprintf( stderr, "handleDragEvent: ButtonPress %d (m_nDragButton = %d)\n", rMessage.xbutton.button, m_nDragButton );
+ break;
+ case ButtonRelease:
+ fprintf( stderr, "handleDragEvent: ButtonRelease %d (m_nDragButton = %d)\n", rMessage.xbutton.button, m_nDragButton );
+ break;
+ case XLIB_KeyPress:
+ fprintf( stderr, "handleDragEvent: KeyPress\n" );
+ break;
+ case KeyRelease:
+ fprintf( stderr, "handleDragEvent: KeyRelease\n" );
+ break;
+ default:
+ fprintf( stderr, "handleDragEvent: <unknown type %d>\n", rMessage.type );
+ break;
+ }
+#endif
+
+ // handle drag related events
+ if( rMessage.type == ClientMessage )
+ {
+ if( Atom(rMessage.xclient.message_type) == m_nXdndStatus && Atom(rMessage.xclient.data.l[0]) == m_aDropWindow )
+ {
+ bHandled = true;
+ DragSourceDragEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >( this );
+ dsde.UserAction = getUserDragAction();
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ m_bDropSuccess = rMessage.xclient.data.l[1] & 1 ? true : false;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "status drop action: accept = %s, %s\n",
+ m_bDropSuccess ? "true" : "false",
+ OUStringToOString( getString( rMessage.xclient.data.l[4] ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ if( rMessage.xclient.data.l[1] & 1 )
+ {
+ if( m_nCurrentProtocolVersion > 1 )
+ {
+ if( Atom(rMessage.xclient.data.l[4]) == m_nXdndActionCopy )
+ dsde.DropAction = DNDConstants::ACTION_COPY;
+ else if( Atom(rMessage.xclient.data.l[4]) == m_nXdndActionMove )
+ dsde.DropAction = DNDConstants::ACTION_MOVE;
+ else if( Atom(rMessage.xclient.data.l[4]) == m_nXdndActionLink )
+ dsde.DropAction = DNDConstants::ACTION_LINK;
+ }
+ else
+ dsde.DropAction = DNDConstants::ACTION_COPY;
+ }
+ m_nTargetAcceptAction = dsde.DropAction;
+
+ if( ! ( rMessage.xclient.data.l[1] & 2 ) )
+ {
+ m_nNoPosX = rMessage.xclient.data.l[2] >> 16;
+ m_nNoPosY = rMessage.xclient.data.l[2] & 0xffff;
+ m_nNoPosWidth = rMessage.xclient.data.l[3] >> 16;
+ m_nNoPosHeight = rMessage.xclient.data.l[3] & 0xffff;
+ }
+ else
+ m_nNoPosX = m_nNoPosY = m_nNoPosWidth = m_nNoPosHeight = 0;
+
+ setCursor( getDefaultCursor( dsde.DropAction ), m_aDropWindow, m_nDragTimestamp );
+ aGuard.clear();
+ m_xDragSourceListener->dragOver( dsde );
+ }
+ else if( Atom(rMessage.xclient.message_type) == m_nXdndFinished && m_aDropWindow == Atom(rMessage.xclient.data.l[0]) )
+ {
+ bHandled = true;
+ // notify the listener
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = m_nTargetAcceptAction;
+ dsde.DropSuccess = m_bDropSuccess;
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ }
+ }
+ else if( rMessage.type == MotionNotify ||
+ rMessage.type == EnterNotify || rMessage.type == LeaveNotify
+ )
+ {
+ bHandled = true;
+ bool bForce = false;
+ int root_x = rMessage.type == MotionNotify ? rMessage.xmotion.x_root : rMessage.xcrossing.x_root;
+ int root_y = rMessage.type == MotionNotify ? rMessage.xmotion.y_root : rMessage.xcrossing.y_root;
+ XLIB_Window root = rMessage.type == MotionNotify ? rMessage.xmotion.root : rMessage.xcrossing.root;
+ m_nDragTimestamp = rMessage.type == MotionNotify ? rMessage.xmotion.time : rMessage.xcrossing.time;
+
+ aGuard.clear();
+ if( rMessage.type == MotionNotify )
+ {
+ bForce = updateDragAction( rMessage.xmotion.state );
+ }
+ updateDragWindow( root_x, root_y, root );
+ aGuard.reset();
+
+ if( m_nCurrentProtocolVersion >= 0 && m_aDropProxy != None )
+ {
+ aGuard.clear();
+ sendDropPosition( bForce, rMessage.type == MotionNotify ? rMessage.xmotion.time : rMessage.xcrossing.time );
+ }
+ }
+ else if( rMessage.type == XLIB_KeyPress || rMessage.type == KeyRelease )
+ {
+ bHandled = true;
+ KeySym aKey = XKeycodeToKeysym( m_pDisplay, rMessage.xkey.keycode, 0 );
+ if( aKey == XK_Escape )
+ {
+ // abort drag
+ if( it != m_aDropTargets.end() )
+ {
+ DropTargetEvent dte;
+ dte.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
+ aGuard.clear();
+ it->second.m_pTarget->dragExit( dte );
+ }
+ else if( m_aDropProxy != None && m_nCurrentProtocolVersion >= 0 )
+ {
+ // send XdndLeave
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndLeave;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ memset( aEvent.xclient.data.l+1, 0, sizeof(long)*4);
+ m_aDropWindow = m_aDropProxy = None;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+ // notify the listener
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ }
+ else
+ {
+ /*
+ * man page says: state is state immediate PRIOR to the
+ * event. It would seem that this is a somewhat arguable
+ * design decision.
+ */
+ int nState = rMessage.xkey.state;
+ int nNewState = 0;
+ switch( aKey )
+ {
+ case XK_Shift_R:
+ case XK_Shift_L: nNewState = ShiftMask;break;
+ case XK_Control_R:
+ case XK_Control_L: nNewState = ControlMask;break;
+ // just interested in shift and ctrl for dnd
+ }
+ if( rMessage.type == XLIB_KeyPress )
+ nState |= nNewState;
+ else
+ nState &= ~nNewState;
+ aGuard.clear();
+ if( updateDragAction( nState ) )
+ sendDropPosition( true, rMessage.xkey.time );
+ }
+ }
+ else if(
+ ( rMessage.type == ButtonPress || rMessage.type == ButtonRelease ) &&
+ rMessage.xbutton.button == m_nDragButton )
+ {
+ bool bCancel = true;
+ if( m_aDropWindow != None )
+ {
+ if( it != m_aDropTargets.end() )
+ {
+ if( it->second.m_pTarget->m_bActive && m_nUserDragAction != DNDConstants::ACTION_NONE && m_bLastDropAccepted )
+ {
+ bHandled = true;
+ int x, y;
+ XLIB_Window aChild;
+ XTranslateCoordinates( m_pDisplay, rMessage.xbutton.root, m_aDropWindow, rMessage.xbutton.x_root, rMessage.xbutton.y_root, &x, &y, &aChild );
+ DropTargetDropEvent dtde;
+ dtde.Source = static_cast< OWeakObject* >(it->second.m_pTarget );
+ dtde.Context = new DropTargetDropContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ dtde.LocationX = x;
+ dtde.LocationY = y;
+ dtde.DropAction = m_nUserDragAction;
+ dtde.SourceActions = m_nSourceActions;
+ dtde.Transferable = m_xDragSourceTransferable;
+ m_bDropSent = true;
+ m_nDropTimeout = time( NULL );
+ m_bDropWaitingForCompletion = true;
+ aGuard.clear();
+ it->second->drop( dtde );
+ bCancel = false;
+ }
+ else bCancel = true;
+ }
+ else if( m_nCurrentProtocolVersion >= 0 )
+ {
+ bHandled = true;
+
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndDrop;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ aEvent.xclient.data.l[1] = 0;
+ aEvent.xclient.data.l[2] = rMessage.xbutton.time;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+
+ m_bDropSent = true;
+ m_nDropTimeout = time( NULL );
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ bCancel = false;
+ }
+ else
+ {
+ // dropping on non XdndWindows: acquire ownership of
+ // PRIMARY and send a middle mouse button click down/up to
+ // target window
+ SelectionAdaptor* pAdaptor = getAdaptor( XA_PRIMARY );
+ if( pAdaptor )
+ {
+ bHandled = true;
+
+ XLIB_Window aDummy;
+ XEvent aEvent;
+ aEvent.type = ButtonPress;
+ aEvent.xbutton.display = m_pDisplay;
+ aEvent.xbutton.window = m_aDropWindow;
+ aEvent.xbutton.root = rMessage.xbutton.root;
+ aEvent.xbutton.subwindow = m_aDropWindow;
+ aEvent.xbutton.time = rMessage.xbutton.time+1;
+ aEvent.xbutton.x_root = rMessage.xbutton.x_root;
+ aEvent.xbutton.y_root = rMessage.xbutton.y_root;
+ aEvent.xbutton.state = rMessage.xbutton.state;
+ aEvent.xbutton.button = Button2;
+ aEvent.xbutton.same_screen = True;
+ XTranslateCoordinates( m_pDisplay,
+ rMessage.xbutton.root, m_aDropWindow,
+ rMessage.xbutton.x_root, rMessage.xbutton.y_root,
+ &aEvent.xbutton.x, &aEvent.xbutton.y,
+ &aDummy );
+ XSendEvent( m_pDisplay, m_aDropWindow, False, ButtonPressMask, &aEvent );
+ aEvent.xbutton.type = ButtonRelease;
+ aEvent.xbutton.time++;
+ aEvent.xbutton.state |= Button2Mask;
+ XSendEvent( m_pDisplay, m_aDropWindow, False, ButtonReleaseMask, &aEvent );
+
+ m_bDropSent = true;
+ m_nDropTimeout = time( NULL );
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ m_bWaitingForPrimaryConversion = true;
+ m_bDropSent = true;
+ m_nDropTimeout = time( NULL );
+ // HACK :-)
+ aGuard.clear();
+ static_cast< X11Clipboard* >( pAdaptor )->setContents( m_xDragSourceTransferable, css::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner >() );
+ aGuard.reset();
+ bCancel = false;
+ }
+ }
+ }
+ if( bCancel )
+ {
+ // cancel drag
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ bHandled = true;
+ }
+ }
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::accept( sal_Int8 dragOperation, XLIB_Window aDropWindow, XLIB_Time )
+{
+ if( aDropWindow == m_aCurrentDropWindow )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "accept: %x\n", dragOperation );
+#endif
+ Atom nAction = None;
+ dragOperation &= (DNDConstants::ACTION_MOVE | DNDConstants::ACTION_COPY | DNDConstants::ACTION_LINK);
+ if( dragOperation & DNDConstants::ACTION_MOVE )
+ nAction = m_nXdndActionMove;
+ else if( dragOperation & DNDConstants::ACTION_COPY )
+ nAction = m_nXdndActionCopy;
+ else if( dragOperation & DNDConstants::ACTION_LINK )
+ nAction = m_nXdndActionLink;
+ m_bLastDropAccepted = true;
+ sendDragStatus( nAction );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::reject( XLIB_Window aDropWindow, XLIB_Time )
+{
+ if( aDropWindow == m_aCurrentDropWindow )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "reject\n" );
+#endif
+ m_bLastDropAccepted = false;
+ sendDragStatus( None );
+ if( m_bDropSent && m_xDragSourceListener.is() )
+ {
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ m_xDragSourceListener->dragDropEnd( dsde );
+ m_xDragSourceListener.clear();
+ }
+ }
+}
+
+/*
+ * XDragSource
+ */
+
+sal_Bool SelectionManager::isDragImageSupported() throw()
+{
+ return sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Int32 SelectionManager::getDefaultCursor( sal_Int8 dragAction ) throw()
+{
+ XLIB_Cursor aCursor = m_aNoneCursor;
+ if( dragAction & DNDConstants::ACTION_MOVE )
+ aCursor = m_aMoveCursor;
+ else if( dragAction & DNDConstants::ACTION_COPY )
+ aCursor = m_aCopyCursor;
+ else if( dragAction & DNDConstants::ACTION_LINK )
+ aCursor = m_aLinkCursor;
+ return aCursor;
+}
+
+// ------------------------------------------------------------------------
+
+int SelectionManager::getXdndVersion( XLIB_Window aWindow, XLIB_Window& rProxy )
+{
+ Atom* pProperties = NULL;
+ int nProperties = 0;
+ Atom nType;
+ int nFormat;
+ unsigned long nItems, nBytes;
+ unsigned char* pBytes = NULL;
+
+ int nVersion = -1;
+ rProxy = None;
+
+ /*
+ * XListProperties is used here to avoid unnecessary XGetWindowProperty calls
+ * and therefore reducing latency penalty
+ */
+ pProperties = XListProperties( m_pDisplay, aWindow, &nProperties );
+ // first look for proxy
+ int i;
+ for( i = 0; i < nProperties; i++ )
+ {
+ if( pProperties[i] == m_nXdndProxy )
+ {
+ XGetWindowProperty( m_pDisplay, aWindow, m_nXdndProxy, 0, 1, False, XA_WINDOW,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+ if( pBytes )
+ {
+ if( nType == XA_WINDOW )
+ rProxy = *(XLIB_Window*)pBytes;
+ XFree( pBytes );
+ pBytes = NULL;
+ if( rProxy != None )
+ {
+ // now check proxy wether it points to itself
+ XGetWindowProperty( m_pDisplay, rProxy, m_nXdndProxy, 0, 1, False, XA_WINDOW,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+ if( pBytes )
+ {
+ if( nType == XA_WINDOW && *(XLIB_Window*)pBytes != rProxy )
+ rProxy = None;
+ XFree( pBytes );
+ pBytes = NULL;
+ }
+ else
+ rProxy = None;
+ }
+ }
+ break;
+ }
+ }
+ XLIB_Window aAwareWindow = rProxy != None ? rProxy : aWindow;
+
+ XGetWindowProperty( m_pDisplay, aAwareWindow, m_nXdndAware, 0, 1, False, XA_ATOM,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+ if( pBytes )
+ {
+ if( nType == XA_ATOM )
+ nVersion = *(Atom*)pBytes;
+ XFree( pBytes );
+ }
+
+ nVersion = nVersion > nXdndProtocolRevision ? nXdndProtocolRevision : nVersion;
+
+ return nVersion;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::updateDragWindow( int nX, int nY, XLIB_Window aRoot )
+{
+ osl::ResettableMutexGuard aGuard( m_aMutex );
+
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+
+ m_nLastDragX = nX;
+ m_nLastDragY = nY;
+
+ XLIB_Window aParent = aRoot;
+ XLIB_Window aChild;
+ XLIB_Window aNewProxy = None, aNewCurrentWindow = None;
+ int nNewProtocolVersion = -1;
+ int nWinX, nWinY;
+
+ // find the first XdndAware window or check if root window is
+ // XdndAware or has XdndProxy
+ do
+ {
+ XTranslateCoordinates( m_pDisplay, aRoot, aParent, nX, nY, &nWinX, &nWinY, &aChild );
+ if( aChild != None )
+ {
+ if( aChild == m_aCurrentDropWindow && aChild != aRoot && m_nCurrentProtocolVersion >= 0 )
+ {
+ aParent = aChild;
+ break;
+ }
+ nNewProtocolVersion = getXdndVersion( aChild, aNewProxy );
+ aParent = aChild;
+ }
+ } while( aChild != None && nNewProtocolVersion < 0 );
+
+ aNewCurrentWindow = aParent;
+ if( aNewCurrentWindow == aRoot )
+ {
+ // no children, try root drop
+ nNewProtocolVersion = getXdndVersion( aNewCurrentWindow, aNewProxy );
+ if( nNewProtocolVersion < 3 )
+ {
+ aNewCurrentWindow = aNewProxy = None;
+ nNewProtocolVersion = nXdndProtocolRevision;
+ }
+ }
+
+
+ DragSourceDragEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = nNewProtocolVersion >= 0 ? m_nUserDragAction : DNDConstants::ACTION_COPY;
+ dsde.UserAction = nNewProtocolVersion >= 0 ? m_nUserDragAction : DNDConstants::ACTION_COPY;
+
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >::const_iterator it;
+ if( aNewCurrentWindow != m_aDropWindow )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "drag left window 0x%lx (rev. %d), entered window 0x%lx (rev %d)\n", m_aDropWindow, m_nCurrentProtocolVersion, aNewCurrentWindow, nNewProtocolVersion );
+#endif
+
+ if( m_aDropWindow != None )
+ {
+ it = m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() )
+ // shortcut for own drop targets
+ {
+ DropTargetEvent dte;
+ dte.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
+ aGuard.clear();
+ it->second.m_pTarget->dragExit( dte );
+ aGuard.reset();
+ }
+ else
+ {
+ // send old drop target a XdndLeave
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndLeave;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ aEvent.xclient.data.l[1] = 0;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+ if( xListener.is() )
+ {
+ aGuard.clear();
+ xListener->dragExit( dsde );
+ aGuard.reset();
+ }
+ }
+
+ m_nCurrentProtocolVersion = nNewProtocolVersion;
+ m_aDropWindow = aNewCurrentWindow;
+ m_aDropProxy = aNewProxy != None ? aNewProxy : m_aDropWindow;
+
+ it = m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() && ! it->second.m_pTarget->m_bActive )
+ m_aDropProxy = None;
+
+ if( m_aDropProxy != None && xListener.is() )
+ {
+ aGuard.clear();
+ xListener->dragEnter( dsde );
+ aGuard.reset();
+ }
+ // send XdndEnter
+ if( m_aDropProxy != None && m_nCurrentProtocolVersion >= 0 )
+ {
+ it = m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() )
+ {
+ XTranslateCoordinates( m_pDisplay, aRoot, m_aDropWindow, nX, nY, &nWinX, &nWinY, &aChild );
+ DropTargetDragEnterEvent dtde;
+ dtde.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
+ dtde.Context = new DropTargetDragContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ dtde.LocationX = nWinX;
+ dtde.LocationY = nWinY;
+ dtde.DropAction = m_nUserDragAction;
+ dtde.SourceActions = m_nSourceActions;
+ dtde.SupportedDataFlavors = m_xDragSourceTransferable->getTransferDataFlavors();
+ aGuard.clear();
+ it->second.m_pTarget->dragEnter( dtde );
+ aGuard.reset();
+ }
+ else
+ {
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndEnter;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ aEvent.xclient.data.l[1] = m_nCurrentProtocolVersion << 24;
+ memset( aEvent.xclient.data.l + 2, 0, sizeof( long )*3 );
+ // fill in data types
+ ::std::list< Atom > aConversions;
+ getNativeTypeList( m_aDragFlavors, aConversions, m_nXdndSelection );
+ if( aConversions.size() > 3 )
+ aEvent.xclient.data.l[1] |= 1;
+ ::std::list< Atom >::const_iterator type_it = aConversions.begin();
+ for( int i = 0; type_it != aConversions.end() && i < 3; i++, ++type_it )
+ aEvent.xclient.data.l[i+2] = *type_it;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+ }
+ m_nNoPosX = m_nNoPosY = m_nNoPosWidth = m_nNoPosHeight = 0;
+ }
+ else if( m_aDropProxy != None && xListener.is() )
+ {
+ aGuard.clear();
+ // drag over for XdndAware windows comes when receiving XdndStatus
+ xListener->dragOver( dsde );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::startDrag(
+ const DragGestureEvent& trigger,
+ sal_Int8 sourceActions,
+ sal_Int32,
+ sal_Int32,
+ const css::uno::Reference< XTransferable >& transferable,
+ const css::uno::Reference< XDragSourceListener >& listener
+ ) throw()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "startDrag( sourceActions = %x )\n", (int)sourceActions );
+#endif
+
+ DragSourceDropEvent aDragFailedEvent;
+ aDragFailedEvent.Source = static_cast< OWeakObject* >(this);
+ aDragFailedEvent.DragSource = static_cast< XDragSource* >(this);
+ aDragFailedEvent.DragSourceContext = new DragSourceContext( None, CurrentTime, *this );
+ aDragFailedEvent.DropAction = DNDConstants::ACTION_NONE;
+ aDragFailedEvent.DropSuccess = sal_False;
+
+ if( m_aDragRunning.check() )
+ {
+ if( listener.is() )
+ listener->dragDropEnd( aDragFailedEvent );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "*** ERROR *** second drag and drop started.\n" );
+ if( m_xDragSourceListener.is() )
+ fprintf( stderr, "*** ERROR *** drag source listener already set.\n" );
+ else
+ fprintf( stderr, "*** ERROR *** drag thread already running.\n" );
+#endif
+ return;
+ }
+
+ SalFrame* pCaptureFrame = NULL;
+
+ {
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ // first get the current pointer position and the window that
+ // the pointer is located in. since said window should be one
+ // of our DropTargets at the time of executeDrag we can use
+ // them for a start
+ XLIB_Window aRoot, aParent, aChild;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask;
+
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >::const_iterator it;
+ it = m_aDropTargets.begin();
+ while( it != m_aDropTargets.end() )
+ {
+ if( XQueryPointer( m_pDisplay, it->second.m_aRootWindow,
+ &aRoot, &aParent,
+ &root_x, &root_y,
+ &win_x, &win_y,
+ &mask ) )
+ {
+ aParent = it->second.m_aRootWindow;
+ break;
+ }
+ ++it;
+ }
+
+ // don't start DnD if there is none of our windows on the same screen as
+ // the pointer or if no mouse button is pressed
+ if( it == m_aDropTargets.end() || (mask & (Button1Mask|Button2Mask|Button3Mask)) == 0 )
+ {
+ aGuard.clear();
+ if( listener.is() )
+ listener->dragDropEnd( aDragFailedEvent );
+ return;
+ }
+
+ // try to find which of our drop targets is the drag source
+ // if that drop target is deregistered we should stop executing
+ // the drag (actually this is a poor substitute for an "endDrag"
+ // method ).
+ m_aDragSourceWindow = None;
+ aParent = aRoot = it->second.m_aRootWindow;
+ do
+ {
+ XTranslateCoordinates( m_pDisplay, aRoot, aParent, root_x, root_y, &win_x, &win_y, &aChild );
+ if( aChild != None && m_aDropTargets.find( aChild ) != m_aDropTargets.end() )
+ {
+ m_aDragSourceWindow = aChild;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found drag source window 0x%lx\n", m_aDragSourceWindow );
+#endif
+ break;
+ }
+ aParent = aChild;
+ } while( aChild != None );
+
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try to grab pointer ... " );
+#endif
+ int nPointerGrabSuccess =
+ XGrabPointer( m_pDisplay, it->second.m_aRootWindow, True,
+ DRAG_EVENT_MASK,
+ GrabModeAsync, GrabModeAsync,
+ None,
+ None,
+ CurrentTime );
+ /* if we could not grab the pointer here, there is a chance
+ that the pointer is grabbed by the other vcl display (the main loop)
+ so let's break that grab an reset it later
+
+ remark: this whole code should really be molten into normal vcl so only
+ one display is used ....
+ */
+ if( nPointerGrabSuccess != GrabSuccess )
+ {
+ osl::SolarMutex& rSolarMutex( Application::GetSolarMutex() );
+ if( rSolarMutex.tryToAcquire() )
+ {
+ pCaptureFrame = GetX11SalData()->GetDisplay()->GetCaptureFrame();
+ if( pCaptureFrame )
+ {
+ GetX11SalData()->GetDisplay()->CaptureMouse( NULL );
+ nPointerGrabSuccess =
+ XGrabPointer( m_pDisplay, it->second.m_aRootWindow, True,
+ DRAG_EVENT_MASK,
+ GrabModeAsync, GrabModeAsync,
+ None,
+ None,
+ CurrentTime );
+ }
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%d\n", nPointerGrabSuccess );
+#endif
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try to grab keyboard ... " );
+#endif
+ int nKeyboardGrabSuccess =
+ XGrabKeyboard( m_pDisplay, it->second.m_aRootWindow, True,
+ GrabModeAsync, GrabModeAsync, CurrentTime );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%d\n", nKeyboardGrabSuccess );
+#endif
+ if( nPointerGrabSuccess != GrabSuccess || nKeyboardGrabSuccess != GrabSuccess )
+ {
+ if( nPointerGrabSuccess == GrabSuccess )
+ XUngrabPointer( m_pDisplay, CurrentTime );
+ if( nKeyboardGrabSuccess == GrabSuccess )
+ XUngrabKeyboard( m_pDisplay, CurrentTime );
+ XFlush( m_pDisplay );
+ aGuard.clear();
+ if( listener.is() )
+ listener->dragDropEnd( aDragFailedEvent );
+ if( pCaptureFrame )
+ {
+ osl::SolarMutex& rSolarMutex( Application::GetSolarMutex() );
+ if( rSolarMutex.tryToAcquire() )
+ GetX11SalData()->GetDisplay()->CaptureMouse( pCaptureFrame );
+#if OSL_DEBUG_LEVEL > 0
+ else
+ OSL_FAIL( "failed to acquire SolarMutex to reset capture frame" );
+#endif
+ }
+ return;
+ }
+
+ m_xDragSourceTransferable = transferable;
+ m_xDragSourceListener = listener;
+ m_aDragFlavors = transferable->getTransferDataFlavors();
+ m_aCurrentCursor = None;
+
+ requestOwnership( m_nXdndSelection );
+
+ ::std::list< Atom > aConversions;
+ ::std::list< Atom >::const_iterator type_it;
+ getNativeTypeList( m_aDragFlavors, aConversions, m_nXdndSelection );
+
+ int nTypes = aConversions.size();
+ Atom* pTypes = (Atom*)alloca( sizeof(Atom)*nTypes );
+ type_it = aConversions.begin();
+ for( int n = 0; n < nTypes; n++, ++type_it )
+ pTypes[n] = *type_it;
+
+ XChangeProperty( m_pDisplay, m_aWindow, m_nXdndTypeList, XA_ATOM, 32, PropModeReplace, (unsigned char*)pTypes, nTypes );
+
+ m_nSourceActions = sourceActions | DNDConstants::ACTION_DEFAULT;
+ m_nUserDragAction = DNDConstants::ACTION_MOVE & m_nSourceActions;
+ if( ! m_nUserDragAction )
+ m_nUserDragAction = DNDConstants::ACTION_COPY & m_nSourceActions;
+ if( ! m_nUserDragAction )
+ m_nUserDragAction = DNDConstants::ACTION_LINK & m_nSourceActions;
+ m_nTargetAcceptAction = DNDConstants::ACTION_DEFAULT;
+ m_bDropSent = false;
+ m_bDropSuccess = false;
+ m_bWaitingForPrimaryConversion = false;
+ m_nDragButton = Button1; // default to left button
+ com::sun::star::awt::MouseEvent aEvent;
+ if( trigger.Event >>= aEvent )
+ {
+ if( aEvent.Buttons & MouseButton::LEFT )
+ m_nDragButton = Button1;
+ else if( aEvent.Buttons & MouseButton::RIGHT )
+ m_nDragButton = Button3;
+ else if( aEvent.Buttons & MouseButton::MIDDLE )
+ m_nDragButton = Button2;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "m_nUserDragAction = %x\n", (int)m_nUserDragAction );
+#endif
+ updateDragWindow( root_x, root_y, aRoot );
+ m_nUserDragAction = ~0;
+ updateDragAction( mask );
+ }
+
+ m_aDragRunning.set();
+ m_aDragExecuteThread = osl_createSuspendedThread( call_SelectionManager_runDragExecute, this );
+ if( m_aDragExecuteThread )
+ osl_resumeThread( m_aDragExecuteThread );
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "osl_createSuspendedThread failed for drag execute\n" );
+#endif
+ m_xDragSourceListener.clear();
+ m_xDragSourceTransferable.clear();
+
+ m_bDropSent = false;
+ m_bDropSuccess = false;
+ m_bWaitingForPrimaryConversion = false;
+ m_aDropWindow = None;
+ m_aDropProxy = None;
+ m_nCurrentProtocolVersion = nXdndProtocolRevision;
+ m_nNoPosX = 0;
+ m_nNoPosY = 0;
+ m_nNoPosWidth = 0;
+ m_nNoPosHeight = 0;
+ m_aCurrentCursor = None;
+
+ XUngrabPointer( m_pDisplay, CurrentTime );
+ XUngrabKeyboard( m_pDisplay, CurrentTime );
+ XFlush( m_pDisplay );
+
+ if( pCaptureFrame )
+ {
+ osl::SolarMutex& rSolarMutex( Application::GetSolarMutex() );
+ if( rSolarMutex.tryToAcquire() )
+ GetX11SalData()->GetDisplay()->CaptureMouse( pCaptureFrame );
+#if OSL_DEBUG_LEVEL > 0
+ else
+ OSL_FAIL( "failed to acquire SolarMutex to reset capture frame" );
+#endif
+ }
+
+ m_aDragRunning.reset();
+
+ if( listener.is() )
+ listener->dragDropEnd( aDragFailedEvent );
+ }
+}
+
+void SelectionManager::runDragExecute( void* pThis )
+{
+ SelectionManager* This = (SelectionManager*)pThis;
+ This->dragDoDispatch();
+}
+
+void SelectionManager::dragDoDispatch()
+{
+
+ // do drag
+ // m_xDragSourceListener will be cleared on finished drop
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "begin executeDrag dispatching\n" );
+#endif
+ TimeValue aTVal;
+ aTVal.Seconds = 0;
+ aTVal.Nanosec = 200000000;
+ oslThread aThread = m_aDragExecuteThread;
+ while( m_xDragSourceListener.is() && ( ! m_bDropSent || time(NULL)-m_nDropTimeout < 5 ) && osl_scheduleThread( aThread ) )
+ {
+ // let the thread in the run method do the dispatching
+ // just look occasionally here whether drop timed out or is completed
+ osl_waitThread( &aTVal );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "end executeDrag dispatching\n" );
+#endif
+ {
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ css::uno::Reference< XTransferable > xTransferable( m_xDragSourceTransferable );
+ m_xDragSourceListener.clear();
+ m_xDragSourceTransferable.clear();
+
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+
+ // cleanup after drag
+ if( m_bWaitingForPrimaryConversion )
+ getAdaptor( XA_PRIMARY )->clearTransferable();
+
+ m_bDropSent = false;
+ m_bDropSuccess = false;
+ m_bWaitingForPrimaryConversion = false;
+ m_aDropWindow = None;
+ m_aDropProxy = None;
+ m_nCurrentProtocolVersion = nXdndProtocolRevision;
+ m_nNoPosX = 0;
+ m_nNoPosY = 0;
+ m_nNoPosWidth = 0;
+ m_nNoPosHeight = 0;
+ m_aCurrentCursor = None;
+
+ XUngrabPointer( m_pDisplay, CurrentTime );
+ XUngrabKeyboard( m_pDisplay, CurrentTime );
+ XFlush( m_pDisplay );
+
+ m_aDragExecuteThread = NULL;
+ m_aDragRunning.reset();
+
+ aGuard.clear();
+ if( xListener.is() )
+ {
+ xTransferable.clear();
+ xListener->dragDropEnd( dsde );
+ }
+ }
+ osl_destroyThread( aThread );
+}
+
+/*
+ * XDragSourceContext
+ */
+
+sal_Int32 SelectionManager::getCurrentCursor()
+{
+ return m_aCurrentCursor;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::setCursor( sal_Int32 cursor, XLIB_Window aDropWindow, XLIB_Time )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+ if( aDropWindow == m_aDropWindow && XLIB_Cursor(cursor) != m_aCurrentCursor )
+ {
+ if( m_xDragSourceListener.is() && ! m_bDropSent )
+ {
+ m_aCurrentCursor = cursor;
+ XChangeActivePointerGrab( m_pDisplay, DRAG_EVENT_MASK, cursor, CurrentTime );
+ XFlush( m_pDisplay );
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::setImage( sal_Int32, XLIB_Window, XLIB_Time )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::transferablesFlavorsChanged()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ m_aDragFlavors = m_xDragSourceTransferable->getTransferDataFlavors();
+ int i;
+
+ std::list< Atom > aConversions;
+ std::list< Atom >::const_iterator type_it;
+
+ getNativeTypeList( m_aDragFlavors, aConversions, m_nXdndSelection );
+
+ int nTypes = aConversions.size();
+ Atom* pTypes = (Atom*)alloca( sizeof(Atom)*aConversions.size() );
+ for( i = 0, type_it = aConversions.begin(); type_it != aConversions.end(); ++type_it, i++ )
+ pTypes[i] = *type_it;
+ XChangeProperty( m_pDisplay, m_aWindow, m_nXdndTypeList, XA_ATOM, 32, PropModeReplace, (unsigned char*)pTypes, nTypes );
+
+ if( m_aCurrentDropWindow != None && m_nCurrentProtocolVersion >= 0 )
+ {
+ // send synthetic leave and enter events
+
+ XEvent aEvent;
+
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+
+ aEvent.xclient.message_type = m_nXdndLeave;
+ aEvent.xclient.data.l[1] = 0;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+
+ aEvent.xclient.message_type = m_nXdndEnter;
+ aEvent.xclient.data.l[1] = m_nCurrentProtocolVersion << 24;
+ memset( aEvent.xclient.data.l + 2, 0, sizeof( long )*3 );
+ // fill in data types
+ if( nTypes > 3 )
+ aEvent.xclient.data.l[1] |= 1;
+ for( int j = 0; j < nTypes && j < 3; j++ )
+ aEvent.xclient.data.l[j+2] = pTypes[j];
+
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+}
+
+/*
+ * dispatch loop
+ */
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleXEvent( XEvent& rEvent )
+{
+ /*
+ * since we are XConnectionListener to a second X display
+ * to get client messages it is essential not to dispatch
+ * events twice that we get on both connections
+ *
+ * between dispatching ButtonPress and startDrag
+ * the user can already have released the mouse. The ButtonRelease
+ * will then be dispatched in VCLs queue and never turn up here.
+ * Which is not so good, since startDrag will XGrabPointer and
+ * XGrabKeyboard -> solid lock.
+ */
+ if( rEvent.xany.display != m_pDisplay
+ && rEvent.type != ClientMessage
+ && rEvent.type != ButtonPress
+ && rEvent.type != ButtonRelease
+ )
+ return false;
+
+ bool bHandled = false;
+ switch (rEvent.type)
+ {
+ case SelectionClear:
+ {
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SelectionClear for selection %s\n",
+ OUStringToOString( getString( rEvent.xselectionclear.selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+ SelectionAdaptor* pAdaptor = getAdaptor( rEvent.xselectionclear.selection );
+ boost::unordered_map< Atom, Selection* >::iterator it( m_aSelections.find( rEvent.xselectionclear.selection ) );
+ if( it != m_aSelections.end() )
+ it->second->m_bOwner = false;
+ aGuard.clear();
+ if ( pAdaptor )
+ pAdaptor->clearTransferable();
+ }
+ break;
+
+ case SelectionRequest:
+ bHandled = handleSelectionRequest( rEvent.xselectionrequest );
+ break;
+ case PropertyNotify:
+ if( rEvent.xproperty.window == m_aWindow ||
+ rEvent.xproperty.window == m_aCurrentDropWindow
+ )
+ bHandled = handleReceivePropertyNotify( rEvent.xproperty );
+ else
+ bHandled = handleSendPropertyNotify( rEvent.xproperty );
+ break;
+ case SelectionNotify:
+ bHandled = handleSelectionNotify( rEvent.xselection );
+ break;
+ case ClientMessage:
+ // messages from drag target
+ if( rEvent.xclient.message_type == m_nXdndStatus ||
+ rEvent.xclient.message_type == m_nXdndFinished )
+ bHandled = handleDragEvent( rEvent );
+ // messages from drag source
+ else if(
+ rEvent.xclient.message_type == m_nXdndEnter ||
+ rEvent.xclient.message_type == m_nXdndLeave ||
+ rEvent.xclient.message_type == m_nXdndPosition ||
+ rEvent.xclient.message_type == m_nXdndDrop
+ )
+ bHandled = handleDropEvent( rEvent.xclient );
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ case MotionNotify:
+ case ButtonPress:
+ case ButtonRelease:
+ case XLIB_KeyPress:
+ case KeyRelease:
+ bHandled = handleDragEvent( rEvent );
+ break;
+ default:
+ ;
+ }
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::dispatchEvent( int millisec )
+{
+ // acquire the mutex to prevent other threads
+ // from using the same X connection
+ osl::ResettableMutexGuard aGuard(m_aMutex);
+
+ if( !XPending( m_pDisplay ))
+ { // wait for any events if none are already queued
+ pollfd aPollFD;
+ aPollFD.fd = XConnectionNumber( m_pDisplay );
+ aPollFD.events = POLLIN;
+ aPollFD.revents = 0;
+ // release mutex for the time of waiting for possible data
+ aGuard.clear();
+ if( poll( &aPollFD, 1, millisec ) <= 0 )
+ return;
+ aGuard.reset();
+ }
+ while( XPending( m_pDisplay ))
+ {
+ XEvent event;
+ XNextEvent( m_pDisplay, &event );
+ aGuard.clear();
+ handleXEvent( event );
+ aGuard.reset();
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::run( void* pThis )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "SelectionManager::run\n" );
+#endif
+ // dispatch until the cows come home
+
+ SelectionManager* This = (SelectionManager*)pThis;
+
+ timeval aLast;
+ gettimeofday( &aLast, 0 );
+
+ css::uno::Reference< XMultiServiceFactory > xFact( ::comphelper::getProcessServiceFactory() );
+ if( xFact.is() )
+ {
+ css::uno::Reference< XDesktop > xDesktop( xFact->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop")) ), UNO_QUERY );
+ if( xDesktop.is() )
+ xDesktop->addTerminateListener(This);
+ }
+
+ while( osl_scheduleThread(This->m_aThread) )
+ {
+ This->dispatchEvent( 1000 );
+
+ timeval aNow;
+ gettimeofday( &aNow, 0 );
+
+ if( (aNow.tv_sec - aLast.tv_sec) > 0 )
+ {
+ osl::ClearableMutexGuard aGuard(This->m_aMutex);
+ std::list< std::pair< SelectionAdaptor*, css::uno::Reference< XInterface > > > aChangeList;
+
+ for( boost::unordered_map< Atom, Selection* >::iterator it = This->m_aSelections.begin(); it != This->m_aSelections.end(); ++it )
+ {
+ if( it->first != This->m_nXdndSelection && ! it->second->m_bOwner )
+ {
+ XLIB_Window aOwner = XGetSelectionOwner( This->m_pDisplay, it->first );
+ if( aOwner != it->second->m_aLastOwner )
+ {
+ it->second->m_aLastOwner = aOwner;
+ std::pair< SelectionAdaptor*, css::uno::Reference< XInterface > >
+ aKeep( it->second->m_pAdaptor, it->second->m_pAdaptor->getReference() );
+ aChangeList.push_back( aKeep );
+ }
+ }
+ }
+ aGuard.clear();
+ while( aChangeList.begin() != aChangeList.end() )
+ {
+ aChangeList.front().first->fireContentsChanged();
+ aChangeList.pop_front();
+ }
+ aLast = aNow;
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "SelectionManager::run end\n" );
+#endif
+}
+
+void SelectionManager::shutdown() throw()
+{
+ osl::ResettableMutexGuard aGuard(m_aMutex);
+ if( m_bShutDown )
+ {
+ return;
+ }
+ m_bShutDown = true;
+ // stop dispatching
+ if( m_aThread )
+ {
+ osl_terminateThread( m_aThread );
+ /*
+ * Allow thread to finish before app exits to avoid pulling the carpet
+ * out from under it if pasting is occuring during shutdown
+ *
+ * a) allow it to have the Mutex and
+ * b) reschedule to allow it to complete callbacks to any
+ * Application::GetSolarMutex protected regions, etc. e.g.
+ * TransferableHelper::getTransferDataFlavors (via
+ * SelectionManager::handleSelectionRequest) which it might
+ * currently be trying to enter.
+ *
+ * Otherwise the thread may be left still waiting on a GlobalMutex
+ * when that gets destroyed, letting the thread blow up and die
+ * when enters the section in a now dead OOo instance.
+ */
+ aGuard.clear();
+ while (osl_isThreadRunning(m_aThread))
+ {
+ SolarMutexGuard guard2;
+ Application::Reschedule();
+ }
+ osl_joinWithThread( m_aThread );
+ osl_destroyThread( m_aThread );
+ m_aThread = NULL;
+ aGuard.reset();
+ }
+ m_xDisplayConnection->removeEventHandler( Any(), this );
+ m_xDisplayConnection.clear();
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool SelectionManager::handleEvent( const Any& event ) throw()
+{
+ Sequence< sal_Int8 > aSeq;
+ if( (event >>= aSeq) )
+ {
+ XEvent* pEvent = (XEvent*)aSeq.getArray();
+ XLIB_Time nTimestamp = CurrentTime;
+ if( pEvent->type == ButtonPress || pEvent->type == ButtonRelease )
+ nTimestamp = pEvent->xbutton.time;
+ else if( pEvent->type == XLIB_KeyPress || pEvent->type == KeyRelease )
+ nTimestamp = pEvent->xkey.time;
+ else if( pEvent->type == MotionNotify )
+ nTimestamp = pEvent->xmotion.time;
+ else if( pEvent->type == PropertyNotify )
+ nTimestamp = pEvent->xproperty.time;
+
+ if( nTimestamp != CurrentTime )
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+
+ m_nSelectionTimestamp = nTimestamp;
+ }
+
+ return sal_Bool( handleXEvent( *pEvent ) );
+ }
+ else
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SelectionManager got downing event\n" );
+ #endif
+ shutdown();
+ }
+ return sal_True;
+}
+
+void SAL_CALL SelectionManager::disposing( const ::com::sun::star::lang::EventObject& )
+ throw( ::com::sun::star::uno::RuntimeException )
+{
+}
+
+void SAL_CALL SelectionManager::queryTermination( const ::com::sun::star::lang::EventObject& )
+ throw( ::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException )
+{
+}
+
+/*
+ * To be safe, shutdown needs to be called before the ~SfxApplication is called, waiting until
+ * the downing event can be too late if paste are requested during shutdown and ~SfxApplication
+ * has been called before vcl is shutdown
+ */
+void SAL_CALL SelectionManager::notifyTermination( const ::com::sun::star::lang::EventObject& rEvent )
+ throw( ::com::sun::star::uno::RuntimeException )
+{
+ css::uno::Reference< XDesktop > xDesktop( rEvent.Source, UNO_QUERY );
+ if( xDesktop.is() == sal_True )
+ xDesktop->removeTerminateListener( this );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SelectionManager got app termination event\n" );
+ #endif
+ shutdown();
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::registerHandler( Atom selection, SelectionAdaptor& rAdaptor )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ Selection* pNewSelection = new Selection();
+ pNewSelection->m_pAdaptor = &rAdaptor;
+ pNewSelection->m_aAtom = selection;
+ m_aSelections[ selection ] = pNewSelection;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::deregisterHandler( Atom selection )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ ::boost::unordered_map< Atom, Selection* >::iterator it =
+ m_aSelections.find( selection );
+ if( it != m_aSelections.end() )
+ {
+ delete it->second->m_pPixmap;
+ delete it->second;
+ m_aSelections.erase( it );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+static bool bWasError = false;
+
+extern "C"
+{
+ int local_xerror_handler(Display* , XErrorEvent*)
+ {
+ bWasError = true;
+ return 0;
+ }
+ typedef int(*xerror_hdl_t)(Display*,XErrorEvent*);
+}
+
+void SelectionManager::registerDropTarget( XLIB_Window aWindow, DropTarget* pTarget )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ // sanity check
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >::const_iterator it =
+ m_aDropTargets.find( aWindow );
+ if( it != m_aDropTargets.end() )
+ OSL_FAIL( "attempt to register window as drop target twice" );
+ else if( aWindow && m_pDisplay )
+ {
+ DropTargetEntry aEntry( pTarget );
+ bWasError=false;
+ /* #i100000# ugly workaround: gtk sets its own XErrorHandler which is not suitable for us
+ unfortunately XErrorHandler is not per display, so this is just and ugly hack
+ Need to remove separate display and integrate clipboard/dnd into vcl's unx code ASAP
+ */
+ xerror_hdl_t pOldHandler = XSetErrorHandler( local_xerror_handler );
+ XSelectInput( m_pDisplay, aWindow, PropertyChangeMask );
+ if( ! bWasError )
+ {
+ // set XdndAware
+ XChangeProperty( m_pDisplay, aWindow, m_nXdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*)&nXdndProtocolRevision, 1 );
+ if( ! bWasError )
+ {
+ // get root window of window (in 99.999% of all cases this will be
+ // DefaultRootWindow( m_pDisplay )
+ int x, y;
+ unsigned int w, h, bw, d;
+ XGetGeometry( m_pDisplay, aWindow, &aEntry.m_aRootWindow,
+ &x, &y, &w, &h, &bw, &d );
+ }
+ }
+ XSetErrorHandler( pOldHandler );
+ if(bWasError)
+ return;
+ m_aDropTargets[ aWindow ] = aEntry;
+ }
+ else
+ OSL_FAIL( "attempt to register None as drop target" );
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::deregisterDropTarget( XLIB_Window aWindow )
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ m_aDropTargets.erase( aWindow );
+ if( aWindow == m_aDragSourceWindow && m_aDragRunning.check() )
+ {
+ // abort drag
+ boost::unordered_map< XLIB_Window, DropTargetEntry >::const_iterator it =
+ m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() )
+ {
+ DropTargetEvent dte;
+ dte.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
+ aGuard.clear();
+ it->second.m_pTarget->dragExit( dte );
+ }
+ else if( m_aDropProxy != None && m_nCurrentProtocolVersion >= 0 )
+ {
+ // send XdndLeave
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndLeave;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ memset( aEvent.xclient.data.l+1, 0, sizeof(long)*4);
+ m_aDropWindow = m_aDropProxy = None;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+ // notify the listener
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ css::uno::Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ }
+}
+
+/*
+ * SelectionAdaptor
+ */
+
+css::uno::Reference< XTransferable > SelectionManager::getTransferable() throw()
+{
+ return m_xDragSourceTransferable;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::clearTransferable() throw()
+{
+ m_xDragSourceTransferable.clear();
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::fireContentsChanged() throw()
+{
+}
+
+// ------------------------------------------------------------------------
+
+css::uno::Reference< XInterface > SelectionManager::getReference() throw()
+{
+ return css::uno::Reference< XInterface >( static_cast<OWeakObject*>(this) );
+}
+
+// ------------------------------------------------------------------------
+
+/*
+ * SelectionManagerHolder
+ */
+
+SelectionManagerHolder::SelectionManagerHolder() :
+ ::cppu::WeakComponentImplHelper3<
+ XDragSource,
+ XInitialization,
+ XServiceInfo > (m_aMutex)
+{
+}
+
+// ------------------------------------------------------------------------
+
+SelectionManagerHolder::~SelectionManagerHolder()
+{
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManagerHolder::initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception )
+{
+ OUString aDisplayName;
+
+ if( arguments.getLength() > 0 )
+ {
+ css::uno::Reference< XDisplayConnection > xConn;
+ arguments.getConstArray()[0] >>= xConn;
+ if( xConn.is() )
+ {
+ Any aIdentifier;
+ aIdentifier >>= aDisplayName;
+ }
+ }
+
+ SelectionManager& rManager = SelectionManager::get( aDisplayName );
+ rManager.initialize( arguments );
+ m_xRealDragSource = static_cast< XDragSource* >(&rManager);
+}
+
+/*
+ * XDragSource
+ */
+
+sal_Bool SelectionManagerHolder::isDragImageSupported() throw()
+{
+ return m_xRealDragSource.is() ? m_xRealDragSource->isDragImageSupported() : sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Int32 SelectionManagerHolder::getDefaultCursor( sal_Int8 dragAction ) throw()
+{
+ return m_xRealDragSource.is() ? m_xRealDragSource->getDefaultCursor( dragAction ) : 0;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManagerHolder::startDrag(
+ const ::com::sun::star::datatransfer::dnd::DragGestureEvent& trigger,
+ sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image,
+ const css::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& transferable,
+ const css::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener
+ ) throw()
+{
+ if( m_xRealDragSource.is() )
+ m_xRealDragSource->startDrag( trigger, sourceActions, cursor, image, transferable, listener );
+}
+
+// ------------------------------------------------------------------------
+
+/*
+ * XServiceInfo
+ */
+
+// ------------------------------------------------------------------------
+
+OUString SelectionManagerHolder::getImplementationName() throw()
+{
+ return OUString(RTL_CONSTASCII_USTRINGPARAM(XDND_IMPLEMENTATION_NAME));
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool SelectionManagerHolder::supportsService( const OUString& ServiceName ) throw()
+{
+ Sequence < OUString > SupportedServicesNames = Xdnd_getSupportedServiceNames();
+
+ for ( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
+ if (SupportedServicesNames[n].compareTo(ServiceName) == 0)
+ return sal_True;
+
+ return sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+Sequence< OUString > SelectionManagerHolder::getSupportedServiceNames() throw()
+{
+ return Xdnd_getSupportedServiceNames();
+}
+
+
+// ------------------------------------------------------------------------
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_selection.hxx b/vcl/unx/generic/dtrans/X11_selection.hxx
new file mode 100644
index 000000000000..42158e99802b
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_selection.hxx
@@ -0,0 +1,533 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _DTRANS_X11_SELECTION_HXX_
+#define _DTRANS_X11_SELECTION_HXX_
+
+#include <cppuhelper/compbase3.hxx>
+#include <cppuhelper/compbase4.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragSource.hpp>
+#include <com/sun/star/awt/XDisplayConnection.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/frame/XDesktop.hpp>
+#include <osl/thread.h>
+
+#include <osl/conditn.hxx>
+
+#include <boost/unordered_map.hpp>
+#include <list>
+
+#include "tools/prex.h"
+#include <X11/Xlib.h>
+#include "tools/postx.h"
+
+#define XDND_IMPLEMENTATION_NAME "com.sun.star.datatransfer.dnd.XdndSupport"
+#define XDND_DROPTARGET_IMPLEMENTATION_NAME "com.sun.star.datatransfer.dnd.XdndDropTarget"
+
+using namespace ::com::sun::star::uno;
+
+namespace x11 {
+
+ class PixmapHolder; // in bmp.hxx
+
+// ------------------------------------------------------------------------
+ rtl_TextEncoding getTextPlainEncoding( const ::rtl::OUString& rMimeType );
+
+ class SelectionAdaptor
+ {
+ public:
+ virtual com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable() = 0;
+ virtual void clearTransferable() = 0;
+ virtual void fireContentsChanged() = 0;
+ virtual com::sun::star::uno::Reference< XInterface > getReference() = 0;
+ // returns a reference that will keep the SelectionAdaptor alive until the
+ // refernce is released
+ };
+
+ class DropTarget :
+ public ::cppu::WeakComponentImplHelper3<
+ ::com::sun::star::datatransfer::dnd::XDropTarget,
+ ::com::sun::star::lang::XInitialization,
+ ::com::sun::star::lang::XServiceInfo
+ >
+ {
+ public:
+ ::osl::Mutex m_aMutex;
+ bool m_bActive;
+ sal_Int8 m_nDefaultActions;
+ XLIB_Window m_aTargetWindow;
+ class SelectionManager* m_pSelectionManager;
+ com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource >
+ m_xSelectionManager;
+ ::std::list< com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener > >
+ m_aListeners;
+
+ DropTarget();
+ virtual ~DropTarget();
+
+ // convenience functions that loop over listeners
+ void dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtde ) throw();
+ void dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw();
+ void dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw();
+ void drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& dtde ) throw();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& args ) throw ( ::com::sun::star::uno::Exception );
+
+ // XDropTarget
+ virtual void SAL_CALL addDropTargetListener( const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw();
+ virtual void SAL_CALL removeDropTargetListener( const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw();
+ virtual sal_Bool SAL_CALL isActive() throw();
+ virtual void SAL_CALL setActive( sal_Bool active ) throw();
+ virtual sal_Int8 SAL_CALL getDefaultActions() throw();
+ virtual void SAL_CALL setDefaultActions( sal_Int8 actions ) throw();
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName() throw();
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw();
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString >
+ SAL_CALL getSupportedServiceNames() throw();
+ };
+
+ class SelectionManagerHolder :
+ public ::cppu::WeakComponentImplHelper3<
+ ::com::sun::star::datatransfer::dnd::XDragSource,
+ ::com::sun::star::lang::XInitialization,
+ ::com::sun::star::lang::XServiceInfo
+ >
+ {
+ ::osl::Mutex m_aMutex;
+ com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource >
+ m_xRealDragSource;
+ public:
+ SelectionManagerHolder();
+ virtual ~SelectionManagerHolder();
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName() throw();
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw();
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString >
+ SAL_CALL getSupportedServiceNames() throw();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception );
+
+ // XDragSource
+ virtual sal_Bool SAL_CALL isDragImageSupported() throw();
+ virtual sal_Int32 SAL_CALL getDefaultCursor( sal_Int8 dragAction ) throw();
+ virtual void SAL_CALL startDrag(
+ const ::com::sun::star::datatransfer::dnd::DragGestureEvent& trigger,
+ sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image,
+ const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& transferable,
+ const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener
+ ) throw();
+
+ };
+
+
+ class SelectionManager :
+ public ::cppu::WeakImplHelper4<
+ ::com::sun::star::datatransfer::dnd::XDragSource,
+ ::com::sun::star::lang::XInitialization,
+ ::com::sun::star::awt::XEventHandler,
+ ::com::sun::star::frame::XTerminateListener
+ >,
+ public SelectionAdaptor
+ {
+ static ::boost::unordered_map< ::rtl::OUString, SelectionManager*, ::rtl::OUStringHash >& getInstances();
+
+ // for INCR type selection transfer
+ // INCR protocol is used if the data cannot
+ // be transported at once but in parts
+ // IncrementalTransfer holds the bytes to be transmitted
+ // as well a the current position
+ // INCR triggers the delivery of the next part by deleting the
+ // property used to transfer the data
+ struct IncrementalTransfer
+ {
+ Sequence< sal_Int8 > m_aData;
+ int m_nBufferPos;
+ XLIB_Window m_aRequestor;
+ Atom m_aProperty;
+ Atom m_aTarget;
+ int m_nFormat;
+ int m_nTransferStartTime;
+ };
+ int m_nIncrementalThreshold;
+
+ // a struct to hold the data associated with a selection
+ struct Selection
+ {
+ enum State
+ {
+ Inactive, WaitingForResponse, WaitingForData, IncrementalTransfer
+ };
+
+ State m_eState;
+ SelectionAdaptor* m_pAdaptor;
+ Atom m_aAtom;
+ ::osl::Condition m_aDataArrived;
+ Sequence< sal_Int8 > m_aData;
+ Sequence< ::com::sun::star::datatransfer::DataFlavor >
+ m_aTypes;
+ std::vector< Atom > m_aNativeTypes;
+ // this is used for caching
+ // m_aTypes is invalid after 2 seconds
+ // m_aNativeTypes contains the corresponding original atom
+ Atom m_aRequestedType;
+ // m_aRequestedType is only valid while WaitingForResponse and WaitingFotData
+ int m_nLastTimestamp;
+ bool m_bHaveUTF16;
+ Atom m_aUTF8Type;
+ bool m_bHaveCompound;
+ bool m_bOwner;
+ XLIB_Window m_aLastOwner;
+ PixmapHolder* m_pPixmap;
+ // m_nOrigXLIB_Timestamp contains the XLIB_Timestamp at which the seclection
+ // was acquired; needed for XLIB_TimeSTAMP target
+ XLIB_Time m_nOrigTimestamp;
+
+ Selection() : m_eState( Inactive ),
+ m_pAdaptor( NULL ),
+ m_aAtom( None ),
+ m_aRequestedType( None ),
+ m_nLastTimestamp( 0 ),
+ m_bHaveUTF16( false ),
+ m_aUTF8Type( None ),
+ m_bHaveCompound( false ),
+ m_bOwner( false ),
+ m_aLastOwner( None ),
+ m_pPixmap( NULL ),
+ m_nOrigTimestamp( CurrentTime )
+ {}
+ };
+
+ // a struct to hold data associated with a XDropTarget
+ struct DropTargetEntry
+ {
+ DropTarget* m_pTarget;
+ XLIB_Window m_aRootWindow;
+
+ DropTargetEntry() : m_pTarget( NULL ), m_aRootWindow( None ) {}
+ DropTargetEntry( DropTarget* pTarget ) :
+ m_pTarget( pTarget ),
+ m_aRootWindow( None )
+ {}
+ DropTargetEntry( const DropTargetEntry& rEntry ) :
+ m_pTarget( rEntry.m_pTarget ),
+ m_aRootWindow( rEntry.m_aRootWindow )
+ {}
+ ~DropTargetEntry() {}
+
+ DropTarget* operator->() const { return m_pTarget; }
+ DropTargetEntry& operator=(const DropTargetEntry& rEntry)
+ { m_pTarget = rEntry.m_pTarget; m_aRootWindow = rEntry.m_aRootWindow; return *this; }
+ };
+
+ // internal data
+ Display* m_pDisplay;
+ oslThread m_aThread;
+ oslThread m_aDragExecuteThread;
+ ::osl::Condition m_aDragRunning;
+ XLIB_Window m_aWindow;
+ com::sun::star::uno::Reference< ::com::sun::star::awt::XDisplayConnection >
+ m_xDisplayConnection;
+ com::sun::star::uno::Reference< com::sun::star::script::XInvocation >
+ m_xBitmapConverter;
+ sal_Int32 m_nSelectionTimeout;
+ XLIB_Time m_nSelectionTimestamp;
+
+
+ // members used for Xdnd
+
+ // drop only
+
+ // contains the XdndEnterEvent of a drop action running
+ // with one of our targets. The data.l[0] member
+ // (conatining the drag source XLIB_Window) is set
+ // to None while that is not the case
+ XClientMessageEvent m_aDropEnterEvent;
+ // set to false on XdndEnter
+ // set to true on first XdndPosition or XdndLeave
+ bool m_bDropEnterSent;
+ XLIB_Window m_aCurrentDropWindow;
+ // XLIB_Time code of XdndDrop
+ XLIB_Time m_nDropTime;
+ sal_Int8 m_nLastDropAction;
+ // XTransferable for Xdnd with foreign drag source
+ com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >
+ m_xDropTransferable;
+ int m_nLastX, m_nLastY;
+ XLIB_Time m_nDropTimestamp;
+ // set to true when calling drop()
+ // if another XdndEnter is received this shows that
+ // someone forgot to call dropComplete - we should reset
+ // and react to the new drop
+ bool m_bDropWaitingForCompletion;
+
+ // drag only
+
+ // None if no Dnd action is running with us as source
+ XLIB_Window m_aDropWindow;
+ // either m_aDropXLIB_Window or its XdndProxy
+ XLIB_Window m_aDropProxy;
+ XLIB_Window m_aDragSourceWindow;
+ // XTransferable for Xdnd when we are drag source
+ com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >
+ m_xDragSourceTransferable;
+ com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >
+ m_xDragSourceListener;
+ // root coordinates
+ int m_nLastDragX, m_nLastDragY;
+ Sequence< ::com::sun::star::datatransfer::DataFlavor >
+ m_aDragFlavors;
+ // the rectangle the pointer must leave until a new XdndPosition should
+ // be sent. empty unless the drop target told to fill
+ int m_nNoPosX, m_nNoPosY, m_nNoPosWidth, m_nNoPosHeight;
+ unsigned int m_nDragButton;
+ sal_Int8 m_nUserDragAction;
+ sal_Int8 m_nTargetAcceptAction;
+ sal_Int8 m_nSourceActions;
+ bool m_bLastDropAccepted;
+ bool m_bDropSuccess;
+ bool m_bDropSent;
+ time_t m_nDropTimeout;
+ bool m_bWaitingForPrimaryConversion;
+ XLIB_Time m_nDragTimestamp;
+
+ // drag cursors
+ XLIB_Cursor m_aMoveCursor;
+ XLIB_Cursor m_aCopyCursor;
+ XLIB_Cursor m_aLinkCursor;
+ XLIB_Cursor m_aNoneCursor;
+ XLIB_Cursor m_aCurrentCursor;
+
+
+ // drag and drop
+
+ int m_nCurrentProtocolVersion;
+ ::boost::unordered_map< XLIB_Window, DropTargetEntry >
+ m_aDropTargets;
+
+
+ // some special atoms that are needed often
+ Atom m_nCLIPBOARDAtom;
+ Atom m_nTARGETSAtom;
+ Atom m_nTIMESTAMPAtom;
+ Atom m_nTEXTAtom;
+ Atom m_nINCRAtom;
+ Atom m_nCOMPOUNDAtom;
+ Atom m_nMULTIPLEAtom;
+ Atom m_nUTF16Atom;
+ Atom m_nImageBmpAtom;
+ Atom m_nXdndAware;
+ Atom m_nXdndEnter;
+ Atom m_nXdndLeave;
+ Atom m_nXdndPosition;
+ Atom m_nXdndStatus;
+ Atom m_nXdndDrop;
+ Atom m_nXdndFinished;
+ Atom m_nXdndSelection;
+ Atom m_nXdndTypeList;
+ Atom m_nXdndProxy;
+ Atom m_nXdndActionCopy;
+ Atom m_nXdndActionMove;
+ Atom m_nXdndActionLink;
+ Atom m_nXdndActionAsk;
+ Atom m_nXdndActionPrivate;
+
+ // caching for atoms
+ ::boost::unordered_map< Atom, ::rtl::OUString >
+ m_aAtomToString;
+ ::boost::unordered_map< ::rtl::OUString, Atom, ::rtl::OUStringHash >
+ m_aStringToAtom;
+
+ // the registered selections
+ ::boost::unordered_map< Atom, Selection* >
+ m_aSelections;
+ // IncrementalTransfers in progress
+ boost::unordered_map< XLIB_Window, boost::unordered_map< Atom, IncrementalTransfer > >
+ m_aIncrementals;
+
+ // do not use X11 multithreading capabilities
+ // since this leads to deadlocks in different Xlib implentations
+ // (XFree as well as Xsun) use an own mutex instead
+ ::osl::Mutex m_aMutex;
+ bool m_bShutDown;
+
+ SelectionManager();
+ ~SelectionManager();
+
+ SelectionAdaptor* getAdaptor( Atom selection );
+ PixmapHolder* getPixmapHolder( Atom selection );
+
+ // handle various events
+ bool handleSelectionRequest( XSelectionRequestEvent& rRequest );
+ bool handleSendPropertyNotify( XPropertyEvent& rNotify );
+ bool handleReceivePropertyNotify( XPropertyEvent& rNotify );
+ bool handleSelectionNotify( XSelectionEvent& rNotify );
+ bool handleDragEvent( XEvent& rMessage );
+ bool handleDropEvent( XClientMessageEvent& rMessage );
+
+ // dnd helpers
+ void sendDragStatus( Atom nDropAction );
+ void sendDropPosition( bool bForce, XLIB_Time eventXLIB_Time );
+ bool updateDragAction( int modifierState );
+ int getXdndVersion( XLIB_Window aXLIB_Window, XLIB_Window& rProxy );
+ XLIB_Cursor createCursor( const unsigned char* pPointerData, const unsigned char* pMaskData, int width, int height, int hotX, int hotY );
+ // coordinates on root XLIB_Window
+ void updateDragWindow( int nX, int nY, XLIB_Window aRoot );
+
+ bool getPasteData( Atom selection, Atom type, Sequence< sal_Int8 >& rData );
+ // returns true if conversion was successful
+ bool convertData( const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTransferable,
+ Atom nType,
+ Atom nSelection,
+ int & rFormat,
+ Sequence< sal_Int8 >& rData );
+ bool sendData( SelectionAdaptor* pAdaptor, XLIB_Window requestor, Atom target, Atom property, Atom selection );
+
+ // thread dispatch loop
+ public:
+ // public for extern "C" stub
+ static void run( void* );
+ private:
+ void dispatchEvent( int millisec );
+ // drag thread dispatch
+ public:
+ // public for extern "C" stub
+ static void runDragExecute( void* );
+ private:
+ void dragDoDispatch();
+ bool handleXEvent( XEvent& rEvent );
+
+ // compound text conversion
+ ::rtl::OString convertToCompound( const ::rtl::OUString& rText );
+ ::rtl::OUString convertFromCompound( const char* pText, int nLen = -1 );
+
+ sal_Int8 getUserDragAction() const;
+ sal_Int32 getSelectionTimeout();
+ public:
+ static SelectionManager& get( const ::rtl::OUString& rDisplayName = ::rtl::OUString() );
+
+ Display * getDisplay() { return m_pDisplay; };
+ XLIB_Window getWindow() { return m_aWindow; };
+
+
+ void registerHandler( Atom selection, SelectionAdaptor& rAdaptor );
+ void deregisterHandler( Atom selection );
+ bool requestOwnership( Atom selection );
+
+ // allow for synchronization over one mutex for XClipboard
+ osl::Mutex& getMutex() { return m_aMutex; }
+
+
+ Atom getAtom( const ::rtl::OUString& rString );
+ const ::rtl::OUString& getString( Atom nAtom );
+
+ // type conversion
+ // note: convertTypeToNative does NOT clear the list, so you can append
+ // multiple types to the same list
+ void convertTypeToNative( const ::rtl::OUString& rType, Atom selection, int& rFormat, ::std::list< Atom >& rConversions, bool bPushFront = false );
+ ::rtl::OUString convertTypeFromNative( Atom nType, Atom selection, int& rFormat );
+ void getNativeTypeList( const Sequence< com::sun::star::datatransfer::DataFlavor >& rTypes, std::list< Atom >& rOutTypeList, Atom targetselection );
+
+ // methods for transferable
+ bool getPasteDataTypes( Atom selection, Sequence< ::com::sun::star::datatransfer::DataFlavor >& rTypes );
+ bool getPasteData( Atom selection, const ::rtl::OUString& rType, Sequence< sal_Int8 >& rData );
+
+ // for XDropTarget to register/deregister itself
+ void registerDropTarget( XLIB_Window aXLIB_Window, DropTarget* pTarget );
+ void deregisterDropTarget( XLIB_Window aXLIB_Window );
+
+ // for XDropTarget{Drag|Drop}Context
+ void accept( sal_Int8 dragOperation, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
+ void reject( XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
+ void dropComplete( sal_Bool success, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
+
+ // for XDragSourceContext
+ sal_Int32 getCurrentCursor();
+ void setCursor( sal_Int32 cursor, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
+ void setImage( sal_Int32 image, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
+ void transferablesFlavorsChanged();
+
+ void shutdown() throw();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception );
+
+ // XEventHandler
+ virtual sal_Bool SAL_CALL handleEvent( const Any& event ) throw();
+
+ // XDragSource
+ virtual sal_Bool SAL_CALL isDragImageSupported() throw();
+ virtual sal_Int32 SAL_CALL getDefaultCursor( sal_Int8 dragAction ) throw();
+ virtual void SAL_CALL startDrag(
+ const ::com::sun::star::datatransfer::dnd::DragGestureEvent& trigger,
+ sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image,
+ const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& transferable,
+ const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener
+ ) throw();
+
+ // SelectionAdaptor for XdndSelection Drag (we are drag source)
+ virtual com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable() throw();
+ virtual void clearTransferable() throw();
+ virtual void fireContentsChanged() throw();
+ virtual com::sun::star::uno::Reference< XInterface > getReference() throw();
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw( ::com::sun::star::uno::RuntimeException );
+
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination( const ::com::sun::star::lang::EventObject& aEvent )
+ throw( ::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException );
+ virtual void SAL_CALL notifyTermination( const ::com::sun::star::lang::EventObject& aEvent )
+ throw( ::com::sun::star::uno::RuntimeException );
+ };
+
+// ------------------------------------------------------------------------
+
+ ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL Xdnd_getSupportedServiceNames();
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL Xdnd_createInstance(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xMultiServiceFactory);
+
+ ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL Xdnd_dropTarget_getSupportedServiceNames();
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL Xdnd_dropTarget_createInstance(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xMultiServiceFactory);
+
+// ------------------------------------------------------------------------
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_service.cxx b/vcl/unx/generic/dtrans/X11_service.cxx
new file mode 100644
index 000000000000..bdfdd4bb7a91
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_service.cxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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/salinst.h"
+
+#include <X11_clipboard.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <uno/dispatcher.h> // declaration of generic uno interface
+#include <uno/mapping.hxx> // mapping stuff
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/compbase1.hxx>
+
+namespace {
+
+namespace css = com::sun::star;
+
+}
+
+using namespace cppu;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::awt;
+using namespace x11;
+
+using ::rtl::OUString;
+
+Sequence< OUString > SAL_CALL x11::X11Clipboard_getSupportedServiceNames()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.clipboard.SystemClipboard"));
+ return aRet;
+}
+
+Sequence< OUString > SAL_CALL x11::Xdnd_getSupportedServiceNames()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.X11DragSource"));
+ return aRet;
+}
+
+Sequence< OUString > SAL_CALL x11::Xdnd_dropTarget_getSupportedServiceNames()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.X11DropTarget"));
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+css::uno::Reference< XInterface > X11SalInstance::CreateClipboard( const Sequence< Any >& arguments )
+{
+ static boost::unordered_map< OUString, ::boost::unordered_map< Atom, Reference< XClipboard > >, ::rtl::OUStringHash > m_aInstances;
+
+ OUString aDisplayName;
+ Atom nSelection;
+
+ // extract display name from connection argument. An exception is thrown
+ // by SelectionManager.initialize() if no display connection is given.
+ if( arguments.getLength() > 0 )
+ {
+ css::uno::Reference< XDisplayConnection > xConn;
+ arguments.getConstArray()[0] >>= xConn;
+
+ if( xConn.is() )
+ {
+ Any aIdentifier = xConn->getIdentifier();
+ aIdentifier >>= aDisplayName;
+ }
+ }
+
+ SelectionManager& rManager = SelectionManager::get( aDisplayName );
+ rManager.initialize( arguments );
+
+ // check if any other selection than clipboard selection is specified
+ if( arguments.getLength() > 1 )
+ {
+ OUString aSelectionName;
+
+ arguments.getConstArray()[1] >>= aSelectionName;
+ nSelection = rManager.getAtom( aSelectionName );
+ }
+ else
+ {
+ // default atom is clipboard selection
+ nSelection = rManager.getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) );
+ }
+
+ ::boost::unordered_map< Atom, css::uno::Reference< XClipboard > >& rMap( m_aInstances[ aDisplayName ] );
+ ::boost::unordered_map< Atom, css::uno::Reference< XClipboard > >::iterator it = rMap.find( nSelection );
+ if( it != rMap.end() )
+ return it->second;
+
+ X11Clipboard* pClipboard = new X11Clipboard( rManager, nSelection );
+ rMap[ nSelection ] = pClipboard;
+
+ return static_cast<OWeakObject*>(pClipboard);
+}
+
+// ------------------------------------------------------------------------
+
+css::uno::Reference< XInterface > X11SalInstance::CreateDragSource()
+{
+ return css::uno::Reference < XInterface >( ( OWeakObject * ) new SelectionManagerHolder() );
+}
+
+// ------------------------------------------------------------------------
+
+css::uno::Reference< XInterface > X11SalInstance::CreateDropTarget()
+{
+ return css::uno::Reference < XInterface >( ( OWeakObject * ) new DropTarget() );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_transferable.cxx b/vcl/unx/generic/dtrans/X11_transferable.cxx
new file mode 100644
index 000000000000..076da0917a40
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_transferable.cxx
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <X11_transferable.hxx>
+#include <X11/Xatom.h>
+#include <com/sun/star/io/IOException.hpp>
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::io;
+using namespace com::sun::star::uno;
+using namespace cppu;
+using namespace osl;
+
+using namespace x11;
+
+using ::rtl::OUString;
+
+
+X11Transferable::X11Transferable(
+ SelectionManager& rManager,
+ const Reference< XInterface >& xCreator,
+ Atom selection
+ ) :
+ m_rManager( rManager ),
+ m_xCreator( xCreator ),
+ m_aSelection( selection )
+{
+}
+
+//==================================================================================================
+
+X11Transferable::~X11Transferable()
+{
+}
+
+//==================================================================================================
+
+Any SAL_CALL X11Transferable::getTransferData( const DataFlavor& rFlavor )
+ throw(UnsupportedFlavorException, IOException, RuntimeException)
+{
+ Any aRet;
+ Sequence< sal_Int8 > aData;
+ bool bSuccess = m_rManager.getPasteData( m_aSelection ? m_aSelection : XA_PRIMARY, rFlavor.MimeType, aData );
+ if( ! bSuccess && m_aSelection == 0 )
+ bSuccess = m_rManager.getPasteData( m_rManager.getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) ), rFlavor.MimeType, aData );
+
+ if( ! bSuccess )
+ {
+ throw UnsupportedFlavorException( rFlavor.MimeType, static_cast < XTransferable * > ( this ) );
+ }
+ if( rFlavor.MimeType.equalsIgnoreAsciiCase( OUString(RTL_CONSTASCII_USTRINGPARAM("text/plain;charset=utf-16")) ) )
+ {
+ int nLen = aData.getLength()/2;
+ if( ((sal_Unicode*)aData.getConstArray())[nLen-1] == 0 )
+ nLen--;
+ OUString aString( (sal_Unicode*)aData.getConstArray(), nLen );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "X11Transferable::getTransferData( \"%s\" )\n -> \"%s\"\n",
+ OUStringToOString( rFlavor.MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( aString, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ aRet <<= aString;
+ }
+ else
+ aRet <<= aData;
+ return aRet;
+}
+
+//==================================================================================================
+
+Sequence< DataFlavor > SAL_CALL X11Transferable::getTransferDataFlavors()
+ throw(RuntimeException)
+{
+ Sequence< DataFlavor > aFlavorList;
+ bool bSuccess = m_rManager.getPasteDataTypes( m_aSelection ? m_aSelection : XA_PRIMARY, aFlavorList );
+ if( ! bSuccess && m_aSelection == 0 )
+ bSuccess = m_rManager.getPasteDataTypes( m_rManager.getAtom( OUString(RTL_CONSTASCII_USTRINGPARAM("CLIPBOARD")) ), aFlavorList );
+
+ return aFlavorList;
+}
+
+//==================================================================================================
+
+sal_Bool SAL_CALL X11Transferable::isDataFlavorSupported( const DataFlavor& aFlavor )
+ throw(RuntimeException)
+{
+ if( aFlavor.DataType != getCppuType( (Sequence< sal_Int8 >*)0 ) )
+ {
+ if( ! aFlavor.MimeType.equalsIgnoreAsciiCase( OUString(RTL_CONSTASCII_USTRINGPARAM("text/plain;charset=utf-16")) ) &&
+ aFlavor.DataType == getCppuType( (OUString*)0 ) )
+ return false;
+ }
+
+ Sequence< DataFlavor > aFlavors( getTransferDataFlavors() );
+ for( int i = 0; i < aFlavors.getLength(); i++ )
+ if( aFlavor.MimeType.equalsIgnoreAsciiCase( aFlavors.getConstArray()[i].MimeType ) &&
+ aFlavor.DataType == aFlavors.getConstArray()[i].DataType )
+ return sal_True;
+
+ return sal_False;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/X11_transferable.hxx b/vcl/unx/generic/dtrans/X11_transferable.hxx
new file mode 100644
index 000000000000..683faa0a7f87
--- /dev/null
+++ b/vcl/unx/generic/dtrans/X11_transferable.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _DTRANS_X11_TRANSFERABLE_HXX_
+#define _DTRANS_X11_TRANSFERABLE_HXX_
+
+#include <X11_selection.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+namespace x11 {
+
+ class X11Transferable : public ::cppu::WeakImplHelper1 <
+ ::com::sun::star::datatransfer::XTransferable >
+ {
+ ::osl::Mutex m_aMutex;
+
+ SelectionManager& m_rManager;
+ com::sun::star::uno::Reference< XInterface > m_xCreator;
+ Atom m_aSelection;
+ public:
+ X11Transferable( SelectionManager& rManager, const com::sun::star::uno::Reference< XInterface >& xCreator, Atom selection = None );
+ virtual ~X11Transferable();
+
+ /*
+ * XTransferable
+ */
+
+ virtual ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor )
+ throw(::com::sun::star::datatransfer::UnsupportedFlavorException,
+ ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException
+ );
+
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ virtual sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor )
+ throw(::com::sun::star::uno::RuntimeException);
+ };
+
+} // namespace
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/bmp.cxx b/vcl/unx/generic/dtrans/bmp.cxx
new file mode 100644
index 000000000000..57ad8ecf8a4d
--- /dev/null
+++ b/vcl/unx/generic/dtrans/bmp.cxx
@@ -0,0 +1,742 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <unistd.h>
+#include <cstdio>
+#include <cstring>
+
+#include <bmp.hxx>
+
+#include <X11_selection.hxx>
+#include <sal/macros.h>
+
+using namespace x11;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::script;
+using namespace com::sun::star::awt;
+
+/*
+ * helper functions
+ */
+
+inline void writeLE( sal_uInt16 nNumber, sal_uInt8* pBuffer )
+{
+ pBuffer[ 0 ] = (nNumber & 0xff);
+ pBuffer[ 1 ] = ((nNumber>>8)&0xff);
+}
+
+inline void writeLE( sal_uInt32 nNumber, sal_uInt8* pBuffer )
+{
+ pBuffer[ 0 ] = (nNumber & 0xff);
+ pBuffer[ 1 ] = ((nNumber>>8)&0xff);
+ pBuffer[ 2 ] = ((nNumber>>16)&0xff);
+ pBuffer[ 3 ] = ((nNumber>>24)&0xff);
+}
+
+inline sal_uInt16 readLE16( const sal_uInt8* pBuffer )
+{
+ return (((sal_uInt16)pBuffer[1]) << 8 ) | pBuffer[0];
+}
+
+inline sal_uInt16 readLE32( const sal_uInt8* pBuffer )
+{
+ return
+ (((sal_uInt32)pBuffer[3]) << 24 ) |
+ (((sal_uInt32)pBuffer[2]) << 16 ) |
+ (((sal_uInt32)pBuffer[1]) << 8 ) |
+ pBuffer[0];
+}
+
+
+/*
+ * BmpTransporter
+ */
+
+BmpTransporter::BmpTransporter( const Sequence<sal_Int8>& rBmp ) :
+ m_aBM( rBmp )
+{
+ const sal_uInt8* pData = (const sal_uInt8*)rBmp.getConstArray();
+
+ if( pData[0] == 'B' || pData[1] == 'M' )
+ {
+ pData = pData+14;
+ m_aSize.Width = readLE32( pData+4 );
+ m_aSize.Height = readLE32( pData+8 );
+ }
+ else
+ m_aSize.Width = m_aSize.Height = 0;
+}
+
+BmpTransporter::~BmpTransporter()
+{
+}
+
+com::sun::star::awt::Size SAL_CALL BmpTransporter::getSize() throw()
+{
+ return m_aSize;
+}
+
+Sequence< sal_Int8 > SAL_CALL BmpTransporter::getDIB() throw()
+{
+ return m_aBM;
+}
+
+Sequence< sal_Int8 > SAL_CALL BmpTransporter::getMaskDIB() throw()
+{
+ return Sequence< sal_Int8 >();
+}
+
+/*
+ * scanline helpers
+ */
+
+inline void X11_writeScanlinePixel( unsigned long nColor, sal_uInt8* pScanline, int depth, int x )
+{
+ switch( depth )
+ {
+ case 1:
+ pScanline[ x/8 ] &= ~(1 << (x&7));
+ pScanline[ x/8 ] |= ((nColor & 1) << (x&7));
+ break;
+ case 4:
+ pScanline[ x/2 ] &= ((x&1) ? 0x0f : 0xf0);
+ pScanline[ x/2 ] |= ((x&1) ? (nColor & 0x0f) : ((nColor & 0x0f) << 4));
+ break;
+ default:
+ case 8:
+ pScanline[ x ] = (nColor & 0xff);
+ break;
+ }
+}
+
+static sal_uInt8* X11_getPaletteBmpFromImage(
+ Display* pDisplay,
+ XImage* pImage,
+ Colormap aColormap,
+ sal_Int32& rOutSize
+ )
+{
+ sal_uInt32 nColors = 0;
+
+ rOutSize = 0;
+
+ sal_uInt8* pBuffer = 0;
+ sal_uInt32 nHeaderSize, nScanlineSize;
+ sal_uInt16 nBitCount;
+ // determine header and scanline size
+ switch( pImage->depth )
+ {
+ case 1:
+ nHeaderSize = 64;
+ nScanlineSize = (pImage->width+31)/32;
+ nBitCount = 1;
+ break;
+ case 4:
+ nHeaderSize = 72;
+ nScanlineSize = (pImage->width+1)/2;
+ nBitCount = 4;
+ break;
+ default:
+ case 8:
+ nHeaderSize = 1084;
+ nScanlineSize = pImage->width;
+ nBitCount = 8;
+ break;
+ }
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+
+ // allocate buffer to hold header and scanlines, initialize to zero
+ rOutSize = nHeaderSize + nScanlineSize*pImage->height;
+ pBuffer = (sal_uInt8*)rtl_allocateZeroMemory( rOutSize );
+ for( int y = 0; y < pImage->height; y++ )
+ {
+ sal_uInt8* pScanline = pBuffer + nHeaderSize + (pImage->height-1-y)*nScanlineSize;
+ for( int x = 0; x < pImage->width; x++ )
+ {
+ unsigned long nPixel = XGetPixel( pImage, x, y );
+ if( nPixel >= nColors )
+ nColors = nPixel+1;
+ X11_writeScanlinePixel( nPixel, pScanline, pImage->depth, x );
+ }
+ }
+
+ // fill in header fields
+ pBuffer[ 0 ] = 'B';
+ pBuffer[ 1 ] = 'M';
+
+ writeLE( nHeaderSize, pBuffer+10 );
+ writeLE( (sal_uInt32)40, pBuffer+14 );
+ writeLE( (sal_uInt32)pImage->width, pBuffer+18 );
+ writeLE( (sal_uInt32)pImage->height, pBuffer+22 );
+ writeLE( (sal_uInt16)1, pBuffer+26 );
+ writeLE( nBitCount, pBuffer+28 );
+ writeLE( (sal_uInt32)(DisplayWidth(pDisplay,DefaultScreen(pDisplay))*1000/DisplayWidthMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+38);
+ writeLE( (sal_uInt32)(DisplayHeight(pDisplay,DefaultScreen(pDisplay))*1000/DisplayHeightMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+42);
+ writeLE( nColors, pBuffer+46 );
+ writeLE( nColors, pBuffer+50 );
+
+ XColor aColors[256];
+ if( nColors > (1U << nBitCount) ) // paranoia
+ nColors = (1U << nBitCount);
+ for( unsigned long nPixel = 0; nPixel < nColors; nPixel++ )
+ {
+ aColors[nPixel].flags = DoRed | DoGreen | DoBlue;
+ aColors[nPixel].pixel = nPixel;
+ }
+ XQueryColors( pDisplay, aColormap, aColors, nColors );
+ for( sal_uInt32 i = 0; i < nColors; i++ )
+ {
+ pBuffer[ 54 + i*4 ] = (sal_uInt8)(aColors[i].blue >> 8);
+ pBuffer[ 55 + i*4 ] = (sal_uInt8)(aColors[i].green >> 8);
+ pBuffer[ 56 + i*4 ] = (sal_uInt8)(aColors[i].red >> 8);
+ }
+
+ // done
+
+ return pBuffer;
+}
+
+inline unsigned long doRightShift( unsigned long nValue, int nShift )
+{
+ return (nShift > 0) ? (nValue >> nShift) : (nValue << (-nShift));
+}
+
+inline unsigned long doLeftShift( unsigned long nValue, int nShift )
+{
+ return (nShift > 0) ? (nValue << nShift) : (nValue >> (-nShift));
+}
+
+static void getShift( unsigned long nMask, int& rShift, int& rSigBits, int& rShift2 )
+{
+ unsigned long nUseMask = nMask;
+ rShift = 0;
+ while( nMask & 0xffffff00 )
+ {
+ rShift++;
+ nMask >>= 1;
+ }
+ if( rShift == 0 )
+ while( ! (nMask & 0x00000080) )
+ {
+ rShift--;
+ nMask <<= 1;
+ }
+
+ int nRotate = sizeof(unsigned long)*8 - rShift;
+ rSigBits = 0;
+ nMask = doRightShift( nUseMask, rShift) ;
+ while( nRotate-- )
+ {
+ if( nMask & 1 )
+ rSigBits++;
+ nMask >>= 1;
+ }
+
+ rShift2 = 0;
+ if( rSigBits < 8 )
+ rShift2 = 8-rSigBits;
+}
+
+static sal_uInt8* X11_getTCBmpFromImage(
+ Display* pDisplay,
+ XImage* pImage,
+ sal_Int32& rOutSize,
+ int nScreenNo
+ )
+{
+ // get masks from visual info (guesswork)
+ XVisualInfo aVInfo;
+ if( ! XMatchVisualInfo( pDisplay, nScreenNo, pImage->depth, TrueColor, &aVInfo ) )
+ return NULL;
+
+ rOutSize = 0;
+
+ sal_uInt8* pBuffer = 0;
+ sal_uInt32 nHeaderSize = 60;
+ sal_uInt32 nScanlineSize = pImage->width*3;
+
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+ int nRedShift, nRedSig, nRedShift2 = 0;
+ getShift( aVInfo.red_mask, nRedShift, nRedSig, nRedShift2 );
+ int nGreenShift, nGreenSig, nGreenShift2 = 0;
+ getShift( aVInfo.green_mask, nGreenShift, nGreenSig, nGreenShift2 );
+ int nBlueShift, nBlueSig, nBlueShift2 = 0;
+ getShift( aVInfo.blue_mask, nBlueShift, nBlueSig, nBlueShift2 );
+
+ // allocate buffer to hold header and scanlines, initialize to zero
+ rOutSize = nHeaderSize + nScanlineSize*pImage->height;
+ pBuffer = (sal_uInt8*)rtl_allocateZeroMemory( rOutSize );
+ for( int y = 0; y < pImage->height; y++ )
+ {
+ sal_uInt8* pScanline = pBuffer + nHeaderSize + (pImage->height-1-y)*nScanlineSize;
+ for( int x = 0; x < pImage->width; x++ )
+ {
+ unsigned long nPixel = XGetPixel( pImage, x, y );
+
+ sal_uInt8 nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.blue_mask, nBlueShift);
+ if( nBlueShift2 )
+ nValue |= (nValue >> nBlueShift2 );
+ *pScanline++ = nValue;
+
+ nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.green_mask, nGreenShift);
+ if( nGreenShift2 )
+ nValue |= (nValue >> nGreenShift2 );
+ *pScanline++ = nValue;
+
+ nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.red_mask, nRedShift);
+ if( nRedShift2 )
+ nValue |= (nValue >> nRedShift2 );
+ *pScanline++ = nValue;
+ }
+ }
+
+ // fill in header fields
+ pBuffer[ 0 ] = 'B';
+ pBuffer[ 1 ] = 'M';
+
+ writeLE( nHeaderSize, pBuffer+10 );
+ writeLE( (sal_uInt32)40, pBuffer+14 );
+ writeLE( (sal_uInt32)pImage->width, pBuffer+18 );
+ writeLE( (sal_uInt32)pImage->height, pBuffer+22 );
+ writeLE( (sal_uInt16)1, pBuffer+26 );
+ writeLE( (sal_uInt16)24, pBuffer+28 );
+ writeLE( (sal_uInt32)(DisplayWidth(pDisplay,DefaultScreen(pDisplay))*1000/DisplayWidthMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+38);
+ writeLE( (sal_uInt32)(DisplayHeight(pDisplay,DefaultScreen(pDisplay))*1000/DisplayHeightMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+42);
+
+ // done
+
+ return pBuffer;
+}
+
+sal_uInt8* x11::X11_getBmpFromPixmap(
+ Display* pDisplay,
+ Drawable aDrawable,
+ Colormap aColormap,
+ sal_Int32& rOutSize
+ )
+{
+ // get geometry of drawable
+ XLIB_Window aRoot;
+ int x,y;
+ unsigned int w, h, bw, d;
+ XGetGeometry( pDisplay, aDrawable, &aRoot, &x, &y, &w, &h, &bw, &d );
+
+ // find which screen we are on
+ int nScreenNo = ScreenCount( pDisplay );
+ while( nScreenNo-- )
+ {
+ if( RootWindow( pDisplay, nScreenNo ) == aRoot )
+ break;
+ }
+ if( nScreenNo < 0 )
+ return NULL;
+
+ if( aColormap == None )
+ aColormap = DefaultColormap( pDisplay, nScreenNo );
+
+ // get the image
+ XImage* pImage = XGetImage( pDisplay, aDrawable, 0, 0, w, h, AllPlanes, ZPixmap );
+ if( ! pImage )
+ return NULL;
+
+ sal_uInt8* pBmp = d <= 8 ?
+ X11_getPaletteBmpFromImage( pDisplay, pImage, aColormap, rOutSize ) :
+ X11_getTCBmpFromImage( pDisplay, pImage, rOutSize, nScreenNo );
+ XDestroyImage( pImage );
+
+ return pBmp;
+}
+
+void x11::X11_freeBmp( sal_uInt8* pBmp )
+{
+ rtl_freeMemory( pBmp );
+}
+
+/*
+ * PixmapHolder
+ */
+
+PixmapHolder::PixmapHolder( Display* pDisplay ) :
+ m_pDisplay( pDisplay ),
+ m_aColormap( None ),
+ m_aPixmap( None ),
+ m_aBitmap( None )
+{
+ /* try to get a 24 bit true color visual, if that fails,
+ * revert to default visual
+ */
+ if( ! XMatchVisualInfo( m_pDisplay, DefaultScreen( m_pDisplay ), 24, TrueColor, &m_aInfo ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PixmapHolder reverting to default visual\n" );
+#endif
+ Visual* pVisual = DefaultVisual( m_pDisplay, DefaultScreen( m_pDisplay ) );
+ m_aInfo.screen = DefaultScreen( m_pDisplay );
+ m_aInfo.visual = pVisual;
+ m_aInfo.visualid = pVisual->visualid;
+ m_aInfo.c_class = pVisual->c_class;
+ m_aInfo.red_mask = pVisual->red_mask;
+ m_aInfo.green_mask = pVisual->green_mask;
+ m_aInfo.blue_mask = pVisual->blue_mask;
+ m_aInfo.depth = DefaultDepth( m_pDisplay, m_aInfo.screen );
+ }
+ m_aColormap = DefaultColormap( m_pDisplay, m_aInfo.screen );
+#if OSL_DEBUG_LEVEL > 1
+ static const char* pClasses[] =
+ { "StaticGray", "GrayScale", "StaticColor", "PseudoColor", "TrueColor", "DirectColor" };
+ fprintf( stderr, "PixmapHolder visual: id = 0x%lx, class = %s (%d), depth=%d; color map = 0x%lx\n",
+ m_aInfo.visualid,
+ (m_aInfo.c_class >= 0 && unsigned(m_aInfo.c_class) < SAL_N_ELEMENTS(pClasses)) ? pClasses[m_aInfo.c_class] : "<unknown>",
+ m_aInfo.c_class,
+ m_aInfo.depth,
+ m_aColormap );
+#endif
+ if( m_aInfo.c_class == TrueColor )
+ {
+ int nRedSig, nGreenSig, nBlueSig;
+ m_nRedShift = m_nRedShift2 = 0;
+ getShift( m_aInfo.red_mask, m_nRedShift, nRedSig, m_nRedShift2 );
+ m_nGreenShift = m_nGreenShift2 = 0;
+ getShift( m_aInfo.green_mask, m_nGreenShift, nGreenSig, m_nGreenShift2 );
+ m_nBlueShift = m_nBlueShift2 = 0;
+ getShift( m_aInfo.blue_mask, m_nBlueShift, nBlueSig, m_nBlueShift2 );
+
+ m_nBlueShift2Mask = m_nBlueShift2 ? ~((unsigned long)((1<<m_nBlueShift2)-1)) : ~0L;
+ m_nGreenShift2Mask = m_nGreenShift2 ? ~((unsigned long)((1<<m_nGreenShift2)-1)) : ~0L;
+ m_nRedShift2Mask = m_nRedShift2 ? ~((unsigned long)((1<<m_nRedShift2)-1)) : ~0L;
+ }
+}
+
+PixmapHolder::~PixmapHolder()
+{
+ if( m_aPixmap != None )
+ XFreePixmap( m_pDisplay, m_aPixmap );
+ if( m_aBitmap != None )
+ XFreePixmap( m_pDisplay, m_aBitmap );
+}
+
+unsigned long PixmapHolder::getTCPixel( sal_uInt8 r, sal_uInt8 g, sal_uInt8 b ) const
+{
+ unsigned long nPixel = 0;
+ unsigned long nValue = (unsigned long)b;
+ nValue &= m_nBlueShift2Mask;
+ nPixel |= doLeftShift( nValue, m_nBlueShift );
+
+ nValue = (unsigned long)g;
+ nValue &= m_nGreenShift2Mask;
+ nPixel |= doLeftShift( nValue, m_nGreenShift );
+
+ nValue = (unsigned long)r;
+ nValue &= m_nRedShift2Mask;
+ nPixel |= doLeftShift( nValue, m_nRedShift );
+
+ return nPixel;
+}
+
+void PixmapHolder::setBitmapDataPalette( const sal_uInt8* pData, XImage* pImage )
+{
+ // setup palette
+ XColor aPalette[256];
+
+ sal_uInt32 nColors = readLE32( pData+32 );
+ sal_uInt32 nWidth = readLE32( pData+4 );
+ sal_uInt32 nHeight = readLE32( pData+8 );
+ sal_uInt16 nDepth = readLE16( pData+14 );
+
+ for( sal_uInt16 i = 0 ; i < nColors; i++ )
+ {
+ if( m_aInfo.c_class != TrueColor )
+ {
+ aPalette[i].red = ((unsigned short)pData[42 + i*4]) << 8 | ((unsigned short)pData[42 + i*4]);
+ aPalette[i].green = ((unsigned short)pData[41 + i*4]) << 8 | ((unsigned short)pData[41 + i*4]);
+ aPalette[i].blue = ((unsigned short)pData[40 + i*4]) << 8 | ((unsigned short)pData[40 + i*4]);
+ XAllocColor( m_pDisplay, m_aColormap, aPalette+i );
+ }
+ else
+ aPalette[i].pixel = getTCPixel( pData[42+i*4], pData[41+i*4], pData[40+i*4] );
+ }
+ const sal_uInt8* pBMData = pData + readLE32( pData ) + 4*nColors;
+
+ sal_uInt32 nScanlineSize = 0;
+ switch( nDepth )
+ {
+ case 1:
+ nScanlineSize = (nWidth+31)/32;
+ break;
+ case 4:
+ nScanlineSize = (nWidth+1)/2;
+ break;
+ case 8:
+ nScanlineSize = nWidth;
+ break;
+ }
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+
+ // allocate buffer to hold header and scanlines, initialize to zero
+ for( unsigned int y = 0; y < nHeight; y++ )
+ {
+ const sal_uInt8* pScanline = pBMData + (nHeight-1-y)*nScanlineSize;
+ for( unsigned int x = 0; x < nWidth; x++ )
+ {
+ int nCol = 0;
+ switch( nDepth )
+ {
+ case 1: nCol = (pScanline[ x/8 ] & (0x80 >> (x&7))) != 0 ? 0 : 1; break;
+ case 4:
+ if( x & 1 )
+ nCol = (int)(pScanline[ x/2 ] >> 4);
+ else
+ nCol = (int)(pScanline[ x/2 ] & 0x0f);
+ break;
+ case 8: nCol = (int)pScanline[x];
+ }
+ XPutPixel( pImage, x, y, aPalette[nCol].pixel );
+ }
+ }
+}
+
+void PixmapHolder::setBitmapDataTCDither( const sal_uInt8* pData, XImage* pImage )
+{
+ XColor aPalette[216];
+
+ int nNonAllocs = 0;
+
+ for( int r = 0; r < 6; r++ )
+ {
+ for( int g = 0; g < 6; g++ )
+ {
+ for( int b = 0; b < 6; b++ )
+ {
+ int i = r*36+g*6+b;
+ aPalette[i].red = r == 5 ? 0xffff : r*10922;
+ aPalette[i].green = g == 5 ? 0xffff : g*10922;
+ aPalette[i].blue = b == 5 ? 0xffff : b*10922;
+ aPalette[i].pixel = 0;
+ if( ! XAllocColor( m_pDisplay, m_aColormap, aPalette+i ) )
+ nNonAllocs++;
+ }
+ }
+ }
+
+ if( nNonAllocs )
+ {
+ XColor aRealPalette[256];
+ int nColors = 1 << m_aInfo.depth;
+ int i;
+ for( i = 0; i < nColors; i++ )
+ aRealPalette[i].pixel = (unsigned long)i;
+ XQueryColors( m_pDisplay, m_aColormap, aRealPalette, nColors );
+ for( i = 0; i < nColors; i++ )
+ {
+ sal_uInt8 nIndex =
+ 36*(sal_uInt8)(aRealPalette[i].red/10923) +
+ 6*(sal_uInt8)(aRealPalette[i].green/10923) +
+ (sal_uInt8)(aRealPalette[i].blue/10923);
+ if( aPalette[nIndex].pixel == 0 )
+ aPalette[nIndex] = aRealPalette[i];
+ }
+ }
+
+ sal_uInt32 nWidth = readLE32( pData+4 );
+ sal_uInt32 nHeight = readLE32( pData+8 );
+
+ const sal_uInt8* pBMData = pData + readLE32( pData );
+ sal_uInt32 nScanlineSize = nWidth*3;
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+
+ for( int y = 0; y < (int)nHeight; y++ )
+ {
+ const sal_uInt8* pScanline = pBMData + (nHeight-1-(sal_uInt32)y)*nScanlineSize;
+ for( int x = 0; x < (int)nWidth; x++ )
+ {
+ sal_uInt8 b = pScanline[3*x];
+ sal_uInt8 g = pScanline[3*x+1];
+ sal_uInt8 r = pScanline[3*x+2];
+ sal_uInt8 i = 36*(r/43) + 6*(g/43) + (b/43);
+
+ XPutPixel( pImage, x, y, aPalette[ i ].pixel );
+ }
+ }
+}
+
+void PixmapHolder::setBitmapDataTC( const sal_uInt8* pData, XImage* pImage )
+{
+ sal_uInt32 nWidth = readLE32( pData+4 );
+ sal_uInt32 nHeight = readLE32( pData+8 );
+
+ const sal_uInt8* pBMData = pData + readLE32( pData );
+ sal_uInt32 nScanlineSize = nWidth*3;
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+
+ for( int y = 0; y < (int)nHeight; y++ )
+ {
+ const sal_uInt8* pScanline = pBMData + (nHeight-1-(sal_uInt32)y)*nScanlineSize;
+ for( int x = 0; x < (int)nWidth; x++ )
+ {
+ unsigned long nPixel = getTCPixel( pScanline[3*x+2], pScanline[3*x+1], pScanline[3*x] );
+ XPutPixel( pImage, x, y, nPixel );
+ }
+ }
+}
+
+bool PixmapHolder::needsConversion( const sal_uInt8* pData )
+{
+ if( pData[0] != 'B' || pData[1] != 'M' )
+ return true;
+
+ pData = pData+14;
+ sal_uInt32 nDepth = readLE32( pData+14 );
+ if( nDepth == 24 )
+ {
+ if( m_aInfo.c_class != TrueColor )
+ return true;
+ }
+ else if( nDepth != (sal_uInt32)m_aInfo.depth )
+ {
+ if( m_aInfo.c_class != TrueColor )
+ return true;
+ }
+
+ return false;
+}
+
+Pixmap PixmapHolder::setBitmapData( const sal_uInt8* pData )
+{
+ if( pData[0] != 'B' || pData[1] != 'M' )
+ return None;
+
+ pData = pData+14;
+
+ // reject compressed data
+ if( readLE32( pData + 16 ) != 0 )
+ return None;
+
+ sal_uInt32 nWidth = readLE32( pData+4 );
+ sal_uInt32 nHeight = readLE32( pData+8 );
+
+ if( m_aPixmap != None )
+ XFreePixmap( m_pDisplay, m_aPixmap ), m_aPixmap = None;
+ if( m_aBitmap != None )
+ XFreePixmap( m_pDisplay, m_aBitmap ), m_aBitmap = None;
+
+ m_aPixmap = XCreatePixmap( m_pDisplay,
+ RootWindow( m_pDisplay, m_aInfo.screen ),
+ nWidth, nHeight, m_aInfo.depth );
+
+ if( m_aPixmap != None )
+ {
+ XImage aImage;
+ aImage.width = (int)nWidth;
+ aImage.height = (int)nHeight;
+ aImage.xoffset = 0;
+ aImage.format = ZPixmap;
+ aImage.data = NULL;
+ aImage.byte_order = ImageByteOrder( m_pDisplay );
+ aImage.bitmap_unit = BitmapUnit( m_pDisplay );
+ aImage.bitmap_bit_order = BitmapBitOrder( m_pDisplay );
+ aImage.bitmap_pad = BitmapPad( m_pDisplay );
+ aImage.depth = m_aInfo.depth;
+ aImage.red_mask = m_aInfo.red_mask;
+ aImage.green_mask = m_aInfo.green_mask;
+ aImage.blue_mask = m_aInfo.blue_mask;
+ aImage.bytes_per_line = 0; // filled in by XInitImage
+ if( m_aInfo.depth <= 8 )
+ aImage.bits_per_pixel = m_aInfo.depth;
+ else
+ aImage.bits_per_pixel = 8*((m_aInfo.depth+7)/8);
+ aImage.obdata = NULL;
+
+ XInitImage( &aImage );
+ aImage.data = (char*)rtl_allocateMemory( nHeight*aImage.bytes_per_line );
+
+ if( readLE32( pData+14 ) == 24 )
+ {
+ if( m_aInfo.c_class == TrueColor )
+ setBitmapDataTC( pData, &aImage );
+ else
+ setBitmapDataTCDither( pData, &aImage );
+ }
+ else
+ setBitmapDataPalette( pData, &aImage );
+
+ // put the image
+ XPutImage( m_pDisplay,
+ m_aPixmap,
+ DefaultGC( m_pDisplay, m_aInfo.screen ),
+ &aImage,
+ 0, 0,
+ 0, 0,
+ nWidth, nHeight );
+
+ // clean up
+ rtl_freeMemory( aImage.data );
+
+ // prepare bitmap (mask)
+ m_aBitmap = XCreatePixmap( m_pDisplay,
+ RootWindow( m_pDisplay, m_aInfo.screen ),
+ nWidth, nHeight, 1 );
+ XGCValues aVal;
+ aVal.function = GXcopy;
+ aVal.foreground = 0xffffffff;
+ GC aGC = XCreateGC( m_pDisplay, m_aBitmap, GCFunction | GCForeground, &aVal );
+ XFillRectangle( m_pDisplay, m_aBitmap, aGC, 0, 0, nWidth, nHeight );
+ XFreeGC( m_pDisplay, aGC );
+ }
+
+ return m_aPixmap;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/bmp.hxx b/vcl/unx/generic/dtrans/bmp.hxx
new file mode 100644
index 000000000000..6d2e76bae0bb
--- /dev/null
+++ b/vcl/unx/generic/dtrans/bmp.hxx
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _DTRANS_BMP_HXX_
+#define _DTRANS_BMP_HXX_
+
+#include "tools/prex.h"
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include "tools/postx.h"
+
+#include <sal/types.h>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <cppuhelper/compbase1.hxx>
+
+
+
+namespace x11 {
+
+// helper methods
+sal_uInt8* X11_getBmpFromPixmap( Display* pDisplay,
+ Drawable aDrawable,
+ Colormap aColormap,
+ sal_Int32& rOutSize );
+
+void X11_freeBmp( sal_uInt8* pBmp );
+
+class PixmapHolder
+{
+ Display* m_pDisplay;
+ Colormap m_aColormap;
+ Pixmap m_aPixmap;
+ Pixmap m_aBitmap;
+ XVisualInfo m_aInfo;
+
+ int m_nRedShift, m_nRedShift2;
+ int m_nGreenShift, m_nGreenShift2;
+ int m_nBlueShift, m_nBlueShift2;
+ unsigned long m_nBlueShift2Mask, m_nRedShift2Mask, m_nGreenShift2Mask;
+
+ // these expect data pointers to bitmapinfo header
+ void setBitmapDataTC( const sal_uInt8* pData, XImage* pImage );
+ void setBitmapDataTCDither( const sal_uInt8* pData, XImage* pImage );
+ void setBitmapDataPalette( const sal_uInt8* pData, XImage* pImage );
+
+ unsigned long getTCPixel( sal_uInt8 r, sal_uInt8 g, sal_uInt8 b ) const;
+public:
+ PixmapHolder( Display* pDisplay );
+ ~PixmapHolder();
+
+ // accepts bitmap file (including bitmap file header)
+ Pixmap setBitmapData( const sal_uInt8* pData );
+ bool needsConversion( const sal_uInt8* pData );
+
+ Colormap getColormap() const { return m_aColormap; }
+ Pixmap getPixmap() const { return m_aPixmap; }
+ Pixmap getBitmap() const { return m_aBitmap; }
+ VisualID getVisualID() const { return m_aInfo.visualid; }
+ int getClass() const { return m_aInfo.c_class; }
+ int getDepth() const { return m_aInfo.depth; }
+};
+
+class BmpTransporter :
+ public cppu::WeakImplHelper1< com::sun::star::awt::XBitmap >
+{
+ com::sun::star::uno::Sequence<sal_Int8> m_aBM;
+ com::sun::star::awt::Size m_aSize;
+public:
+ BmpTransporter( const com::sun::star::uno::Sequence<sal_Int8>& rBmp );
+ virtual ~BmpTransporter();
+
+ virtual com::sun::star::awt::Size SAL_CALL getSize() throw();
+ virtual com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getDIB() throw();
+ virtual com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getMaskDIB() throw();
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/config.cxx b/vcl/unx/generic/dtrans/config.cxx
new file mode 100644
index 000000000000..5f711da47434
--- /dev/null
+++ b/vcl/unx/generic/dtrans/config.cxx
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <cstdio>
+#include <unotools/configitem.hxx>
+
+#include "X11_selection.hxx"
+
+#define SETTINGS_CONFIGNODE "VCL/Settings/Transfer"
+#define SELECTION_PROPERTY "SelectionTimeout"
+
+namespace x11
+{
+
+class DtransX11ConfigItem : public ::utl::ConfigItem
+{
+ sal_Int32 m_nSelectionTimeout;
+
+ virtual void Notify( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rPropertyNames );
+ virtual void Commit();
+public:
+ DtransX11ConfigItem();
+ virtual ~DtransX11ConfigItem();
+
+ sal_Int32 getSelectionTimeout() const { return m_nSelectionTimeout; }
+};
+
+}
+
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace x11;
+
+using ::rtl::OUString;
+
+sal_Int32 SelectionManager::getSelectionTimeout()
+{
+ if( m_nSelectionTimeout < 1 )
+ {
+ DtransX11ConfigItem aCfg;
+ m_nSelectionTimeout = aCfg.getSelectionTimeout();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "initialized selection timeout to %" SAL_PRIdINT32 " seconds\n", m_nSelectionTimeout );
+#endif
+ }
+ return m_nSelectionTimeout;
+}
+
+/*
+ * DtransX11ConfigItem constructor
+ */
+
+DtransX11ConfigItem::DtransX11ConfigItem() :
+ ConfigItem( OUString( RTL_CONSTASCII_USTRINGPARAM( SETTINGS_CONFIGNODE ) ),
+ CONFIG_MODE_DELAYED_UPDATE ),
+ m_nSelectionTimeout( 3 )
+{
+ if( IsValidConfigMgr() )
+ {
+ Sequence< OUString > aKeys( 1 );
+ aKeys.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( SELECTION_PROPERTY ) );
+ Sequence< Any > aValues = GetProperties( aKeys );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %" SAL_PRIdINT32 " properties for %s\n", aValues.getLength(), SELECTION_PROPERTY );
+#endif
+ Any* pValue = aValues.getArray();
+ for( int i = 0; i < aValues.getLength(); i++, pValue++ )
+ {
+ if( pValue->getValueTypeClass() == TypeClass_STRING )
+ {
+ const OUString* pLine = (const OUString*)pValue->getValue();
+ if( pLine->getLength() )
+ {
+ m_nSelectionTimeout = pLine->toInt32();
+ if( m_nSelectionTimeout < 1 )
+ m_nSelectionTimeout = 1;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found SelectionTimeout \"%s\"\n",
+ OUStringToOString( *pLine, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "found SelectionTimeout of type \"%s\"\n",
+ OUStringToOString( pValue->getValueType().getTypeName(), osl_getThreadTextEncoding() ).getStr() );
+#endif
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "no valid configmanager, could not read timeout setting\n" );
+#endif
+}
+
+/*
+ * DtransX11ConfigItem destructor
+ */
+
+DtransX11ConfigItem::~DtransX11ConfigItem()
+{
+}
+
+/*
+ * DtransX11ConfigItem::Commit
+ */
+
+void DtransX11ConfigItem::Commit()
+{
+ // for the clipboard service this is readonly, so
+ // there is nothing to commit
+}
+
+/*
+ * DtransX11ConfigItem::Notify
+ */
+
+void DtransX11ConfigItem::Notify( const Sequence< OUString >& /*rPropertyNames*/ )
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/copydata_curs.h b/vcl/unx/generic/dtrans/copydata_curs.h
new file mode 100644
index 000000000000..a882a541a6d7
--- /dev/null
+++ b/vcl/unx/generic/dtrans/copydata_curs.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#define copydata_curs_width 32
+#define copydata_curs_height 32
+#define copydata_curs_x_hot 1
+#define copydata_curs_y_hot 1
+static unsigned char copydata_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x10, 0xf0, 0x1f, 0x00, 0x08, 0xf0, 0x1f, 0x00, 0x10, 0xf0, 0x1e, 0x00,
+ 0xa8, 0xf2, 0x1e, 0x00, 0x50, 0x35, 0x18, 0x00, 0x00, 0xf0, 0x1e, 0x00,
+ 0x00, 0xf0, 0x1e, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/copydata_mask.h b/vcl/unx/generic/dtrans/copydata_mask.h
new file mode 100644
index 000000000000..9cd73b08d106
--- /dev/null
+++ b/vcl/unx/generic/dtrans/copydata_mask.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#define copydata_mask_width 32
+#define copydata_mask_height 32
+#define copydata_mask_x_hot 1
+#define copydata_mask_y_hot 1
+static unsigned char copydata_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x3c, 0xf8, 0x3f, 0x00,
+ 0x3c, 0xf8, 0x3f, 0x00, 0x3c, 0xf8, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00,
+ 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/linkdata_curs.h b/vcl/unx/generic/dtrans/linkdata_curs.h
new file mode 100644
index 000000000000..054ef55ef2bb
--- /dev/null
+++ b/vcl/unx/generic/dtrans/linkdata_curs.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#define linkdata_curs_width 32
+#define linkdata_curs_height 32
+#define linkdata_curs_x_hot 1
+#define linkdata_curs_y_hot 1
+static unsigned char linkdata_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x10, 0xf0, 0x1f, 0x00, 0x08, 0x70, 0x18, 0x00, 0x10, 0xf0, 0x18, 0x00,
+ 0xa8, 0x72, 0x18, 0x00, 0x50, 0x35, 0x1a, 0x00, 0x00, 0x30, 0x1f, 0x00,
+ 0x00, 0xb0, 0x1f, 0x00, 0x00, 0x70, 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/linkdata_mask.h b/vcl/unx/generic/dtrans/linkdata_mask.h
new file mode 100644
index 000000000000..429c603066dc
--- /dev/null
+++ b/vcl/unx/generic/dtrans/linkdata_mask.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#define linkdata_mask_width 32
+#define linkdata_mask_height 32
+#define linkdata_mask_x_hot 1
+#define linkdata_mask_y_hot 1
+static unsigned char linkdata_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x3c, 0xf8, 0x3f, 0x00,
+ 0x3c, 0xf8, 0x3f, 0x00, 0x3c, 0xf8, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00,
+ 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/movedata_curs.h b/vcl/unx/generic/dtrans/movedata_curs.h
new file mode 100644
index 000000000000..642bbd176e4b
--- /dev/null
+++ b/vcl/unx/generic/dtrans/movedata_curs.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#define movedata_curs_width 32
+#define movedata_curs_height 32
+#define movedata_curs_x_hot 1
+#define movedata_curs_y_hot 1
+static unsigned char movedata_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00,
+ 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00,
+ 0xa8, 0xaa, 0x00, 0x00, 0x50, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/movedata_mask.h b/vcl/unx/generic/dtrans/movedata_mask.h
new file mode 100644
index 000000000000..f06c80f1728c
--- /dev/null
+++ b/vcl/unx/generic/dtrans/movedata_mask.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#define movedata_mask_width 32
+#define movedata_mask_height 32
+#define movedata_mask_x_hot 1
+#define movedata_mask_y_hot 1
+static unsigned char movedata_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x3c, 0xe0, 0x01, 0x00,
+ 0x3c, 0xe0, 0x01, 0x00, 0x3c, 0xe0, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/nodrop_curs.h b/vcl/unx/generic/dtrans/nodrop_curs.h
new file mode 100644
index 000000000000..5c501d3876c4
--- /dev/null
+++ b/vcl/unx/generic/dtrans/nodrop_curs.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#define nodrop_curs_width 32
+#define nodrop_curs_height 32
+#define nodrop_curs_x_hot 9
+#define nodrop_curs_y_hot 9
+static unsigned char nodrop_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00,
+ 0xf8, 0x7f, 0x00, 0x00, 0x7c, 0xf8, 0x00, 0x00, 0x1c, 0xfc, 0x00, 0x00,
+ 0x1e, 0xfe, 0x01, 0x00, 0x0e, 0xdf, 0x01, 0x00, 0x8e, 0xcf, 0x01, 0x00,
+ 0xce, 0xc7, 0x01, 0x00, 0xee, 0xc3, 0x01, 0x00, 0xfe, 0xe1, 0x01, 0x00,
+ 0xfc, 0xe0, 0x00, 0x00, 0x7c, 0xf8, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00,
+ 0xf0, 0x3f, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/dtrans/nodrop_mask.h b/vcl/unx/generic/dtrans/nodrop_mask.h
new file mode 100644
index 000000000000..bd315dc28df1
--- /dev/null
+++ b/vcl/unx/generic/dtrans/nodrop_mask.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#define nodrop_mask_width 32
+#define nodrop_mask_height 32
+#define nodrop_mask_x_hot 9
+#define nodrop_mask_y_hot 9
+static unsigned char nodrop_mask_bits[] = {
+ 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00,
+ 0xfc, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x7e, 0xfe, 0x01, 0x00,
+ 0x3f, 0xff, 0x03, 0x00, 0x9f, 0xff, 0x03, 0x00, 0xdf, 0xff, 0x03, 0x00,
+ 0xff, 0xef, 0x03, 0x00, 0xff, 0xe7, 0x03, 0x00, 0xff, 0xf3, 0x03, 0x00,
+ 0xfe, 0xf9, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00,
+ 0xf8, 0x7f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/fontmanager/adobeenc.tab b/vcl/unx/generic/fontmanager/adobeenc.tab
new file mode 100644
index 000000000000..492e92f3fcf2
--- /dev/null
+++ b/vcl/unx/generic/fontmanager/adobeenc.tab
@@ -0,0 +1,1087 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+struct AdobeEncEntry {
+ sal_Unicode aUnicode;
+ sal_uInt8 aAdobeStandardCode;
+ const char* const pAdobename;
+};
+
+static const AdobeEncEntry aAdobeCodes[]=
+{
+ { 0x0041, 0101, "A" },
+ { 0x00C6, 0341, "AE" },
+ { 0x01FC, 0, "AEacute" },
+ { 0xF7E6, 0, "AEsmall" },
+ { 0x00C1, 0, "Aacute" },
+ { 0xF7E1, 0, "Aacutesmall" },
+ { 0x0102, 0, "Abreve" },
+ { 0x00C2, 0, "Acircumflex" },
+ { 0xF7E2, 0, "Acircumflexsmall" },
+ { 0xF6C9, 0, "Acute" },
+ { 0xF7B4, 0, "Acutesmall" },
+ { 0x00C4, 0, "Adieresis" },
+ { 0xF7E4, 0, "Adieresissmall" },
+ { 0x00C0, 0, "Agrave" },
+ { 0xF7E0, 0, "Agravesmall" },
+ { 0x0391, 0, "Alpha" },
+ { 0x0386, 0, "Alphatonos" },
+ { 0x0100, 0, "Amacron" },
+ { 0x0104, 0, "Aogonek" },
+ { 0x00C5, 0, "Aring" },
+ { 0x01FA, 0, "Aringacute" },
+ { 0xF7E5, 0, "Aringsmall" },
+ { 0xF761, 0, "Asmall" },
+ { 0x00C3, 0, "Atilde" },
+ { 0xF7E3, 0, "Atildesmall" },
+ { 0x0042, 0102, "B" },
+ { 0x0392, 0, "Beta" },
+ { 0xF6F4, 0, "Brevesmall" },
+ { 0xF762, 0, "Bsmall" },
+ { 0x0043, 0103, "C" },
+ { 0x0106, 0, "Cacute" },
+ { 0xF6CA, 0, "Caron" },
+ { 0xF6F5, 0, "Caronsmall" },
+ { 0x010C, 0, "Ccaron" },
+ { 0x00C7, 0, "Ccedilla" },
+ { 0xF7E7, 0, "Ccedillasmall" },
+ { 0x0108, 0, "Ccircumflex" },
+ { 0x010A, 0, "Cdotaccent" },
+ { 0xF7B8, 0, "Cedillasmall" },
+ { 0x03A7, 0, "Chi" },
+ { 0xF6F6, 0, "Circumflexsmall" },
+ { 0xF763, 0, "Csmall" },
+ { 0x0044, 0104, "D" },
+ { 0x010E, 0, "Dcaron" },
+ { 0x0110, 0, "Dcroat" },
+ { 0x2206, 0, "Delta" },
+ { 0x0394, 0, "Delta" },
+ { 0xF6CB, 0, "Dieresis" },
+ { 0xF6CC, 0, "DieresisAcute" },
+ { 0xF6CD, 0, "DieresisGrave" },
+ { 0xF7A8, 0, "Dieresissmall" },
+ { 0xF6F7, 0, "Dotaccentsmall" },
+ { 0xF764, 0, "Dsmall" },
+ { 0x0045, 0105, "E" },
+ { 0x00C9, 0, "Eacute" },
+ { 0xF7E9, 0, "Eacutesmall" },
+ { 0x0114, 0, "Ebreve" },
+ { 0x011A, 0, "Ecaron" },
+ { 0x00CA, 0, "Ecircumflex" },
+ { 0xF7EA, 0, "Ecircumflexsmall" },
+ { 0x00CB, 0, "Edieresis" },
+ { 0xF7EB, 0, "Edieresissmall" },
+ { 0x0116, 0, "Edotaccent" },
+ { 0x00C8, 0, "Egrave" },
+ { 0xF7E8, 0, "Egravesmall" },
+ { 0x0112, 0, "Emacron" },
+ { 0x014A, 0, "Eng" },
+ { 0x0118, 0, "Eogonek" },
+ { 0x0395, 0, "Epsilon" },
+ { 0x0388, 0, "Epsilontonos" },
+ { 0xF765, 0, "Esmall" },
+ { 0x0397, 0, "Eta" },
+ { 0x0389, 0, "Etatonos" },
+ { 0x00D0, 0, "Eth" },
+ { 0xF7F0, 0, "Ethsmall" },
+ { 0x20AC, 0, "Euro" },
+ { 0x0046, 0106, "F" },
+ { 0xF766, 0, "Fsmall" },
+ { 0x0047, 0107, "G" },
+ { 0x0393, 0, "Gamma" },
+ { 0x011E, 0, "Gbreve" },
+ { 0x01E6, 0, "Gcaron" },
+ { 0x011C, 0, "Gcircumflex" },
+ { 0x0122, 0, "Gcommaaccent" },
+ { 0x0120, 0, "Gdotaccent" },
+ { 0xF6CE, 0, "Grave" },
+ { 0xF760, 0, "Gravesmall" },
+ { 0xF767, 0, "Gsmall" },
+ { 0x0048, 0110, "H" },
+ { 0x25CF, 0, "H18533" },
+ { 0x25AA, 0, "H18543" },
+ { 0x25AB, 0, "H18551" },
+ { 0x25A1, 0, "H22073" },
+ { 0x0126, 0, "Hbar" },
+ { 0x0124, 0, "Hcircumflex" },
+ { 0xF768, 0, "Hsmall" },
+ { 0xF6CF, 0, "Hungarumlaut" },
+ { 0xF6F8, 0, "Hungarumlautsmall" },
+ { 0x0049, 0111, "I" },
+ { 0x0132, 0, "IJ" },
+ { 0x00CD, 0, "Iacute" },
+ { 0xF7ED, 0, "Iacutesmall" },
+ { 0x012C, 0, "Ibreve" },
+ { 0x00CE, 0, "Icircumflex" },
+ { 0xF7EE, 0, "Icircumflexsmall" },
+ { 0x00CF, 0, "Idieresis" },
+ { 0xF7EF, 0, "Idieresissmall" },
+ { 0x0130, 0, "Idotaccent" },
+ { 0x2111, 0, "Ifraktur" },
+ { 0x00CC, 0, "Igrave" },
+ { 0xF7EC, 0, "Igravesmall" },
+ { 0x012A, 0, "Imacron" },
+ { 0x012E, 0, "Iogonek" },
+ { 0x0399, 0, "Iota" },
+ { 0x03AA, 0, "Iotadieresis" },
+ { 0x038A, 0, "Iotatonos" },
+ { 0xF769, 0, "Ismall" },
+ { 0x0128, 0, "Itilde" },
+ { 0x004A, 0112, "J" },
+ { 0x0134, 0, "Jcircumflex" },
+ { 0xF76A, 0, "Jsmall" },
+ { 0x004B, 0113, "K" },
+ { 0x039A, 0, "Kappa" },
+ { 0x0136, 0, "Kcommaaccent" },
+ { 0xF76B, 0, "Ksmall" },
+ { 0x004C, 0114, "L" },
+ { 0xF6BF, 0, "LL" },
+ { 0x0139, 0, "Lacute" },
+ { 0x039B, 0, "Lambda" },
+ { 0x013D, 0, "Lcaron" },
+ { 0x013B, 0, "Lcommaaccent" },
+ { 0x013F, 0, "Ldot" },
+ { 0x0141, 0350, "Lslash" },
+ { 0xF6F9, 0, "Lslashsmall" },
+ { 0xF76C, 0, "Lsmall" },
+ { 0x004D, 0115, "M" },
+ { 0xF6D0, 0, "Macron" },
+ { 0xF7AF, 0, "Macronsmall" },
+ { 0xF76D, 0, "Msmall" },
+ { 0x039C, 0, "Mu" },
+ { 0x004E, 0116, "N" },
+ { 0x0143, 0, "Nacute" },
+ { 0x0147, 0, "Ncaron" },
+ { 0x0145, 0, "Ncommaaccent" },
+ { 0xF76E, 0, "Nsmall" },
+ { 0x00D1, 0, "Ntilde" },
+ { 0xF7F1, 0, "Ntildesmall" },
+ { 0x039D, 0, "Nu" },
+ { 0x004F, 0117, "O" },
+ { 0x0152, 0, "OE" },
+ { 0xF6FA, 0, "OEsmall" },
+ { 0x00D3, 0, "Oacute" },
+ { 0xF7F3, 0, "Oacutesmall" },
+ { 0x014E, 0, "Obreve" },
+ { 0x00D4, 0, "Ocircumflex" },
+ { 0xF7F4, 0, "Ocircumflexsmall" },
+ { 0x00D6, 0, "Odieresis" },
+ { 0xF7F6, 0, "Odieresissmall" },
+ { 0xF6FB, 0, "Ogoneksmall" },
+ { 0x00D2, 0, "Ograve" },
+ { 0xF7F2, 0, "Ogravesmall" },
+ { 0x01A0, 0, "Ohorn" },
+ { 0x0150, 0, "Ohungarumlaut" },
+ { 0x014C, 0, "Omacron" },
+ { 0x2126, 0, "Omega" },
+ { 0x03A9, 0, "Omega" },
+ { 0x038F, 0, "Omegatonos" },
+ { 0x039F, 0, "Omicron" },
+ { 0x038C, 0, "Omicrontonos" },
+ { 0x00D8, 0351, "Oslash" },
+ { 0x01FE, 0, "Oslashacute" },
+ { 0xF7F8, 0, "Oslashsmall" },
+ { 0xF76F, 0, "Osmall" },
+ { 0x00D5, 0, "Otilde" },
+ { 0xF7F5, 0, "Otildesmall" },
+ { 0x0050, 0120, "P" },
+ { 0x03A6, 0, "Phi" },
+ { 0x03A0, 0, "Pi" },
+ { 0x03A8, 0, "Psi" },
+ { 0xF770, 0, "Psmall" },
+ { 0x0051, 0121, "Q" },
+ { 0xF771, 0, "Qsmall" },
+ { 0x0052, 0122, "R" },
+ { 0x0154, 0, "Racute" },
+ { 0x0158, 0, "Rcaron" },
+ { 0x0156, 0, "Rcommaaccent" },
+ { 0x211C, 0, "Rfraktur" },
+ { 0x03A1, 0, "Rho" },
+ { 0xF6FC, 0, "Ringsmall" },
+ { 0xF772, 0, "Rsmall" },
+ { 0x0053, 0123, "S" },
+ { 0x250C, 0, "SF010000" },
+ { 0x2514, 0, "SF020000" },
+ { 0x2510, 0, "SF030000" },
+ { 0x2518, 0, "SF040000" },
+ { 0x253C, 0, "SF050000" },
+ { 0x252C, 0, "SF060000" },
+ { 0x2534, 0, "SF070000" },
+ { 0x251C, 0, "SF080000" },
+ { 0x2524, 0, "SF090000" },
+ { 0x2500, 0, "SF100000" },
+ { 0x2502, 0, "SF110000" },
+ { 0x2561, 0, "SF190000" },
+ { 0x2562, 0, "SF200000" },
+ { 0x2556, 0, "SF210000" },
+ { 0x2555, 0, "SF220000" },
+ { 0x2563, 0, "SF230000" },
+ { 0x2551, 0, "SF240000" },
+ { 0x2557, 0, "SF250000" },
+ { 0x255D, 0, "SF260000" },
+ { 0x255C, 0, "SF270000" },
+ { 0x255B, 0, "SF280000" },
+ { 0x255E, 0, "SF360000" },
+ { 0x255F, 0, "SF370000" },
+ { 0x255A, 0, "SF380000" },
+ { 0x2554, 0, "SF390000" },
+ { 0x2569, 0, "SF400000" },
+ { 0x2566, 0, "SF410000" },
+ { 0x2560, 0, "SF420000" },
+ { 0x2550, 0, "SF430000" },
+ { 0x256C, 0, "SF440000" },
+ { 0x2567, 0, "SF450000" },
+ { 0x2568, 0, "SF460000" },
+ { 0x2564, 0, "SF470000" },
+ { 0x2565, 0, "SF480000" },
+ { 0x2559, 0, "SF490000" },
+ { 0x2558, 0, "SF500000" },
+ { 0x2552, 0, "SF510000" },
+ { 0x2553, 0, "SF520000" },
+ { 0x256B, 0, "SF530000" },
+ { 0x256A, 0, "SF540000" },
+ { 0x015A, 0, "Sacute" },
+ { 0x0160, 0, "Scaron" },
+ { 0xF6FD, 0, "Scaronsmall" },
+ { 0x015E, 0, "Scedilla" },
+ { 0xF6C1, 0, "Scedilla" },
+ { 0x015C, 0, "Scircumflex" },
+ { 0x0218, 0, "Scommaaccent" },
+ { 0x03A3, 0, "Sigma" },
+ { 0xF773, 0, "Ssmall" },
+ { 0x0054, 0124, "T" },
+ { 0x03A4, 0, "Tau" },
+ { 0x0166, 0, "Tbar" },
+ { 0x0164, 0, "Tcaron" },
+ { 0x0162, 0, "Tcommaaccent" },
+ { 0x021A, 0, "Tcommaaccent" },
+ { 0x0398, 0, "Theta" },
+ { 0x00DE, 0, "Thorn" },
+ { 0xF7FE, 0, "Thornsmall" },
+ { 0xF6FE, 0, "Tildesmall" },
+ { 0xF774, 0, "Tsmall" },
+ { 0x0055, 0125, "U" },
+ { 0x00DA, 0, "Uacute" },
+ { 0xF7FA, 0, "Uacutesmall" },
+ { 0x016C, 0, "Ubreve" },
+ { 0x00DB, 0, "Ucircumflex" },
+ { 0xF7FB, 0, "Ucircumflexsmall" },
+ { 0x00DC, 0, "Udieresis" },
+ { 0xF7FC, 0, "Udieresissmall" },
+ { 0x00D9, 0, "Ugrave" },
+ { 0xF7F9, 0, "Ugravesmall" },
+ { 0x01AF, 0, "Uhorn" },
+ { 0x0170, 0, "Uhungarumlaut" },
+ { 0x016A, 0, "Umacron" },
+ { 0x0172, 0, "Uogonek" },
+ { 0x03A5, 0, "Upsilon" },
+ { 0x03D2, 0, "Upsilon1" },
+ { 0x03AB, 0, "Upsilondieresis" },
+ { 0x038E, 0, "Upsilontonos" },
+ { 0x016E, 0, "Uring" },
+ { 0xF775, 0, "Usmall" },
+ { 0x0168, 0, "Utilde" },
+ { 0x0056, 0126, "V" },
+ { 0xF776, 0, "Vsmall" },
+ { 0x0057, 0127, "W" },
+ { 0x1E82, 0, "Wacute" },
+ { 0x0174, 0, "Wcircumflex" },
+ { 0x1E84, 0, "Wdieresis" },
+ { 0x1E80, 0, "Wgrave" },
+ { 0xF777, 0, "Wsmall" },
+ { 0x0058, 0130, "X" },
+ { 0x039E, 0, "Xi" },
+ { 0xF778, 0, "Xsmall" },
+ { 0x0059, 0131, "Y" },
+ { 0x00DD, 0, "Yacute" },
+ { 0xF7FD, 0, "Yacutesmall" },
+ { 0x0176, 0, "Ycircumflex" },
+ { 0x0178, 0, "Ydieresis" },
+ { 0xF7FF, 0, "Ydieresissmall" },
+ { 0x1EF2, 0, "Ygrave" },
+ { 0xF779, 0, "Ysmall" },
+ { 0x005A, 0132, "Z" },
+ { 0x0179, 0, "Zacute" },
+ { 0x017D, 0, "Zcaron" },
+ { 0xF6FF, 0, "Zcaronsmall" },
+ { 0x017B, 0, "Zdotaccent" },
+ { 0x0396, 0, "Zeta" },
+ { 0xF77A, 0, "Zsmall" },
+ { 0x0061, 0141, "a" },
+ { 0x00E1, 0, "aacute" },
+ { 0x0103, 0, "abreve" },
+ { 0x00E2, 0, "acircumflex" },
+ { 0x00B4, 0302, "acute" },
+ { 0x0301, 0, "acutecomb" },
+ { 0x00E4, 0, "adieresis" },
+ { 0x00E6, 0361, "ae" },
+ { 0x01FD, 0, "aeacute" },
+ { 0x2015, 0, "afii00208" },
+ { 0x0410, 0, "afii10017" },
+ { 0x0411, 0, "afii10018" },
+ { 0x0412, 0, "afii10019" },
+ { 0x0413, 0, "afii10020" },
+ { 0x0414, 0, "afii10021" },
+ { 0x0415, 0, "afii10022" },
+ { 0x0401, 0, "afii10023" },
+ { 0x0416, 0, "afii10024" },
+ { 0x0417, 0, "afii10025" },
+ { 0x0418, 0, "afii10026" },
+ { 0x0419, 0, "afii10027" },
+ { 0x041A, 0, "afii10028" },
+ { 0x041B, 0, "afii10029" },
+ { 0x041C, 0, "afii10030" },
+ { 0x041D, 0, "afii10031" },
+ { 0x041E, 0, "afii10032" },
+ { 0x041F, 0, "afii10033" },
+ { 0x0420, 0, "afii10034" },
+ { 0x0421, 0, "afii10035" },
+ { 0x0422, 0, "afii10036" },
+ { 0x0423, 0, "afii10037" },
+ { 0x0424, 0, "afii10038" },
+ { 0x0425, 0, "afii10039" },
+ { 0x0426, 0, "afii10040" },
+ { 0x0427, 0, "afii10041" },
+ { 0x0428, 0, "afii10042" },
+ { 0x0429, 0, "afii10043" },
+ { 0x042A, 0, "afii10044" },
+ { 0x042B, 0, "afii10045" },
+ { 0x042C, 0, "afii10046" },
+ { 0x042D, 0, "afii10047" },
+ { 0x042E, 0, "afii10048" },
+ { 0x042F, 0, "afii10049" },
+ { 0x0490, 0, "afii10050" },
+ { 0x0402, 0, "afii10051" },
+ { 0x0403, 0, "afii10052" },
+ { 0x0404, 0, "afii10053" },
+ { 0x0405, 0, "afii10054" },
+ { 0x0406, 0, "afii10055" },
+ { 0x0407, 0, "afii10056" },
+ { 0x0408, 0, "afii10057" },
+ { 0x0409, 0, "afii10058" },
+ { 0x040A, 0, "afii10059" },
+ { 0x040B, 0, "afii10060" },
+ { 0x040C, 0, "afii10061" },
+ { 0x040E, 0, "afii10062" },
+ { 0xF6C4, 0, "afii10063" },
+ { 0xF6C5, 0, "afii10064" },
+ { 0x0430, 0, "afii10065" },
+ { 0x0431, 0, "afii10066" },
+ { 0x0432, 0, "afii10067" },
+ { 0x0433, 0, "afii10068" },
+ { 0x0434, 0, "afii10069" },
+ { 0x0435, 0, "afii10070" },
+ { 0x0451, 0, "afii10071" },
+ { 0x0436, 0, "afii10072" },
+ { 0x0437, 0, "afii10073" },
+ { 0x0438, 0, "afii10074" },
+ { 0x0439, 0, "afii10075" },
+ { 0x043A, 0, "afii10076" },
+ { 0x043B, 0, "afii10077" },
+ { 0x043C, 0, "afii10078" },
+ { 0x043D, 0, "afii10079" },
+ { 0x043E, 0, "afii10080" },
+ { 0x043F, 0, "afii10081" },
+ { 0x0440, 0, "afii10082" },
+ { 0x0441, 0, "afii10083" },
+ { 0x0442, 0, "afii10084" },
+ { 0x0443, 0, "afii10085" },
+ { 0x0444, 0, "afii10086" },
+ { 0x0445, 0, "afii10087" },
+ { 0x0446, 0, "afii10088" },
+ { 0x0447, 0, "afii10089" },
+ { 0x0448, 0, "afii10090" },
+ { 0x0449, 0, "afii10091" },
+ { 0x044A, 0, "afii10092" },
+ { 0x044B, 0, "afii10093" },
+ { 0x044C, 0, "afii10094" },
+ { 0x044D, 0, "afii10095" },
+ { 0x044E, 0, "afii10096" },
+ { 0x044F, 0, "afii10097" },
+ { 0x0491, 0, "afii10098" },
+ { 0x0452, 0, "afii10099" },
+ { 0x0453, 0, "afii10100" },
+ { 0x0454, 0, "afii10101" },
+ { 0x0455, 0, "afii10102" },
+ { 0x0456, 0, "afii10103" },
+ { 0x0457, 0, "afii10104" },
+ { 0x0458, 0, "afii10105" },
+ { 0x0459, 0, "afii10106" },
+ { 0x045A, 0, "afii10107" },
+ { 0x045B, 0, "afii10108" },
+ { 0x045C, 0, "afii10109" },
+ { 0x045E, 0, "afii10110" },
+ { 0x040F, 0, "afii10145" },
+ { 0x0462, 0, "afii10146" },
+ { 0x0472, 0, "afii10147" },
+ { 0x0474, 0, "afii10148" },
+ { 0xF6C6, 0, "afii10192" },
+ { 0x045F, 0, "afii10193" },
+ { 0x0463, 0, "afii10194" },
+ { 0x0473, 0, "afii10195" },
+ { 0x0475, 0, "afii10196" },
+ { 0xF6C7, 0, "afii10831" },
+ { 0xF6C8, 0, "afii10832" },
+ { 0x04D9, 0, "afii10846" },
+ { 0x200E, 0, "afii299" },
+ { 0x200F, 0, "afii300" },
+ { 0x200D, 0, "afii301" },
+ { 0x066A, 0, "afii57381" },
+ { 0x060C, 0, "afii57388" },
+ { 0x0660, 0, "afii57392" },
+ { 0x0661, 0, "afii57393" },
+ { 0x0662, 0, "afii57394" },
+ { 0x0663, 0, "afii57395" },
+ { 0x0664, 0, "afii57396" },
+ { 0x0665, 0, "afii57397" },
+ { 0x0666, 0, "afii57398" },
+ { 0x0667, 0, "afii57399" },
+ { 0x0668, 0, "afii57400" },
+ { 0x0669, 0, "afii57401" },
+ { 0x061B, 0, "afii57403" },
+ { 0x061F, 0, "afii57407" },
+ { 0x0621, 0, "afii57409" },
+ { 0x0622, 0, "afii57410" },
+ { 0x0623, 0, "afii57411" },
+ { 0x0624, 0, "afii57412" },
+ { 0x0625, 0, "afii57413" },
+ { 0x0626, 0, "afii57414" },
+ { 0x0627, 0, "afii57415" },
+ { 0x0628, 0, "afii57416" },
+ { 0x0629, 0, "afii57417" },
+ { 0x062A, 0, "afii57418" },
+ { 0x062B, 0, "afii57419" },
+ { 0x062C, 0, "afii57420" },
+ { 0x062D, 0, "afii57421" },
+ { 0x062E, 0, "afii57422" },
+ { 0x062F, 0, "afii57423" },
+ { 0x0630, 0, "afii57424" },
+ { 0x0631, 0, "afii57425" },
+ { 0x0632, 0, "afii57426" },
+ { 0x0633, 0, "afii57427" },
+ { 0x0634, 0, "afii57428" },
+ { 0x0635, 0, "afii57429" },
+ { 0x0636, 0, "afii57430" },
+ { 0x0637, 0, "afii57431" },
+ { 0x0638, 0, "afii57432" },
+ { 0x0639, 0, "afii57433" },
+ { 0x063A, 0, "afii57434" },
+ { 0x0640, 0, "afii57440" },
+ { 0x0641, 0, "afii57441" },
+ { 0x0642, 0, "afii57442" },
+ { 0x0643, 0, "afii57443" },
+ { 0x0644, 0, "afii57444" },
+ { 0x0645, 0, "afii57445" },
+ { 0x0646, 0, "afii57446" },
+ { 0x0648, 0, "afii57448" },
+ { 0x0649, 0, "afii57449" },
+ { 0x064A, 0, "afii57450" },
+ { 0x064B, 0, "afii57451" },
+ { 0x064C, 0, "afii57452" },
+ { 0x064D, 0, "afii57453" },
+ { 0x064E, 0, "afii57454" },
+ { 0x064F, 0, "afii57455" },
+ { 0x0650, 0, "afii57456" },
+ { 0x0651, 0, "afii57457" },
+ { 0x0652, 0, "afii57458" },
+ { 0x0647, 0, "afii57470" },
+ { 0x06A4, 0, "afii57505" },
+ { 0x067E, 0, "afii57506" },
+ { 0x0686, 0, "afii57507" },
+ { 0x0698, 0, "afii57508" },
+ { 0x06AF, 0, "afii57509" },
+ { 0x0679, 0, "afii57511" },
+ { 0x0688, 0, "afii57512" },
+ { 0x0691, 0, "afii57513" },
+ { 0x06BA, 0, "afii57514" },
+ { 0x06D2, 0, "afii57519" },
+ { 0x06D5, 0, "afii57534" },
+ { 0x20AA, 0, "afii57636" },
+ { 0x05BE, 0, "afii57645" },
+ { 0x05C3, 0, "afii57658" },
+ { 0x05D0, 0, "afii57664" },
+ { 0x05D1, 0, "afii57665" },
+ { 0x05D2, 0, "afii57666" },
+ { 0x05D3, 0, "afii57667" },
+ { 0x05D4, 0, "afii57668" },
+ { 0x05D5, 0, "afii57669" },
+ { 0x05D6, 0, "afii57670" },
+ { 0x05D7, 0, "afii57671" },
+ { 0x05D8, 0, "afii57672" },
+ { 0x05D9, 0, "afii57673" },
+ { 0x05DA, 0, "afii57674" },
+ { 0x05DB, 0, "afii57675" },
+ { 0x05DC, 0, "afii57676" },
+ { 0x05DD, 0, "afii57677" },
+ { 0x05DE, 0, "afii57678" },
+ { 0x05DF, 0, "afii57679" },
+ { 0x05E0, 0, "afii57680" },
+ { 0x05E1, 0, "afii57681" },
+ { 0x05E2, 0, "afii57682" },
+ { 0x05E3, 0, "afii57683" },
+ { 0x05E4, 0, "afii57684" },
+ { 0x05E5, 0, "afii57685" },
+ { 0x05E6, 0, "afii57686" },
+ { 0x05E7, 0, "afii57687" },
+ { 0x05E8, 0, "afii57688" },
+ { 0x05E9, 0, "afii57689" },
+ { 0x05EA, 0, "afii57690" },
+ { 0xFB2A, 0, "afii57694" },
+ { 0xFB2B, 0, "afii57695" },
+ { 0xFB4B, 0, "afii57700" },
+ { 0xFB1F, 0, "afii57705" },
+ { 0x05F0, 0, "afii57716" },
+ { 0x05F1, 0, "afii57717" },
+ { 0x05F2, 0, "afii57718" },
+ { 0xFB35, 0, "afii57723" },
+ { 0x05B4, 0, "afii57793" },
+ { 0x05B5, 0, "afii57794" },
+ { 0x05B6, 0, "afii57795" },
+ { 0x05BB, 0, "afii57796" },
+ { 0x05B8, 0, "afii57797" },
+ { 0x05B7, 0, "afii57798" },
+ { 0x05B0, 0, "afii57799" },
+ { 0x05B2, 0, "afii57800" },
+ { 0x05B1, 0, "afii57801" },
+ { 0x05B3, 0, "afii57802" },
+ { 0x05C2, 0, "afii57803" },
+ { 0x05C1, 0, "afii57804" },
+ { 0x05B9, 0, "afii57806" },
+ { 0x05BC, 0, "afii57807" },
+ { 0x05BD, 0, "afii57839" },
+ { 0x05BF, 0, "afii57841" },
+ { 0x05C0, 0, "afii57842" },
+ { 0x02BC, 0, "afii57929" },
+ { 0x2105, 0, "afii61248" },
+ { 0x2113, 0, "afii61289" },
+ { 0x2116, 0, "afii61352" },
+ { 0x202C, 0, "afii61573" },
+ { 0x202D, 0, "afii61574" },
+ { 0x202E, 0, "afii61575" },
+ { 0x200C, 0, "afii61664" },
+ { 0x066D, 0, "afii63167" },
+ { 0x02BD, 0, "afii64937" },
+ { 0x00E0, 0, "agrave" },
+ { 0x2135, 0, "aleph" },
+ { 0x03B1, 0, "alpha" },
+ { 0x03AC, 0, "alphatonos" },
+ { 0x0101, 0, "amacron" },
+ { 0x0026, 046, "ampersand" },
+ { 0xF726, 0, "ampersandsmall" },
+ { 0x2220, 0, "angle" },
+ { 0x2329, 0, "angleleft" },
+ { 0x232A, 0, "angleright" },
+ { 0x0387, 0, "anoteleia" },
+ { 0x0105, 0, "aogonek" },
+ { 0x2248, 0, "approxequal" },
+ { 0x00E5, 0, "aring" },
+ { 0x01FB, 0, "aringacute" },
+ { 0x2194, 0, "arrowboth" },
+ { 0x21D4, 0, "arrowdblboth" },
+ { 0x21D3, 0, "arrowdbldown" },
+ { 0x21D0, 0, "arrowdblleft" },
+ { 0x21D2, 0, "arrowdblright" },
+ { 0x21D1, 0, "arrowdblup" },
+ { 0x2193, 0, "arrowdown" },
+ { 0xF8E7, 0, "arrowhorizex" },
+ { 0x2190, 0, "arrowleft" },
+ { 0x2192, 0, "arrowright" },
+ { 0x2191, 0, "arrowup" },
+ { 0x2195, 0, "arrowupdn" },
+ { 0x21A8, 0, "arrowupdnbse" },
+ { 0xF8E6, 0, "arrowvertex" },
+ { 0x005E, 0136, "asciicircum" },
+ { 0x007E, 0176, "asciitilde" },
+ { 0x002A, 052, "asterisk" },
+ { 0x2217, 0, "asteriskmath" },
+ { 0xF6E9, 0, "asuperior" },
+ { 0x0040, 0100, "at" },
+ { 0x00E3, 0, "atilde" },
+ { 0x0062, 0142, "b" },
+ { 0x005C, 0134, "backslash" },
+ { 0x007C, 0174, "bar" },
+ { 0x03B2, 0, "beta" },
+ { 0x2588, 0, "block" },
+ { 0xF8F4, 0, "braceex" },
+ { 0x007B, 0173, "braceleft" },
+ { 0xF8F3, 0, "braceleftbt" },
+ { 0xF8F2, 0, "braceleftmid" },
+ { 0xF8F1, 0, "bracelefttp" },
+ { 0x007D, 0175, "braceright" },
+ { 0xF8FE, 0, "bracerightbt" },
+ { 0xF8FD, 0, "bracerightmid" },
+ { 0xF8FC, 0, "bracerighttp" },
+ { 0x005B, 0133, "bracketleft" },
+ { 0xF8F0, 0, "bracketleftbt" },
+ { 0xF8EF, 0, "bracketleftex" },
+ { 0xF8EE, 0, "bracketlefttp" },
+ { 0x005D, 0135, "bracketright" },
+ { 0xF8FB, 0, "bracketrightbt" },
+ { 0xF8FA, 0, "bracketrightex" },
+ { 0xF8F9, 0, "bracketrighttp" },
+ { 0x02D8, 0306, "breve" },
+ { 0x00A6, 0, "brokenbar" },
+ { 0xF6EA, 0, "bsuperior" },
+ { 0x2022, 0267, "bullet" },
+ { 0x0063, 0143, "c" },
+ { 0x0107, 0, "cacute" },
+ { 0x02C7, 0317, "caron" },
+ { 0x21B5, 0, "carriagereturn" },
+ { 0x010D, 0, "ccaron" },
+ { 0x00E7, 0, "ccedilla" },
+ { 0x0109, 0, "ccircumflex" },
+ { 0x010B, 0, "cdotaccent" },
+ { 0x00B8, 0313, "cedilla" },
+ { 0x00A2, 0242, "cent" },
+ { 0xF6DF, 0, "centinferior" },
+ { 0xF7A2, 0, "centoldstyle" },
+ { 0xF6E0, 0, "centsuperior" },
+ { 0x03C7, 0, "chi" },
+ { 0x25CB, 0, "circle" },
+ { 0x2297, 0, "circlemultiply" },
+ { 0x2295, 0, "circleplus" },
+ { 0x02C6, 0303, "circumflex" },
+ { 0x2663, 0, "club" },
+ { 0x003A, 072, "colon" },
+ { 0x20A1, 0, "colonmonetary" },
+ { 0x002C, 054, "comma" },
+ { 0xF6C3, 0, "commaaccent" },
+ { 0xF6E1, 0, "commainferior" },
+ { 0xF6E2, 0, "commasuperior" },
+ { 0x2245, 0, "congruent" },
+ { 0x00A9, 0, "copyright" },
+ { 0xF8E9, 0, "copyrightsans" },
+ { 0xF6D9, 0, "copyrightserif" },
+ { 0x00A4, 0250, "currency" },
+ { 0xF6D1, 0, "cyrBreve" },
+ { 0xF6D2, 0, "cyrFlex" },
+ { 0xF6D4, 0, "cyrbreve" },
+ { 0xF6D5, 0, "cyrflex" },
+ { 0x0064, 0144, "d" },
+ { 0x2020, 0262, "dagger" },
+ { 0x2021, 0263, "daggerdbl" },
+ { 0xF6D3, 0, "dblGrave" },
+ { 0xF6D6, 0, "dblgrave" },
+ { 0x010F, 0, "dcaron" },
+ { 0x0111, 0, "dcroat" },
+ { 0x00B0, 0, "degree" },
+ { 0x03B4, 0, "delta" },
+ { 0x2666, 0, "diamond" },
+ { 0x00A8, 0310, "dieresis" },
+ { 0xF6D7, 0, "dieresisacute" },
+ { 0xF6D8, 0, "dieresisgrave" },
+ { 0x0385, 0, "dieresistonos" },
+ { 0x00F7, 0, "divide" },
+ { 0x2593, 0, "dkshade" },
+ { 0x2584, 0, "dnblock" },
+ { 0x0024, 044, "dollar" },
+ { 0xF6E3, 0, "dollarinferior" },
+ { 0xF724, 0, "dollaroldstyle" },
+ { 0xF6E4, 0, "dollarsuperior" },
+ { 0x20AB, 0, "dong" },
+ { 0x02D9, 0307, "dotaccent" },
+ { 0x0323, 0, "dotbelowcomb" },
+ { 0x0131, 0365, "dotlessi" },
+ { 0xF6BE, 0, "dotlessj" },
+ { 0x22C5, 0, "dotmath" },
+ { 0xF6EB, 0, "dsuperior" },
+ { 0x0065, 0145, "e" },
+ { 0x00E9, 0, "eacute" },
+ { 0x0115, 0, "ebreve" },
+ { 0x011B, 0, "ecaron" },
+ { 0x00EA, 0, "ecircumflex" },
+ { 0x00EB, 0, "edieresis" },
+ { 0x0117, 0, "edotaccent" },
+ { 0x00E8, 0, "egrave" },
+ { 0x0038, 070, "eight" },
+ { 0x2088, 0, "eightinferior" },
+ { 0xF738, 0, "eightoldstyle" },
+ { 0x2078, 0, "eightsuperior" },
+ { 0x2208, 0, "element" },
+ { 0x2026, 0274, "ellipsis" },
+ { 0x0113, 0, "emacron" },
+ { 0x2014, 0320, "emdash" },
+ { 0x2205, 0, "emptyset" },
+ { 0x2013, 0261, "endash" },
+ { 0x014B, 0, "eng" },
+ { 0x0119, 0, "eogonek" },
+ { 0x03B5, 0, "epsilon" },
+ { 0x03AD, 0, "epsilontonos" },
+ { 0x003D, 075, "equal" },
+ { 0x2261, 0, "equivalence" },
+ { 0x212E, 0, "estimated" },
+ { 0xF6EC, 0, "esuperior" },
+ { 0x03B7, 0, "eta" },
+ { 0x03AE, 0, "etatonos" },
+ { 0x00F0, 0, "eth" },
+ { 0x0021, 041, "exclam" },
+ { 0x203C, 0, "exclamdbl" },
+ { 0x00A1, 0241, "exclamdown" },
+ { 0xF7A1, 0, "exclamdownsmall" },
+ { 0xF721, 0, "exclamsmall" },
+ { 0x2203, 0, "existential" },
+ { 0x0066, 0146, "f" },
+ { 0x2640, 0, "female" },
+ { 0xFB00, 0, "ff" },
+ { 0xFB03, 0, "ffi" },
+ { 0xFB04, 0, "ffl" },
+ { 0xFB01, 0256, "fi" },
+ { 0x2012, 0, "figuredash" },
+ { 0x25A0, 0, "filledbox" },
+ { 0x25AC, 0, "filledrect" },
+ { 0x0035, 065, "five" },
+ { 0x215D, 0, "fiveeighths" },
+ { 0x2085, 0, "fiveinferior" },
+ { 0xF735, 0, "fiveoldstyle" },
+ { 0x2075, 0, "fivesuperior" },
+ { 0xFB02, 0257, "fl" },
+ { 0x0192, 0246, "florin" },
+ { 0x0034, 064, "four" },
+ { 0x2084, 0, "fourinferior" },
+ { 0xF734, 0, "fouroldstyle" },
+ { 0x2074, 0, "foursuperior" },
+ { 0x2044, 0244, "fraction" },
+ { 0x2215, 0244, "fraction" },
+ { 0x20A3, 0, "franc" },
+ { 0x0067, 0147, "g" },
+ { 0x03B3, 0, "gamma" },
+ { 0x011F, 0, "gbreve" },
+ { 0x01E7, 0, "gcaron" },
+ { 0x011D, 0, "gcircumflex" },
+ { 0x0123, 0, "gcommaaccent" },
+ { 0x0121, 0, "gdotaccent" },
+ { 0x00DF, 0373, "germandbls" },
+ { 0x2207, 0, "gradient" },
+ { 0x0060, 0301, "grave" },
+ { 0x0300, 0, "gravecomb" },
+ { 0x003E, 076, "greater" },
+ { 0x2265, 0, "greaterequal" },
+ { 0x00AB, 0253, "guillemotleft" },
+ { 0x00BB, 0273, "guillemotright" },
+ { 0x2039, 0254, "guilsinglleft" },
+ { 0x203A, 0255, "guilsinglright" },
+ { 0x0068, 0150, "h" },
+ { 0x0127, 0, "hbar" },
+ { 0x0125, 0, "hcircumflex" },
+ { 0x2665, 0, "heart" },
+ { 0x0309, 0, "hookabovecomb" },
+ { 0x2302, 0, "house" },
+ { 0x02DD, 0315, "hungarumlaut" },
+ { 0x002D, 055, "hyphen" },
+ { 0x00AD, 0, "hyphen" },
+ { 0xF6E5, 0, "hypheninferior" },
+ { 0xF6E6, 0, "hyphensuperior" },
+ { 0x0069, 0151, "i" },
+ { 0x00ED, 0, "iacute" },
+ { 0x012D, 0, "ibreve" },
+ { 0x00EE, 0, "icircumflex" },
+ { 0x00EF, 0, "idieresis" },
+ { 0x00EC, 0, "igrave" },
+ { 0x0133, 0, "ij" },
+ { 0x012B, 0, "imacron" },
+ { 0x221E, 0, "infinity" },
+ { 0x222B, 0, "integral" },
+ { 0x2321, 0, "integralbt" },
+ { 0xF8F5, 0, "integralex" },
+ { 0x2320, 0, "integraltp" },
+ { 0x2229, 0, "intersection" },
+ { 0x25D8, 0, "invbullet" },
+ { 0x25D9, 0, "invcircle" },
+ { 0x263B, 0, "invsmileface" },
+ { 0x012F, 0, "iogonek" },
+ { 0x03B9, 0, "iota" },
+ { 0x03CA, 0, "iotadieresis" },
+ { 0x0390, 0, "iotadieresistonos" },
+ { 0x03AF, 0, "iotatonos" },
+ { 0xF6ED, 0, "isuperior" },
+ { 0x0129, 0, "itilde" },
+ { 0x006A, 0152, "j" },
+ { 0x0135, 0, "jcircumflex" },
+ { 0x006B, 0153, "k" },
+ { 0x03BA, 0, "kappa" },
+ { 0x0137, 0, "kcommaaccent" },
+ { 0x0138, 0, "kgreenlandic" },
+ { 0x006C, 0154, "l" },
+ { 0x013A, 0, "lacute" },
+ { 0x03BB, 0, "lambda" },
+ { 0x013E, 0, "lcaron" },
+ { 0x013C, 0, "lcommaaccent" },
+ { 0x0140, 0, "ldot" },
+ { 0x003C, 074, "less" },
+ { 0x2264, 0, "lessequal" },
+ { 0x258C, 0, "lfblock" },
+ { 0x20A4, 0, "lira" },
+ { 0xF6C0, 0, "ll" },
+ { 0x2227, 0, "logicaland" },
+ { 0x00AC, 0, "logicalnot" },
+ { 0x2228, 0, "logicalor" },
+ { 0x017F, 0, "longs" },
+ { 0x25CA, 0, "lozenge" },
+ { 0x0142, 0370, "lslash" },
+ { 0xF6EE, 0, "lsuperior" },
+ { 0x2591, 0, "ltshade" },
+ { 0x006D, 0155, "m" },
+ { 0x00AF, 0305, "macron" },
+ { 0x02C9, 0305, "macron" },
+ { 0x2642, 0, "male" },
+ { 0x2212, 0, "minus" },
+ { 0x2032, 0, "minute" },
+ { 0xF6EF, 0, "msuperior" },
+ { 0x00B5, 0, "mu" },
+ { 0x03BC, 0, "mu" },
+ { 0x00D7, 0, "multiply" },
+ { 0x266A, 0, "musicalnote" },
+ { 0x266B, 0, "musicalnotedbl" },
+ { 0x006E, 0156, "n" },
+ { 0x0144, 0, "nacute" },
+ { 0x0149, 0, "napostrophe" },
+ { 0x0148, 0, "ncaron" },
+ { 0x0146, 0, "ncommaaccent" },
+ { 0x0039, 071, "nine" },
+ { 0x2089, 0, "nineinferior" },
+ { 0xF739, 0, "nineoldstyle" },
+ { 0x2079, 0, "ninesuperior" },
+ { 0x2209, 0, "notelement" },
+ { 0x2260, 0, "notequal" },
+ { 0x2284, 0, "notsubset" },
+ { 0x207F, 0, "nsuperior" },
+ { 0x00F1, 0, "ntilde" },
+ { 0x03BD, 0, "nu" },
+ { 0x0023, 043, "numbersign" },
+ { 0x006F, 0157, "o" },
+ { 0x00F3, 0, "oacute" },
+ { 0x014F, 0, "obreve" },
+ { 0x00F4, 0, "ocircumflex" },
+ { 0x00F6, 0, "odieresis" },
+ { 0x0153, 0372, "oe" },
+ { 0x02DB, 0316, "ogonek" },
+ { 0x00F2, 0, "ograve" },
+ { 0x01A1, 0, "ohorn" },
+ { 0x0151, 0, "ohungarumlaut" },
+ { 0x014D, 0, "omacron" },
+ { 0x03C9, 0, "omega" },
+ { 0x03D6, 0, "omega1" },
+ { 0x03CE, 0, "omegatonos" },
+ { 0x03BF, 0, "omicron" },
+ { 0x03CC, 0, "omicrontonos" },
+ { 0x0031, 061, "one" },
+ { 0x2024, 0, "onedotenleader" },
+ { 0x215B, 0, "oneeighth" },
+ { 0xF6DC, 0, "onefitted" },
+ { 0x00BD, 0, "onehalf" },
+ { 0x2081, 0, "oneinferior" },
+ { 0xF731, 0, "oneoldstyle" },
+ { 0x00BC, 0, "onequarter" },
+ { 0x00B9, 0, "onesuperior" },
+ { 0x2153, 0, "onethird" },
+ { 0x25E6, 0, "openbullet" },
+ { 0x00AA, 0343, "ordfeminine" },
+ { 0x00BA, 0353, "ordmasculine" },
+ { 0x221F, 0, "orthogonal" },
+ { 0x00F8, 0371, "oslash" },
+ { 0x01FF, 0, "oslashacute" },
+ { 0xF6F0, 0, "osuperior" },
+ { 0x00F5, 0, "otilde" },
+ { 0x0070, 0160, "p" },
+ { 0x00B6, 0266, "paragraph" },
+ { 0x0028, 050, "parenleft" },
+ { 0xF8ED, 0, "parenleftbt" },
+ { 0xF8EC, 0, "parenleftex" },
+ { 0x208D, 0, "parenleftinferior" },
+ { 0x207D, 0, "parenleftsuperior" },
+ { 0xF8EB, 0, "parenlefttp" },
+ { 0x0029, 051, "parenright" },
+ { 0xF8F8, 0, "parenrightbt" },
+ { 0xF8F7, 0, "parenrightex" },
+ { 0x208E, 0, "parenrightinferior" },
+ { 0x207E, 0, "parenrightsuperior" },
+ { 0xF8F6, 0, "parenrighttp" },
+ { 0x2202, 0, "partialdiff" },
+ { 0x0025, 045, "percent" },
+ { 0x002E, 056, "period" },
+ { 0x00B7, 0264, "periodcentered" },
+ { 0x2219, 0, "periodcentered" },
+ { 0xF6E7, 0, "periodinferior" },
+ { 0xF6E8, 0, "periodsuperior" },
+ { 0x22A5, 0, "perpendicular" },
+ { 0x2030, 0275, "perthousand" },
+ { 0x20A7, 0, "peseta" },
+ { 0x03C6, 0, "phi" },
+ { 0x03D5, 0, "phi1" },
+ { 0x03C0, 0, "pi" },
+ { 0x002B, 053, "plus" },
+ { 0x00B1, 0, "plusminus" },
+ { 0x211E, 0, "prescription" },
+ { 0x220F, 0, "product" },
+ { 0x2282, 0, "propersubset" },
+ { 0x2283, 0, "propersuperset" },
+ { 0x221D, 0, "proportional" },
+ { 0x03C8, 0, "psi" },
+ { 0x0071, 0161, "q" },
+ { 0x003F, 077, "question" },
+ { 0x00BF, 0277, "questiondown" },
+ { 0xF7BF, 0, "questiondownsmall" },
+ { 0xF73F, 0, "questionsmall" },
+ { 0x0022, 042, "quotedbl" },
+ { 0x201E, 0271, "quotedblbase" },
+ { 0x201C, 0252, "quotedblleft" },
+ { 0x201D, 0272, "quotedblright" },
+ { 0x2018, 0140, "quoteleft" },
+ { 0x201B, 0, "quotereversed" },
+ { 0x2019, 047, "quoteright" },
+ { 0x201A, 0270, "quotesinglbase" },
+ { 0x0027, 0251, "quotesingle" },
+ { 0x0072, 0162, "r" },
+ { 0x0155, 0, "racute" },
+ { 0x221A, 0, "radical" },
+ { 0xF8E5, 0, "radicalex" },
+ { 0x0159, 0, "rcaron" },
+ { 0x0157, 0, "rcommaaccent" },
+ { 0x2286, 0, "reflexsubset" },
+ { 0x2287, 0, "reflexsuperset" },
+ { 0x00AE, 0, "registered" },
+ { 0xF8E8, 0, "registersans" },
+ { 0xF6DA, 0, "registerserif" },
+ { 0x2310, 0, "revlogicalnot" },
+ { 0x03C1, 0, "rho" },
+ { 0x02DA, 0312, "ring" },
+ { 0xF6F1, 0, "rsuperior" },
+ { 0x2590, 0, "rtblock" },
+ { 0xF6DD, 0, "rupiah" },
+ { 0x0073, 0163, "s" },
+ { 0x015B, 0, "sacute" },
+ { 0x0161, 0, "scaron" },
+ { 0x015F, 0, "scedilla" },
+ { 0xF6C2, 0, "scedilla" },
+ { 0x015D, 0, "scircumflex" },
+ { 0x0219, 0, "scommaaccent" },
+ { 0x2033, 0, "second" },
+ { 0x00A7, 0247, "section" },
+ { 0x003B, 073, "semicolon" },
+ { 0x0037, 067, "seven" },
+ { 0x215E, 0, "seveneighths" },
+ { 0x2087, 0, "seveninferior" },
+ { 0xF737, 0, "sevenoldstyle" },
+ { 0x2077, 0, "sevensuperior" },
+ { 0x2592, 0, "shade" },
+ { 0x03C3, 0, "sigma" },
+ { 0x03C2, 0, "sigma1" },
+ { 0x223C, 0, "similar" },
+ { 0x0036, 066, "six" },
+ { 0x2086, 0, "sixinferior" },
+ { 0xF736, 0, "sixoldstyle" },
+ { 0x2076, 0, "sixsuperior" },
+ { 0x002F, 057, "slash" },
+ { 0x263A, 0, "smileface" },
+ { 0x0020, 040, "space" },
+ { 0x00A0, 040, "space" },
+ { 0x2660, 0, "spade" },
+ { 0xF6F2, 0, "ssuperior" },
+ { 0x00A3, 0243, "sterling" },
+ { 0x220B, 0, "suchthat" },
+ { 0x2211, 0, "summation" },
+ { 0x263C, 0, "sun" },
+ { 0x0074, 0164, "t" },
+ { 0x03C4, 0, "tau" },
+ { 0x0167, 0, "tbar" },
+ { 0x0165, 0, "tcaron" },
+ { 0x0163, 0, "tcommaaccent" },
+ { 0x021B, 0, "tcommaaccent" },
+ { 0x2234, 0, "therefore" },
+ { 0x03B8, 0, "theta" },
+ { 0x03D1, 0, "theta1" },
+ { 0x00FE, 0, "thorn" },
+ { 0x0033, 063, "three" },
+ { 0x215C, 0, "threeeighths" },
+ { 0x2083, 0, "threeinferior" },
+ { 0xF733, 0, "threeoldstyle" },
+ { 0x00BE, 0, "threequarters" },
+ { 0xF6DE, 0, "threequartersemdash" },
+ { 0x00B3, 0, "threesuperior" },
+ { 0x02DC, 0304, "tilde" },
+ { 0x0303, 0, "tildecomb" },
+ { 0x0384, 0, "tonos" },
+ { 0x2122, 0, "trademark" },
+ { 0xF8EA, 0, "trademarksans" },
+ { 0xF6DB, 0, "trademarkserif" },
+ { 0x25BC, 0, "triagdn" },
+ { 0x25C4, 0, "triaglf" },
+ { 0x25BA, 0, "triagrt" },
+ { 0x25B2, 0, "triagup" },
+ { 0xF6F3, 0, "tsuperior" },
+ { 0x0032, 062, "two" },
+ { 0x2025, 0, "twodotenleader" },
+ { 0x2082, 0, "twoinferior" },
+ { 0xF732, 0, "twooldstyle" },
+ { 0x00B2, 0, "twosuperior" },
+ { 0x2154, 0, "twothirds" },
+ { 0x0075, 0165, "u" },
+ { 0x00FA, 0, "uacute" },
+ { 0x016D, 0, "ubreve" },
+ { 0x00FB, 0, "ucircumflex" },
+ { 0x00FC, 0, "udieresis" },
+ { 0x00F9, 0, "ugrave" },
+ { 0x01B0, 0, "uhorn" },
+ { 0x0171, 0, "uhungarumlaut" },
+ { 0x016B, 0, "umacron" },
+ { 0x005F, 0137, "underscore" },
+ { 0x2017, 0, "underscoredbl" },
+ { 0x222A, 0, "union" },
+ { 0x2200, 0, "universal" },
+ { 0x0173, 0, "uogonek" },
+ { 0x2580, 0, "upblock" },
+ { 0x03C5, 0, "upsilon" },
+ { 0x03CB, 0, "upsilondieresis" },
+ { 0x03B0, 0, "upsilondieresistonos" },
+ { 0x03CD, 0, "upsilontonos" },
+ { 0x016F, 0, "uring" },
+ { 0x0169, 0, "utilde" },
+ { 0x0076, 0166, "v" },
+ { 0x0077, 0167, "w" },
+ { 0x1E83, 0, "wacute" },
+ { 0x0175, 0, "wcircumflex" },
+ { 0x1E85, 0, "wdieresis" },
+ { 0x2118, 0, "weierstrass" },
+ { 0x1E81, 0, "wgrave" },
+ { 0x0078, 0170, "x" },
+ { 0x03BE, 0, "xi" },
+ { 0x0079, 0171, "y" },
+ { 0x00FD, 0, "yacute" },
+ { 0x0177, 0, "ycircumflex" },
+ { 0x00FF, 0, "ydieresis" },
+ { 0x00A5, 0245, "yen" },
+ { 0x1EF3, 0, "ygrave" },
+ { 0x007A, 0172, "z" },
+ { 0x017A, 0, "zacute" },
+ { 0x017E, 0, "zcaron" },
+ { 0x017C, 0, "zdotaccent" },
+ { 0x0030, 060, "zero" },
+ { 0x2080, 0, "zeroinferior" },
+ { 0xF730, 0, "zerooldstyle" },
+ { 0x2070, 0, "zerosuperior" },
+ { 0x03B6, 0, "zeta" }
+};
diff --git a/vcl/unx/generic/fontmanager/afm_keyword_list b/vcl/unx/generic/fontmanager/afm_keyword_list
new file mode 100755
index 000000000000..c9bb13467e3e
--- /dev/null
+++ b/vcl/unx/generic/fontmanager/afm_keyword_list
@@ -0,0 +1,62 @@
+%language=C++
+%global-table
+%null-strings
+%struct-type
+struct hash_entry { const char* name; enum parseKey eKey; };
+%%
+Ascender,ASCENDER
+Ascent,ASCENT
+B,CHARBBOX
+C,CODE
+CC,COMPCHAR
+CH,CODEHEX
+CapHeight,CAPHEIGHT
+CharWidth,CHARWIDTH
+CharacterSet,CHARACTERSET
+Characters,CHARACTERS
+Comment,COMMENT
+Descender,DESCENDER
+Descent,DESCENT
+Em,EM
+EncodingScheme,ENCODINGSCHEME
+EndCharMetrics,ENDCHARMETRICS
+EndComposites,ENDCOMPOSITES
+EndDirection,ENDDIRECTION
+EndFontMetrics,ENDFONTMETRICS
+EndKernData,ENDKERNDATA
+EndKernPairs,ENDKERNPAIRS
+EndTrackKern,ENDTRACKKERN
+FamilyName,FAMILYNAME
+FontBBox,FONTBBOX
+FontName,FONTNAME
+FullName,FULLNAME
+IsBaseFont,ISBASEFONT
+IsFixedPitch,ISFIXEDPITCH
+ItalicAngle,ITALICANGLE
+KP,KERNPAIR
+KPX,KERNPAIRXAMT
+L,LIGATURE
+MappingScheme,MAPPINGSCHEME
+MetricsSets,METRICSSETS
+N,CHARNAME
+Notice,NOTICE
+PCC,COMPCHARPIECE
+StartCharMetrics,STARTCHARMETRICS
+StartComposites,STARTCOMPOSITES
+StartDirection,STARTDIRECTION
+StartFontMetrics,STARTFONTMETRICS
+StartKernData,STARTKERNDATA
+StartKernPairs,STARTKERNPAIRS
+StartTrackKern,STARTTRACKKERN
+StdHW,STDHW
+StdVW,STDVW
+TrackKern,TRACKKERN
+UnderlinePosition,UNDERLINEPOSITION
+UnderlineThickness,UNDERLINETHICKNESS
+V,VVECTOR
+Version,VERSION
+W,XYWIDTH
+W0X,X0WIDTH
+WX,XWIDTH
+Weight,WEIGHT
+XHeight,XHEIGHT
diff --git a/vcl/unx/generic/fontmanager/fontcache.cxx b/vcl/unx/generic/fontmanager/fontcache.cxx
new file mode 100644
index 000000000000..96953ab9fc24
--- /dev/null
+++ b/vcl/unx/generic/fontmanager/fontcache.cxx
@@ -0,0 +1,817 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <cstdlib>
+#include <cstring>
+
+#include "fontcache.hxx"
+
+#include "osl/thread.h"
+
+#include "unotools/atom.hxx"
+
+#include "tools/stream.hxx"
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#if OSL_DEBUG_LEVEL >1
+#include <cstdio>
+#endif
+
+#define FONTCACHEFILE "/user/psprint/pspfontcache"
+#define CACHE_MAGIC "PspFontCacheFile format 4"
+
+using namespace std;
+using namespace psp;
+using namespace utl;
+
+using ::rtl::OUString;
+using ::rtl::OString;
+using ::rtl::OUStringToOString;
+
+/*
+ * static helpers
+ */
+
+/*
+ * FontCache constructor
+ */
+
+FontCache::FontCache()
+{
+ m_bDoFlush = false;
+ m_aCacheFile = getOfficePath( UserPath );
+ if( m_aCacheFile.Len() )
+ {
+ m_aCacheFile.AppendAscii( FONTCACHEFILE );
+ read();
+ }
+}
+
+/*
+ * FontCache destructor
+ */
+
+FontCache::~FontCache()
+{
+ clearCache();
+}
+
+/*
+ * FontCache::clearCache
+ */
+void FontCache::clearCache()
+{
+ for( FontCacheData::iterator dir_it = m_aCache.begin(); dir_it != m_aCache.end(); ++dir_it )
+ {
+ for( FontDirMap::iterator entry_it = dir_it->second.m_aEntries.begin(); entry_it != dir_it->second.m_aEntries.end(); ++entry_it )
+ {
+ for( FontCacheEntry::iterator font_it = entry_it->second.m_aEntry.begin(); font_it != entry_it->second.m_aEntry.end(); ++font_it )
+ delete *font_it;
+ }
+ }
+ m_aCache.clear();
+}
+
+/*
+ * FontCache::Commit
+ */
+
+void FontCache::flush()
+{
+ if( ! m_bDoFlush || ! m_aCacheFile.Len() )
+ return;
+
+ SvFileStream aStream;
+ aStream.Open( m_aCacheFile, STREAM_WRITE | STREAM_TRUNC );
+ if( ! (aStream.IsOpen() && aStream.IsWritable()) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FontCache::flush: opening cache file %s failed\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
+#endif
+ return;
+ }
+
+ aStream.SetLineDelimiter( LINEEND_LF );
+ aStream.WriteLine( ByteString( CACHE_MAGIC ) );
+
+ PrintFontManager& rManager( PrintFontManager::get() );
+ MultiAtomProvider* pAtoms = rManager.m_pAtoms;
+
+ for( FontCacheData::const_iterator dir_it = m_aCache.begin(); dir_it != m_aCache.end(); ++ dir_it )
+ {
+ const FontDirMap& rDir( dir_it->second.m_aEntries );
+
+ ByteString aDirectory( rManager.getDirectory( dir_it->first ) );
+ ByteString aLine( "FontCacheDirectory:" );
+ aLine.Append( ByteString::CreateFromInt64( dir_it->second.m_nTimestamp ) );
+ aLine.Append( ':' );
+ aLine.Append( aDirectory );
+ if( rDir.empty() && dir_it->second.m_bNoFiles )
+ aLine.Insert( "Empty", 0 );
+ aStream.WriteLine( aLine );
+
+ for( FontDirMap::const_iterator entry_it = rDir.begin(); entry_it != rDir.end(); ++entry_it )
+ {
+ // insert cache entries
+ const FontCacheEntry& rEntry( entry_it->second.m_aEntry );
+ if( rEntry.begin() == rEntry.end() )
+ continue;
+
+ aLine = "File:";
+ aLine.Append( ByteString( entry_it->first ) );
+ aStream.WriteLine( aLine );
+
+ int nEntrySize = entry_it->second.m_aEntry.size();
+ // write: type;nfonts
+ aLine = ByteString::CreateFromInt32( rEntry.front()->m_eType );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( nEntrySize ) );
+ aStream.WriteLine( aLine );
+
+ sal_Int32 nSubEntry = 0;
+ for( FontCacheEntry::const_iterator it = rEntry.begin(); it != rEntry.end(); ++it, nSubEntry++ )
+ {
+ /*
+ * for each font entry write:
+ * name[;name[;name]]
+ * fontnr;PSName;italic;weight;width;pitch;encoding;ascend;descend;leading;vsubst;gxw;gxh;gyw;gyh;useroverrride;embed;antialias[;{metricfile,typeflags}][;stylename]
+ */
+ if( nEntrySize > 1 )
+ nSubEntry = static_cast<const PrintFontManager::TrueTypeFontFile*>(*it)->m_nCollectionEntry;
+ else
+ nSubEntry = -1;
+
+ aLine = OUStringToOString( pAtoms->getString( ATOM_FAMILYNAME, (*it)->m_nFamilyName ), RTL_TEXTENCODING_UTF8 );
+ for( ::std::list< int >::const_iterator name_it = (*it)->m_aAliases.begin(); name_it != (*it)->m_aAliases.end(); ++name_it )
+ {
+ const OUString& rAdd( pAtoms->getString( ATOM_FAMILYNAME, *name_it ) );
+ if( rAdd.getLength() )
+ {
+ aLine.Append( ';' );
+ aLine.Append( ByteString( String( rAdd ), RTL_TEXTENCODING_UTF8 ) );
+ }
+ }
+ aStream.WriteLine( aLine );
+
+ const OUString& rPSName( pAtoms->getString( ATOM_PSNAME, (*it)->m_nPSName ) );
+ aLine = ByteString::CreateFromInt32( nSubEntry );
+ aLine.Append( ';' );
+ aLine.Append( ByteString( String( rPSName ), RTL_TEXTENCODING_UTF8 ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eItalic ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eWeight ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eWidth ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_ePitch ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aEncoding ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_nAscend ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_nDescend ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_nLeading ) );
+ aLine.Append( ';' );
+ aLine.Append( (*it)->m_bHaveVerticalSubstitutedGlyphs ? "1" : "0" );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricX.width ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricX.height ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricY.width ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricY.height ) );
+ aLine.Append( ';' );
+ aLine.Append( (*it)->m_bUserOverride ? "1" : "0" );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( 0 ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( 0 ) );
+
+ switch( (*it)->m_eType )
+ {
+ case fonttype::Type1:
+ aLine.Append( ';' );
+ aLine.Append( ByteString( static_cast<const PrintFontManager::Type1FontFile*>(*it)->m_aMetricFile ) );
+ break;
+ case fonttype::TrueType:
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( static_cast<const PrintFontManager::TrueTypeFontFile*>(*it)->m_nTypeFlags ) );
+ break;
+ default: break;
+ }
+ if( (*it)->m_aStyleName.getLength() )
+ {
+ aLine.Append( ';' );
+ aLine.Append( ByteString( String( (*it)->m_aStyleName ), RTL_TEXTENCODING_UTF8 ) );
+ }
+ aStream.WriteLine( aLine );
+ }
+ aStream.WriteLine( ByteString() );
+ }
+ }
+ m_bDoFlush = false;
+}
+
+/*
+ * FontCache::read
+ */
+
+void FontCache::read()
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ MultiAtomProvider* pAtoms = rManager.m_pAtoms;
+
+ SvFileStream aStream( m_aCacheFile, STREAM_READ );
+ if( ! aStream.IsOpen() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FontCache::read: opening cache file %s failed\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
+#endif
+ return;
+ }
+
+
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+ if( !aLine.Equals( CACHE_MAGIC ) )
+ {
+ #if OSL_DEBUG_LEVEL >1
+ fprintf( stderr, "FontCache::read: cache file %s fails magic test\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
+ #endif
+ return;
+ }
+
+ int nDir = 0;
+ FontDirMap* pDir = NULL;
+ xub_StrLen nIndex;
+ bool bKeepOnlyUserOverridden = false;
+ do
+ {
+ aStream.ReadLine( aLine );
+ if( aLine.CompareTo( "FontCacheDirectory:", 19 ) == COMPARE_EQUAL ||
+ aLine.CompareTo( "EmptyFontCacheDirectory:", 24 ) == COMPARE_EQUAL )
+ {
+ bool bEmpty = (aLine.CompareTo( "Empty", 5 ) == COMPARE_EQUAL);
+ xub_StrLen nSearchIndex = bEmpty ? 24 : 19;
+
+ OString aDir;
+ sal_Int64 nTimestamp = 0;
+ xub_StrLen nTEnd = aLine.Search( ':', nSearchIndex );
+ if( nTEnd != STRING_NOTFOUND )
+ {
+ nTimestamp = aLine.Copy( nSearchIndex, nTEnd - nSearchIndex ).ToInt64();
+ aDir = aLine.Copy( nTEnd+1 );
+ }
+ else
+ {
+ // invalid format, remove
+ pDir = NULL;
+ nDir = 0;
+ m_bDoFlush = true;
+ continue;
+ }
+
+ // is the directory modified ?
+ struct stat aStat;
+ if( stat( aDir.getStr(), &aStat ) ||
+ ! S_ISDIR(aStat.st_mode) )
+ {
+ // remove outdated cache data
+ pDir = NULL;
+ nDir = 0;
+ m_bDoFlush = true;
+ continue;
+ }
+ else
+ {
+ nDir = rManager.getDirectoryAtom( aDir, true );
+ m_aCache[ nDir ].m_nTimestamp = (sal_Int64)aStat.st_mtime;
+ m_aCache[ nDir ].m_bNoFiles = bEmpty;
+ pDir = bEmpty ? NULL : &m_aCache[ nDir ].m_aEntries;
+ bKeepOnlyUserOverridden = ((sal_Int64)aStat.st_mtime != nTimestamp);
+ m_aCache[ nDir ].m_bUserOverrideOnly = bKeepOnlyUserOverridden;
+ }
+ }
+ else if( pDir && aLine.CompareTo( "File:", 5 ) == COMPARE_EQUAL )
+ {
+ OString aFile( aLine.Copy( 5 ) );
+ aStream.ReadLine( aLine );
+
+ const char* pLine = aLine.GetBuffer();
+
+ fonttype::type eType = (fonttype::type)atoi( pLine );
+ if( eType != fonttype::TrueType &&
+ eType != fonttype::Type1 &&
+ eType != fonttype::Builtin
+ )
+ continue;
+ while( *pLine && *pLine != ';' )
+ pLine++;
+ if( *pLine != ';' )
+ continue;
+
+ pLine++;
+ sal_Int32 nFonts = atoi( pLine );
+ for( int n = 0; n < nFonts; n++ )
+ {
+ aStream.ReadLine( aLine );
+ pLine = aLine.GetBuffer();
+ int nLen = aLine.Len();
+
+ PrintFontManager::PrintFont* pFont = NULL;
+ switch( eType )
+ {
+ case fonttype::TrueType:
+ pFont = new PrintFontManager::TrueTypeFontFile();
+ break;
+ case fonttype::Type1:
+ pFont = new PrintFontManager::Type1FontFile();
+ break;
+ case fonttype::Builtin:
+ pFont = new PrintFontManager::BuiltinFont();
+ break;
+ default: break;
+ }
+
+ for( nIndex = 0; nIndex < nLen && pLine[nIndex] != ';'; nIndex++ )
+ ;
+
+ pFont->m_nFamilyName = pAtoms->getAtom( ATOM_FAMILYNAME,
+ OUString( pLine, nIndex, RTL_TEXTENCODING_UTF8 ),
+ sal_True );
+ while( nIndex < nLen )
+ {
+ xub_StrLen nLastIndex = nIndex+1;
+ for( nIndex = nLastIndex ; nIndex < nLen && pLine[nIndex] != ';'; nIndex++ )
+ ;
+ if( nIndex - nLastIndex )
+ {
+ OUString aAlias( pLine+nLastIndex, nIndex-nLastIndex, RTL_TEXTENCODING_UTF8 );
+ pFont->m_aAliases.push_back( pAtoms->getAtom( ATOM_FAMILYNAME, aAlias, sal_True ) );
+ }
+ }
+ aStream.ReadLine( aLine );
+ pLine = aLine.GetBuffer();
+ nLen = aLine.Len();
+
+ // get up to 20 token positions
+ const int nMaxTokens = 20;
+ int nTokenPos[nMaxTokens];
+ nTokenPos[0] = 0;
+ int nTokens = 1;
+ for( int i = 0; i < nLen; i++ )
+ {
+ if( pLine[i] == ';' )
+ {
+ nTokenPos[nTokens++] = i+1;
+ if( nTokens == nMaxTokens )
+ break;
+ }
+ }
+ if( nTokens < 18 )
+ {
+ delete pFont;
+ continue;
+ }
+ int nCollEntry = atoi( pLine );
+ pFont->m_nPSName = pAtoms->getAtom( ATOM_PSNAME, OUString( pLine + nTokenPos[1], nTokenPos[2]-nTokenPos[1]-1, RTL_TEXTENCODING_UTF8 ), sal_True );
+ pFont->m_eItalic = (italic::type)atoi( pLine+nTokenPos[2] );
+ pFont->m_eWeight = (weight::type)atoi( pLine+nTokenPos[3] );
+ pFont->m_eWidth = (width::type)atoi( pLine+nTokenPos[4] );
+ pFont->m_ePitch = (pitch::type)atoi( pLine+nTokenPos[5] );
+ pFont->m_aEncoding = (rtl_TextEncoding)atoi( pLine+nTokenPos[6] );
+ pFont->m_nAscend = atoi( pLine + nTokenPos[7] );
+ pFont->m_nDescend = atoi( pLine + nTokenPos[8] );
+ pFont->m_nLeading = atoi( pLine + nTokenPos[9] );
+ pFont->m_bHaveVerticalSubstitutedGlyphs
+ = (atoi( pLine + nTokenPos[10] ) != 0);
+ pFont->m_aGlobalMetricX.width
+ = atoi( pLine + nTokenPos[11] );
+ pFont->m_aGlobalMetricX.height
+ = atoi( pLine + nTokenPos[12] );
+ pFont->m_aGlobalMetricY.width
+ = atoi( pLine + nTokenPos[13] );
+ pFont->m_aGlobalMetricY.height
+ = atoi( pLine + nTokenPos[14] );
+ pFont->m_bUserOverride
+ = (atoi( pLine + nTokenPos[15] ) != 0);
+ int nStyleTokenNr = 18;
+ switch( eType )
+ {
+ case fonttype::TrueType:
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nTypeFlags = atoi( pLine + nTokenPos[18] );
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nCollectionEntry = nCollEntry;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nDirectory = nDir;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_aFontFile = aFile;
+ nStyleTokenNr++;
+ break;
+ case fonttype::Type1:
+ {
+ int nTokLen = (nTokens > 19 ) ? nTokenPos[19]-nTokenPos[18]-1 : nLen - nTokenPos[18];
+ static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_aMetricFile = OString( pLine + nTokenPos[18], nTokLen );
+ static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_nDirectory = nDir;
+ static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_aFontFile = aFile;
+ nStyleTokenNr++;
+ }
+ break;
+ case fonttype::Builtin:
+ static_cast<PrintFontManager::BuiltinFont*>(pFont)->m_nDirectory = nDir;
+ static_cast<PrintFontManager::BuiltinFont*>(pFont)->m_aMetricFile = aFile;
+ break;
+ default: break;
+ }
+ if( nTokens > nStyleTokenNr )
+ pFont->m_aStyleName = OUString::intern( pLine + nTokenPos[nStyleTokenNr],
+ nLen - nTokenPos[nStyleTokenNr],
+ RTL_TEXTENCODING_UTF8 );
+
+ bool bObsolete = false;
+ if( bKeepOnlyUserOverridden )
+ {
+ if( pFont->m_bUserOverride )
+ {
+ ByteString aFilePath = rManager.getDirectory( nDir );
+ aFilePath.Append( '/' );
+ aFilePath.Append( ByteString(aFile) );
+ struct stat aStat;
+ if( stat( aFilePath.GetBuffer(), &aStat ) ||
+ ! S_ISREG( aStat.st_mode ) ||
+ aStat.st_size < 16 )
+ {
+ bObsolete = true;
+ }
+ #if OSL_DEBUG_LEVEL > 2
+ else
+ fprintf( stderr, "keeping file %s in outdated cache entry due to user override\n",
+ aFilePath.GetBuffer() );
+ #endif
+ }
+ else
+ bObsolete = true;
+ }
+ if( bObsolete )
+ {
+ m_bDoFlush = true;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "removing obsolete font %s\n", aFile.getStr() );
+#endif
+ delete pFont;
+ continue;
+ }
+
+ FontCacheEntry& rEntry = (*pDir)[aFile].m_aEntry;
+ rEntry.push_back( pFont );
+ }
+ }
+ } while( ! aStream.IsEof() );
+}
+
+/*
+ * FontCache::updateDirTimestamp
+ */
+void FontCache::updateDirTimestamp( int nDirID )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ const OString& rDir = rManager.getDirectory( nDirID );
+
+ struct stat aStat;
+ if( ! stat( rDir.getStr(), &aStat ) )
+ m_aCache[ nDirID ].m_nTimestamp = (sal_Int64)aStat.st_mtime;
+}
+
+
+/*
+ * FontCache::copyPrintFont
+ */
+void FontCache::copyPrintFont( const PrintFontManager::PrintFont* pFrom, PrintFontManager::PrintFont* pTo ) const
+{
+ if( pFrom->m_eType != pTo->m_eType )
+ return;
+ switch( pFrom->m_eType )
+ {
+ case fonttype::TrueType:
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nDirectory;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_aFontFile = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_aFontFile;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nCollectionEntry = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nCollectionEntry;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nTypeFlags = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nTypeFlags;
+ break;
+ case fonttype::Type1:
+ static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_nDirectory;
+ static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_aFontFile = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_aFontFile;
+ static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_aMetricFile = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_aMetricFile;
+ break;
+ case fonttype::Builtin:
+ static_cast<PrintFontManager::BuiltinFont*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::BuiltinFont*>(pFrom)->m_nDirectory;
+ static_cast<PrintFontManager::BuiltinFont*>(pTo)->m_aMetricFile = static_cast<const PrintFontManager::BuiltinFont*>(pFrom)->m_aMetricFile;
+ break;
+ default: break;
+ }
+ pTo->m_nFamilyName = pFrom->m_nFamilyName;
+ pTo->m_aStyleName = pFrom->m_aStyleName;
+ pTo->m_aAliases = pFrom->m_aAliases;
+ pTo->m_nPSName = pFrom->m_nPSName;
+ pTo->m_eItalic = pFrom->m_eItalic;
+ pTo->m_eWeight = pFrom->m_eWeight;
+ pTo->m_eWidth = pFrom->m_eWidth;
+ pTo->m_ePitch = pFrom->m_ePitch;
+ pTo->m_aEncoding = pFrom->m_aEncoding;
+ pTo->m_aGlobalMetricX = pFrom->m_aGlobalMetricX;
+ pTo->m_aGlobalMetricY = pFrom->m_aGlobalMetricY;
+ pTo->m_nAscend = pFrom->m_nAscend;
+ pTo->m_nDescend = pFrom->m_nDescend;
+ pTo->m_nLeading = pFrom->m_nLeading;
+ pTo->m_nXMin = pFrom->m_nXMin;
+ pTo->m_nYMin = pFrom->m_nYMin;
+ pTo->m_nXMax = pFrom->m_nXMax;
+ pTo->m_nYMax = pFrom->m_nYMax;
+ pTo->m_bHaveVerticalSubstitutedGlyphs = pFrom->m_bHaveVerticalSubstitutedGlyphs;
+ pTo->m_bUserOverride = pFrom->m_bUserOverride;
+}
+
+/*
+ * FontCache::equalsPrintFont
+ */
+bool FontCache::equalsPrintFont( const PrintFontManager::PrintFont* pLeft, PrintFontManager::PrintFont* pRight ) const
+{
+ if( pLeft->m_eType != pRight->m_eType )
+ return false;
+ switch( pLeft->m_eType )
+ {
+ case fonttype::TrueType:
+ {
+ const PrintFontManager::TrueTypeFontFile* pLT = static_cast<const PrintFontManager::TrueTypeFontFile*>(pLeft);
+ const PrintFontManager::TrueTypeFontFile* pRT = static_cast<const PrintFontManager::TrueTypeFontFile*>(pRight);
+ if( pRT->m_nDirectory != pLT->m_nDirectory ||
+ pRT->m_aFontFile != pLT->m_aFontFile ||
+ pRT->m_nCollectionEntry != pLT->m_nCollectionEntry ||
+ pRT->m_nTypeFlags != pLT->m_nTypeFlags )
+ return false;
+ }
+ break;
+ case fonttype::Type1:
+ {
+ const PrintFontManager::Type1FontFile* pLT = static_cast<const PrintFontManager::Type1FontFile*>(pLeft);
+ const PrintFontManager::Type1FontFile* pRT = static_cast<const PrintFontManager::Type1FontFile*>(pRight);
+ if( pRT->m_nDirectory != pLT->m_nDirectory ||
+ pRT->m_aFontFile != pLT->m_aFontFile ||
+ pRT->m_aMetricFile != pLT->m_aMetricFile )
+ return false;
+ }
+ break;
+ case fonttype::Builtin:
+ {
+ const PrintFontManager::BuiltinFont* pLT = static_cast<const PrintFontManager::BuiltinFont*>(pLeft);
+ const PrintFontManager::BuiltinFont* pRT = static_cast<const PrintFontManager::BuiltinFont*>(pRight);
+ if( pRT->m_nDirectory != pLT->m_nDirectory ||
+ pRT->m_aMetricFile != pLT->m_aMetricFile )
+ return false;
+ }
+ break;
+ default: break;
+ }
+ if( pRight->m_nFamilyName != pLeft->m_nFamilyName ||
+ pRight->m_aStyleName != pLeft->m_aStyleName ||
+ pRight->m_nPSName != pLeft->m_nPSName ||
+ pRight->m_eItalic != pLeft->m_eItalic ||
+ pRight->m_eWeight != pLeft->m_eWeight ||
+ pRight->m_eWidth != pLeft->m_eWidth ||
+ pRight->m_ePitch != pLeft->m_ePitch ||
+ pRight->m_aEncoding != pLeft->m_aEncoding ||
+ pRight->m_aGlobalMetricX != pLeft->m_aGlobalMetricX ||
+ pRight->m_aGlobalMetricY != pLeft->m_aGlobalMetricY ||
+ pRight->m_nAscend != pLeft->m_nAscend ||
+ pRight->m_nDescend != pLeft->m_nDescend ||
+ pRight->m_nLeading != pLeft->m_nLeading ||
+ pRight->m_nXMin != pLeft->m_nXMin ||
+ pRight->m_nYMin != pLeft->m_nYMin ||
+ pRight->m_nXMax != pLeft->m_nXMax ||
+ pRight->m_nYMax != pLeft->m_nYMax ||
+ pRight->m_bHaveVerticalSubstitutedGlyphs != pLeft->m_bHaveVerticalSubstitutedGlyphs ||
+ pRight->m_bUserOverride != pLeft->m_bUserOverride
+ )
+ return false;
+ std::list< int >::const_iterator lit, rit;
+ for( lit = pLeft->m_aAliases.begin(), rit = pRight->m_aAliases.begin();
+ lit != pLeft->m_aAliases.end() && rit != pRight->m_aAliases.end() && (*lit) == (*rit);
+ ++lit, ++rit )
+ ;
+ return lit == pLeft->m_aAliases.end() && rit == pRight->m_aAliases.end();
+}
+
+/*
+ * FontCache::clonePrintFont
+ */
+PrintFontManager::PrintFont* FontCache::clonePrintFont( const PrintFontManager::PrintFont* pOldFont ) const
+{
+ PrintFontManager::PrintFont* pFont = NULL;
+ switch( pOldFont->m_eType )
+ {
+ case fonttype::TrueType:
+ pFont = new PrintFontManager::TrueTypeFontFile();
+ break;
+ case fonttype::Type1:
+ pFont = new PrintFontManager::Type1FontFile();
+ break;
+ case fonttype::Builtin:
+ pFont = new PrintFontManager::BuiltinFont();
+ break;
+ default: break;
+ }
+ if( pFont )
+ {
+ copyPrintFont( pOldFont, pFont );
+ }
+ return pFont;
+ }
+
+/*
+ * FontCache::getFontCacheFile
+ */
+bool FontCache::getFontCacheFile( int nDirID, const OString& rFile, list< PrintFontManager::PrintFont* >& rNewFonts ) const
+{
+ bool bSuccess = false;
+
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ if( dir != m_aCache.end() )
+ {
+ FontDirMap::const_iterator entry = dir->second.m_aEntries.find( rFile );
+ if( entry != dir->second.m_aEntries.end() )
+ {
+ for( FontCacheEntry::const_iterator font = entry->second.m_aEntry.begin(); font != entry->second.m_aEntry.end(); ++font )
+ {
+ bSuccess = true;
+ PrintFontManager::PrintFont* pFont = clonePrintFont( *font );
+ rNewFonts.push_back( pFont );
+ }
+ }
+ }
+ return bSuccess;
+}
+
+/*
+ * FontCache::updateFontCacheEntry
+ */
+void FontCache::updateFontCacheEntry( const PrintFontManager::PrintFont* pFont, bool bFlush )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+
+ OString aFile;
+ int nDirID = 0;
+ switch( pFont->m_eType )
+ {
+ case fonttype::TrueType:
+ nDirID = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_nDirectory;
+ aFile = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_aFontFile;
+ break;
+ case fonttype::Type1:
+ nDirID = static_cast<const PrintFontManager::Type1FontFile*>(pFont)->m_nDirectory;
+ aFile = static_cast<const PrintFontManager::Type1FontFile*>(pFont)->m_aFontFile;
+ break;
+ case fonttype::Builtin:
+ nDirID = static_cast<const PrintFontManager::BuiltinFont*>(pFont)->m_nDirectory;
+ aFile = static_cast<const PrintFontManager::BuiltinFont*>(pFont)->m_aMetricFile;
+ break;
+ default:
+ return;
+ }
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ FontDirMap::const_iterator entry;
+ FontCacheEntry::const_iterator font;
+ PrintFontManager::PrintFont* pCacheFont = NULL;
+
+ if( dir != m_aCache.end() )
+ {
+ entry = dir->second.m_aEntries.find( aFile );
+ if( entry != dir->second.m_aEntries.end() )
+ {
+ for( font = entry->second.m_aEntry.begin(); font != entry->second.m_aEntry.end(); ++font )
+ {
+ if( (*font)->m_eType == pFont->m_eType &&
+ ( (*font)->m_eType != fonttype::TrueType ||
+ static_cast<const PrintFontManager::TrueTypeFontFile*>(*font)->m_nCollectionEntry == static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_nCollectionEntry
+ ) )
+ break;
+ }
+ if( font != entry->second.m_aEntry.end() )
+ pCacheFont = *font;
+ }
+ }
+ else
+ createCacheDir( nDirID );
+
+ if( pCacheFont )
+ {
+ if( ! equalsPrintFont( pFont, pCacheFont ) )
+ {
+ copyPrintFont( pFont, pCacheFont );
+ m_bDoFlush = true;
+ }
+ }
+ else
+ {
+ pCacheFont = clonePrintFont( pFont );
+ m_aCache[nDirID].m_aEntries[aFile].m_aEntry.push_back( pCacheFont );
+
+ ByteString aPath = rManager.getDirectory( nDirID );
+ aPath.Append( '/' );
+ aPath.Append( ByteString( aFile ) );
+ m_bDoFlush = true;
+ }
+ if( bFlush )
+ flush();
+}
+
+/*
+ * FontCache::listDirectory
+ */
+bool FontCache::listDirectory( const OString& rDir, std::list< PrintFontManager::PrintFont* >& rNewFonts ) const
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ int nDirID = rManager.getDirectoryAtom( rDir );
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ bool bFound = (dir != m_aCache.end());
+
+ if( bFound && !dir->second.m_bNoFiles )
+ {
+ for( FontDirMap::const_iterator file = dir->second.m_aEntries.begin(); file != dir->second.m_aEntries.end(); ++file )
+ {
+ for( FontCacheEntry::const_iterator font = file->second.m_aEntry.begin(); font != file->second.m_aEntry.end(); ++font )
+ {
+ PrintFontManager::PrintFont* pFont = clonePrintFont( *font );
+ rNewFonts.push_back( pFont );
+ }
+ }
+ }
+ return bFound;
+}
+
+/*
+ * FontCache::listDirectory
+ */
+bool FontCache::scanAdditionalFiles( const OString& rDir )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ int nDirID = rManager.getDirectoryAtom( rDir );
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ bool bFound = (dir != m_aCache.end());
+
+ return (bFound && dir->second.m_bUserOverrideOnly);
+}
+
+/*
+ * FontCache::createCacheDir
+ */
+void FontCache::createCacheDir( int nDirID )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+
+ const OString& rDir = rManager.getDirectory( nDirID );
+ struct stat aStat;
+ if( ! stat( rDir.getStr(), &aStat ) )
+ m_aCache[nDirID].m_nTimestamp = (sal_Int64)aStat.st_mtime;
+}
+
+/*
+ * FontCache::markEmptyDir
+ */
+void FontCache::markEmptyDir( int nDirID, bool bNoFiles )
+{
+ createCacheDir( nDirID );
+ m_aCache[nDirID].m_bNoFiles = bNoFiles;
+ m_bDoFlush = true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/fontmanager/fontconfig.cxx b/vcl/unx/generic/fontmanager/fontconfig.cxx
new file mode 100644
index 000000000000..fe595290160a
--- /dev/null
+++ b/vcl/unx/generic/fontmanager/fontconfig.cxx
@@ -0,0 +1,1444 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 "fontcache.hxx"
+#include "impfont.hxx"
+#include "vcl/fontmanager.hxx"
+
+using namespace psp;
+
+#ifdef ENABLE_FONTCONFIG
+ #include <fontconfig/fontconfig.h>
+ #include <ft2build.h>
+ #include <fontconfig/fcfreetype.h>
+ // allow compile on baseline (currently with fontconfig 2.2.0)
+ #ifndef FC_WEIGHT_BOOK // TODO: remove when baseline moves to fc>=2.2.1
+ #define FC_WEIGHT_BOOK 75
+ #endif
+ #ifndef FC_EMBEDDED_BITMAP // TODO: remove when baseline moves to fc>=2.3.92
+ #define FC_EMBEDDED_BITMAP "embeddedbitmap"
+ #endif
+ #ifndef FC_FAMILYLANG // TODO: remove when baseline moves to fc>=2.2.97
+ #define FC_FAMILYLANG "familylang"
+ #endif
+ #ifndef FC_CAPABILITY // TODO: remove when baseline moves to fc>=2.2.97
+ #define FC_CAPABILITY "capability"
+ #endif
+ #ifndef FC_STYLELANG // TODO: remove when baseline moves to fc>=2.2.97
+ #define FC_STYLELANG "stylelang"
+ #endif
+ #ifndef FC_HINT_STYLE // TODO: remove when baseline moves to fc>=2.2.91
+ #define FC_HINT_STYLE "hintstyle"
+ #define FC_HINT_NONE 0
+ #define FC_HINT_SLIGHT 1
+ #define FC_HINT_MEDIUM 2
+ #define FC_HINT_FULL 3
+ #endif
+ #ifndef FC_FT_FACE
+ #define FC_FT_FACE "ftface"
+ #endif
+ #ifndef FC_EMBOLDEN
+ #define FC_EMBOLDEN "embolden"
+ #endif
+#else
+ typedef void FcConfig;
+ typedef void FcObjectSet;
+ typedef void FcPattern;
+ typedef void FcFontSet;
+ typedef void FcCharSet;
+ typedef int FcResult;
+ typedef int FcBool;
+ typedef int FcMatchKind;
+ typedef char FcChar8;
+ typedef int FcChar32;
+ typedef unsigned int FT_UInt;
+ typedef void* FT_Face;
+ typedef int FcSetName;
+#endif
+
+#include <cstdio>
+#include <cstdarg>
+
+#include "unotools/atom.hxx"
+
+#include "osl/module.h"
+#include "osl/thread.h"
+#include "osl/process.h"
+
+#include "rtl/ustrbuf.hxx"
+#include "rtl/locale.hxx"
+
+#include "sal/alloca.h"
+
+#include <utility>
+#include <algorithm>
+
+using namespace osl;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::rtl::OString;
+
+namespace
+{
+ typedef std::pair<FcChar8*, FcChar8*> lang_and_element;
+}
+
+class FontCfgWrapper
+{
+ oslModule m_pLib;
+ FcFontSet* m_pOutlineSet;
+
+ int m_nFcVersion;
+ FcBool (*m_pFcInit)();
+ void (*m_pFcFini)();
+ int (*m_pFcGetVersion)();
+ FcConfig* (*m_pFcConfigGetCurrent)();
+ FcObjectSet* (*m_pFcObjectSetVaBuild)(const char*,va_list);
+ void (*m_pFcObjectSetDestroy)(FcObjectSet* pSet);
+ FcPattern* (*m_pFcPatternCreate)();
+ void (*m_pFcPatternDestroy)(FcPattern*);
+ FcBool (*m_pFcPatternEqual)(const FcPattern*,const FcPattern*);
+ FcFontSet* (*m_pFcConfigGetFonts)(FcConfig*,FcSetName);
+ FcFontSet* (*m_pFcFontSetCreate)();
+ FcCharSet* (*m_pFcCharSetCreate)();
+ FcBool (*m_pFcCharSetAddChar)(FcCharSet *, FcChar32);
+ FcBool (*m_pFcCharSetHasChar)(FcCharSet *, FcChar32);
+ void (*m_pFcCharSetDestroy)(FcCharSet*);
+ void (*m_pFcFontSetDestroy)(FcFontSet*);
+ FcBool (*m_pFcFontSetAdd)(FcFontSet*,FcPattern*);
+ void (*m_pFcPatternReference)(FcPattern*);
+ FcResult (*m_pFcPatternGetCharSet)(const FcPattern*,const char*,int,FcCharSet**);
+ FcResult (*m_pFcPatternGetString)(const FcPattern*,const char*,int,FcChar8**);
+ FcResult (*m_pFcPatternGetInteger)(const FcPattern*,const char*,int,int*);
+ FcResult (*m_pFcPatternGetDouble)(const FcPattern*,const char*,int,double*);
+ FcResult (*m_pFcPatternGetBool)(const FcPattern*,const char*,int,FcBool*);
+ void (*m_pFcDefaultSubstitute)(FcPattern *);
+ FcPattern* (*m_pFcFontSetMatch)(FcConfig*,FcFontSet**, int, FcPattern*,FcResult*);
+ FcPattern* (*m_pFcFontMatch)(FcConfig*,FcPattern*,FcResult*);
+ FcBool (*m_pFcConfigAppFontAddFile)(FcConfig*, const FcChar8*);
+ FcBool (*m_pFcConfigAppFontAddDir)(FcConfig*, const FcChar8*);
+ FcBool (*m_pFcConfigParseAndLoad)(FcConfig*,const FcChar8*,FcBool);
+ FcBool (*m_pFcConfigSubstitute)(FcConfig*,FcPattern*,FcMatchKind);
+
+ FcPattern* (*m_pFcPatternDuplicate)(const FcPattern*);
+ FcBool (*m_pFcPatternAddInteger)(FcPattern*,const char*,int);
+ FcBool (*m_pFcPatternAddDouble)(FcPattern*,const char*,double);
+ FcBool (*m_pFcPatternAddBool)(FcPattern*,const char*,FcBool);
+ FcBool (*m_pFcPatternAddCharSet)(FcPattern*,const char*,const FcCharSet*);
+ FcBool (*m_pFcPatternAddString)(FcPattern*,const char*,const FcChar8*);
+ FcBool (*m_pFcPatternDel)(FcPattern*,const char*);
+
+ FT_UInt (*m_pFcFreeTypeCharIndex)(FT_Face,FcChar32);
+ FcBool (*m_pFcPatternAddFTFace)(FcPattern*,const char*,const FT_Face);
+
+ oslGenericFunction loadSymbol( const char* );
+ void addFontSet( FcSetName );
+
+ FontCfgWrapper();
+ ~FontCfgWrapper();
+
+public:
+ static FontCfgWrapper& get();
+ static void release();
+
+ bool isValid() const
+ { return m_pLib != NULL;}
+
+ FcFontSet* getFontSet();
+
+ FcBool FcInit()
+ { return m_pFcInit(); }
+
+ void FcFini()
+ {
+ //To-Do: get gtk vclplug smoketest to pass
+ //if (m_pFcFini) m_pFcFini();
+ }
+
+ int FcGetVersion()
+ { return m_pFcGetVersion(); }
+
+ FcConfig* FcConfigGetCurrent()
+ { return m_pFcConfigGetCurrent(); }
+
+ FcObjectSet* FcObjectSetBuild( const char* first, ... )
+ {
+ va_list ap;
+ va_start( ap, first );
+ FcObjectSet* pSet = m_pFcObjectSetVaBuild( first, ap );
+ va_end( ap );
+ return pSet;
+ }
+
+ void FcObjectSetDestroy( FcObjectSet* pSet )
+ { m_pFcObjectSetDestroy( pSet ); }
+
+ FcPattern* FcPatternCreate()
+ { return m_pFcPatternCreate(); }
+
+ void FcPatternDestroy( FcPattern* pPattern )
+ { if (m_pFcPatternDestroy) m_pFcPatternDestroy( pPattern ); }
+
+ FcBool FcPatternEqual( const FcPattern* pPatternA, const FcPattern *pPatternB )
+ { return m_pFcPatternEqual( pPatternA, pPatternB ); }
+
+ FcFontSet* FcConfigGetFonts( FcConfig* pConfig, FcSetName eSet)
+ { return m_pFcConfigGetFonts( pConfig, eSet ); }
+
+ FcFontSet* FcFontSetCreate()
+ { return m_pFcFontSetCreate(); }
+
+ FcCharSet* FcCharSetCreate()
+ { return m_pFcCharSetCreate(); }
+
+ FcBool FcCharSetAddChar(FcCharSet *fcs, FcChar32 ucs4)
+ { return m_pFcCharSetAddChar(fcs, ucs4); }
+
+ FcBool FcCharSetHasChar(FcCharSet *fcs, FcChar32 ucs4)
+ { return m_pFcCharSetHasChar(fcs, ucs4); }
+
+ void FcCharSetDestroy( FcCharSet* pSet )
+ { m_pFcCharSetDestroy( pSet );}
+
+ void FcFontSetDestroy( FcFontSet* pSet )
+ { m_pFcFontSetDestroy( pSet );}
+
+ FcBool FcFontSetAdd( FcFontSet* pSet, FcPattern* pPattern )
+ { return m_pFcFontSetAdd( pSet, pPattern ); }
+
+ void FcPatternReference( FcPattern* pPattern )
+ { m_pFcPatternReference( pPattern ); }
+
+ FcResult FcPatternGetCharSet( const FcPattern* pPattern, const char* object, int n, FcCharSet** s )
+ { return m_pFcPatternGetCharSet( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetString( const FcPattern* pPattern, const char* object, int n, FcChar8** s )
+ { return m_pFcPatternGetString( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetInteger( const FcPattern* pPattern, const char* object, int n, int* s )
+ { return m_pFcPatternGetInteger( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetDouble( const FcPattern* pPattern, const char* object, int n, double* s )
+ { return m_pFcPatternGetDouble( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetBool( const FcPattern* pPattern, const char* object, int n, FcBool* s )
+ { return m_pFcPatternGetBool( pPattern, object, n, s ); }
+ FcBool FcConfigAppFontAddFile( FcConfig* pConfig, const FcChar8* pFileName )
+ { return m_pFcConfigAppFontAddFile( pConfig, pFileName ); }
+ FcBool FcConfigAppFontAddDir(FcConfig* pConfig, const FcChar8* pDirName )
+ { return m_pFcConfigAppFontAddDir( pConfig, pDirName ); }
+ FcBool FcConfigParseAndLoad( FcConfig* pConfig, const FcChar8* pFileName, FcBool bComplain )
+ { return m_pFcConfigParseAndLoad( pConfig, pFileName, bComplain ); }
+
+ void FcDefaultSubstitute( FcPattern* pPattern )
+ { m_pFcDefaultSubstitute( pPattern ); }
+ FcPattern* FcFontSetMatch( FcConfig* pConfig, FcFontSet **ppFontSet, int nset, FcPattern* pPattern, FcResult* pResult )
+ { return m_pFcFontSetMatch ? m_pFcFontSetMatch( pConfig, ppFontSet, nset, pPattern, pResult ) : 0; }
+ FcPattern* FcFontMatch( FcConfig* pConfig, FcPattern* pPattern, FcResult* pResult )
+ { return m_pFcFontMatch( pConfig, pPattern, pResult ); }
+ FcBool FcConfigSubstitute( FcConfig* pConfig, FcPattern* pPattern, FcMatchKind eKind )
+ { return m_pFcConfigSubstitute( pConfig, pPattern, eKind ); }
+
+ FcPattern* FcPatternDuplicate( const FcPattern* pPattern ) const
+ { return m_pFcPatternDuplicate( pPattern ); }
+ FcBool FcPatternAddInteger( FcPattern* pPattern, const char* pObject, int nValue )
+ { return m_pFcPatternAddInteger( pPattern, pObject, nValue ); }
+ FcBool FcPatternAddDouble( FcPattern* pPattern, const char* pObject, double nValue )
+ { return m_pFcPatternAddDouble( pPattern, pObject, nValue ); }
+ FcBool FcPatternAddString( FcPattern* pPattern, const char* pObject, const FcChar8* pString )
+ { return m_pFcPatternAddString( pPattern, pObject, pString ); }
+ FcBool FcPatternAddBool( FcPattern* pPattern, const char* pObject, bool nValue )
+ { return m_pFcPatternAddBool( pPattern, pObject, nValue ); }
+ FcBool FcPatternAddCharSet(FcPattern* pPattern,const char* pObject,const FcCharSet*pCharSet)
+ { return m_pFcPatternAddCharSet(pPattern,pObject,pCharSet); }
+ FcBool FcPatternDel(FcPattern* pPattern, const char* object)
+ { return m_pFcPatternDel( pPattern, object); }
+
+ FT_UInt FcFreeTypeCharIndex( FT_Face face, FcChar32 ucs4 )
+ { return m_pFcFreeTypeCharIndex ? m_pFcFreeTypeCharIndex( face, ucs4 ) : 0; }
+ FcBool FcPatternAddFTFace( FcPattern* pPattern, const char* pObject, const FT_Face nValue )
+ {
+ return m_pFcPatternAddFTFace
+ ? m_pFcPatternAddFTFace( pPattern, pObject, nValue )
+ : false;
+ }
+public:
+ FcResult LocalizedElementFromPattern(FcPattern* pPattern, FcChar8 **family,
+ const char *elementtype, const char *elementlangtype);
+//to-do, make private and add some cleanish accessor methods
+ boost::unordered_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aFontNameToLocalized;
+ boost::unordered_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aLocalizedToCanonical;
+private:
+ void cacheLocalizedFontNames(FcChar8 *origfontname, FcChar8 *bestfontname, const std::vector< lang_and_element > &lang_and_elements);
+};
+
+oslGenericFunction FontCfgWrapper::loadSymbol( const char* pSymbol )
+{
+ OUString aSym( OUString::createFromAscii( pSymbol ) );
+ oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" );
+#endif
+ return pSym;
+}
+
+FontCfgWrapper::FontCfgWrapper()
+ : m_pLib( NULL ),
+ m_pOutlineSet( NULL ),
+ m_nFcVersion( 0 )
+{
+ OUString aLib( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so.1" ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ if( !m_pLib )
+ {
+ aLib = OUString( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so" ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ }
+
+ if( ! m_pLib )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "no libfontconfig\n" );
+#endif
+ return;
+ }
+
+ m_pFcInit = (FcBool(*)())
+ loadSymbol( "FcInit" );
+ m_pFcFini = (void(*)())
+ loadSymbol( "FcFini" );
+ m_pFcGetVersion = (int(*)())
+ loadSymbol( "FcGetVersion" );
+ m_pFcConfigGetCurrent = (FcConfig *(*)())
+ loadSymbol( "FcConfigGetCurrent" );
+ m_pFcObjectSetVaBuild = (FcObjectSet*(*)(const char*,va_list))
+ loadSymbol( "FcObjectSetVaBuild" );
+ m_pFcObjectSetDestroy = (void(*)(FcObjectSet*))
+ loadSymbol( "FcObjectSetDestroy" );
+ m_pFcPatternCreate = (FcPattern*(*)())
+ loadSymbol( "FcPatternCreate" );
+ m_pFcPatternDestroy = (void(*)(FcPattern*))
+ loadSymbol( "FcPatternDestroy" );
+ m_pFcPatternEqual = (FcBool(*)(const FcPattern*,const FcPattern*))
+ loadSymbol( "FcPatternEqual" );
+ m_pFcConfigGetFonts = (FcFontSet*(*)(FcConfig*,FcSetName))
+ loadSymbol( "FcConfigGetFonts" );
+ m_pFcFontSetCreate = (FcFontSet*(*)())
+ loadSymbol( "FcFontSetCreate" );
+ m_pFcCharSetCreate = (FcCharSet*(*)())
+ loadSymbol( "FcCharSetCreate" );
+ m_pFcCharSetAddChar = (FcBool(*)(FcCharSet*, FcChar32))
+ loadSymbol( "FcCharSetAddChar" );
+ m_pFcCharSetHasChar = (FcBool(*)(FcCharSet*, FcChar32))
+ loadSymbol( "FcCharSetHasChar" );
+ m_pFcCharSetDestroy = (void(*)(FcCharSet*))
+ loadSymbol( "FcCharSetDestroy" );
+ m_pFcFontSetDestroy = (void(*)(FcFontSet*))
+ loadSymbol( "FcFontSetDestroy" );
+ m_pFcFontSetAdd = (FcBool(*)(FcFontSet*,FcPattern*))
+ loadSymbol( "FcFontSetAdd" );
+ m_pFcPatternReference = (void(*)(FcPattern*))
+ loadSymbol( "FcPatternReference" );
+ m_pFcPatternGetCharSet = (FcResult(*)(const FcPattern*,const char*,int,FcCharSet**))
+ loadSymbol( "FcPatternGetCharSet" );
+ m_pFcPatternGetString = (FcResult(*)(const FcPattern*,const char*,int,FcChar8**))
+ loadSymbol( "FcPatternGetString" );
+ m_pFcPatternGetInteger = (FcResult(*)(const FcPattern*,const char*,int,int*))
+ loadSymbol( "FcPatternGetInteger" );
+ m_pFcPatternGetDouble = (FcResult(*)(const FcPattern*,const char*,int,double*))
+ loadSymbol( "FcPatternGetDouble" );
+ m_pFcPatternGetBool = (FcResult(*)(const FcPattern*,const char*,int,FcBool*))
+ loadSymbol( "FcPatternGetBool" );
+ m_pFcConfigAppFontAddFile = (FcBool(*)(FcConfig*, const FcChar8*))
+ loadSymbol( "FcConfigAppFontAddFile" );
+ m_pFcConfigAppFontAddDir = (FcBool(*)(FcConfig*, const FcChar8*))
+ loadSymbol( "FcConfigAppFontAddDir" );
+ m_pFcConfigParseAndLoad = (FcBool(*)(FcConfig*, const FcChar8*, FcBool))
+ loadSymbol( "FcConfigParseAndLoad" );
+ m_pFcDefaultSubstitute = (void(*)(FcPattern *))
+ loadSymbol( "FcDefaultSubstitute" );
+ m_pFcFontSetMatch = (FcPattern*(*)(FcConfig*,FcFontSet**,int,FcPattern*,FcResult*))
+ loadSymbol( "FcFontSetMatch" );
+ m_pFcFontMatch = (FcPattern*(*)(FcConfig*,FcPattern*,FcResult*))
+ loadSymbol( "FcFontMatch" );
+ m_pFcConfigSubstitute = (FcBool(*)(FcConfig*,FcPattern*,FcMatchKind))
+ loadSymbol( "FcConfigSubstitute" );
+
+ m_pFcPatternDuplicate = (FcPattern*(*)(const FcPattern*))
+ loadSymbol( "FcPatternDuplicate" );
+ m_pFcPatternAddInteger = (FcBool(*)(FcPattern*,const char*,int))
+ loadSymbol( "FcPatternAddInteger" );
+ m_pFcPatternAddDouble = (FcBool(*)(FcPattern*,const char*,double))
+ loadSymbol( "FcPatternAddDouble" );
+ m_pFcPatternAddBool = (FcBool(*)(FcPattern*,const char*,FcBool))
+ loadSymbol( "FcPatternAddBool" );
+ m_pFcPatternAddCharSet = (FcBool(*)(FcPattern*,const char*,const FcCharSet *))
+ loadSymbol( "FcPatternAddCharSet" );
+ m_pFcPatternAddString = (FcBool(*)(FcPattern*,const char*,const FcChar8*))
+ loadSymbol( "FcPatternAddString" );
+ m_pFcPatternDel = (FcBool(*)(FcPattern*,const char*))
+ loadSymbol( "FcPatternDel" );
+
+ m_pFcFreeTypeCharIndex = (FT_UInt(*)(FT_Face,FcChar32))
+ loadSymbol( "FcFreeTypeCharIndex" );
+ m_pFcPatternAddFTFace = (FcBool(*)(FcPattern*,const char*,const FT_Face))
+ loadSymbol( "FcPatternAddFTFace" );
+
+ m_nFcVersion = FcGetVersion();
+#if (OSL_DEBUG_LEVEL > 1)
+ fprintf( stderr,"FC_VERSION = %05d\n", m_nFcVersion );
+#endif
+ // make minimum version configurable
+ const char* pMinFcVersion = getenv( "SAL_MIN_FC_VERSION");
+ if( pMinFcVersion )
+ {
+ const int nMinFcVersion = atoi( pMinFcVersion );
+ if( m_nFcVersion < nMinFcVersion )
+ m_pFcInit = NULL;
+ }
+
+ if( ! (
+ m_pFcInit &&
+ m_pFcGetVersion &&
+ m_pFcConfigGetCurrent &&
+ m_pFcObjectSetVaBuild &&
+ m_pFcObjectSetDestroy &&
+ m_pFcPatternCreate &&
+ m_pFcPatternDestroy &&
+ m_pFcPatternEqual &&
+ m_pFcConfigGetFonts &&
+ m_pFcFontSetCreate &&
+ m_pFcCharSetCreate &&
+ m_pFcCharSetAddChar &&
+ m_pFcCharSetHasChar &&
+ m_pFcCharSetDestroy &&
+ m_pFcFontSetDestroy &&
+ m_pFcFontSetAdd &&
+ m_pFcPatternReference &&
+ m_pFcPatternGetCharSet &&
+ m_pFcPatternGetString &&
+ m_pFcPatternGetInteger &&
+ m_pFcPatternGetDouble &&
+ m_pFcPatternGetBool &&
+ m_pFcConfigAppFontAddFile &&
+ m_pFcConfigAppFontAddDir &&
+ m_pFcConfigParseAndLoad &&
+ m_pFcFontMatch &&
+ m_pFcDefaultSubstitute &&
+ m_pFcConfigSubstitute &&
+ m_pFcPatternDuplicate &&
+ m_pFcPatternAddInteger &&
+ m_pFcPatternAddDouble &&
+ m_pFcPatternAddCharSet &&
+ m_pFcPatternAddBool &&
+ m_pFcPatternAddString &&
+ m_pFcPatternDel
+ ) )
+ {
+ osl_unloadModule( (oslModule)m_pLib );
+ m_pLib = NULL;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "not all needed symbols were found in libfontconfig\n" );
+#endif
+ return;
+ }
+
+
+ FcInit();
+ if( ! FcConfigGetCurrent() )
+ {
+ osl_unloadModule( (oslModule)m_pLib );
+ m_pLib = NULL;
+ }
+}
+
+void FontCfgWrapper::addFontSet( FcSetName eSetName )
+{
+ #ifdef ENABLE_FONTCONFIG
+ /*
+ add only acceptable outlined fonts to our config,
+ for future fontconfig use
+ */
+ FcFontSet* pOrig = FcConfigGetFonts( FcConfigGetCurrent(), eSetName );
+ if( !pOrig )
+ return;
+
+ // filter the font sets to remove obsolete faces
+ for( int i = 0; i < pOrig->nfont; ++i )
+ {
+ FcPattern* pPattern = pOrig->fonts[i];
+ // #i115131# ignore non-outline fonts
+ FcBool bOutline = FcFalse;
+ FcResult eOutRes = FcPatternGetBool( pPattern, FC_OUTLINE, 0, &bOutline );
+ if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) )
+ continue;
+ FcPatternReference( pPattern );
+ FcFontSetAdd( m_pOutlineSet, pPattern );
+ }
+
+ // TODO?: FcFontSetDestroy( pOrig );
+ #else
+ (void)eSetName; // prevent compiler warning about unused parameter
+ #endif
+}
+
+#ifdef ENABLE_FONTCONFIG
+namespace
+{
+ int compareFontNames(FontCfgWrapper& rWrapper, const FcPattern *a, const FcPattern *b)
+ {
+ FcChar8 *pNameA=NULL, *pNameB=NULL;
+
+ bool bHaveA = rWrapper.FcPatternGetString(a, FC_FAMILY, 0, &pNameA) == FcResultMatch;
+ bool bHaveB = rWrapper.FcPatternGetString(b, FC_FAMILY, 0, &pNameB) == FcResultMatch;
+
+ if (bHaveA && bHaveB)
+ return strcmp((const char*)pNameA, (const char*)pNameB);
+
+ return bHaveA - bHaveB;
+ }
+
+ //Sort fonts so that fonts with the same family name are side-by-side, with
+ //those with higher version numbers first
+ class SortFont : public ::std::binary_function< const FcPattern*, const FcPattern*, bool >
+ {
+ private:
+ FontCfgWrapper& m_rWrapper;
+ public:
+ SortFont(FontCfgWrapper& rWrapper) : m_rWrapper(rWrapper) {}
+
+ bool operator()(const FcPattern *a, const FcPattern *b)
+ {
+ int comp = compareFontNames(m_rWrapper, a, b);
+ if (comp != 0)
+ return comp < 0;
+
+ int nVersionA=0, nVersionB=0;
+
+ bool bHaveA = m_rWrapper.FcPatternGetInteger(a, FC_FONTVERSION, 0, &nVersionA) == FcResultMatch;
+ bool bHaveB = m_rWrapper.FcPatternGetInteger(b, FC_FONTVERSION, 0, &nVersionB) == FcResultMatch;
+
+ if (bHaveA && bHaveB)
+ return nVersionA > nVersionB;
+
+ return bHaveA - bHaveA;
+ }
+ };
+
+ //See fdo#30729 for where an old opensymbol installed system-wide can
+ //clobber the new opensymbol installed locally
+ //
+ //See if this font is a duplicate with equal attributes which has already been
+ //inserted, or if it an older version of an inserted fonts. Depends on FcFontSet
+ //on being sorted with SortFont
+ bool isPreviouslyDuplicateOrObsoleted(FontCfgWrapper& rWrapper, FcFontSet *pFSet, int i)
+ {
+ if (i == 0)
+ return false;
+
+ const FcPattern *a = pFSet->fonts[i];
+ const FcPattern *b = pFSet->fonts[i-1];
+
+ if (compareFontNames(rWrapper, a, b) != 0)
+ return false;
+
+ FcPattern* pTestPatternA = rWrapper.FcPatternDuplicate(a);
+ rWrapper.FcPatternDel(pTestPatternA, FC_FILE);
+ rWrapper.FcPatternDel(pTestPatternA, FC_CHARSET);
+ rWrapper.FcPatternDel(pTestPatternA, FC_CAPABILITY);
+ rWrapper.FcPatternDel(pTestPatternA, FC_FONTVERSION);
+
+ FcPattern* pTestPatternB = rWrapper.FcPatternDuplicate(b);
+ rWrapper.FcPatternDel(pTestPatternB, FC_FILE);
+ rWrapper.FcPatternDel(pTestPatternB, FC_CHARSET);
+ rWrapper.FcPatternDel(pTestPatternB, FC_CAPABILITY);
+ rWrapper.FcPatternDel(pTestPatternB, FC_FONTVERSION);
+
+ bool bIsDup = false;
+ if (rWrapper.FcPatternEqual(pTestPatternA, pTestPatternB))
+ bIsDup = true;
+
+ rWrapper.FcPatternDestroy(pTestPatternB);
+ rWrapper.FcPatternDestroy(pTestPatternA);
+
+ return bIsDup;
+ }
+}
+#endif
+
+FcFontSet* FontCfgWrapper::getFontSet()
+{
+ #ifdef ENABLE_FONTCONFIG
+ if( !m_pOutlineSet )
+ {
+ m_pOutlineSet = FcFontSetCreate();
+ addFontSet( FcSetSystem );
+ if( m_nFcVersion > 20400 ) // #i85462# prevent crashes
+ addFontSet( FcSetApplication );
+
+ ::std::sort(m_pOutlineSet->fonts,m_pOutlineSet->fonts+m_pOutlineSet->nfont,SortFont(*this));
+ }
+ #endif
+
+ return m_pOutlineSet;
+}
+
+FontCfgWrapper::~FontCfgWrapper()
+{
+ if( m_pOutlineSet )
+ FcFontSetDestroy( m_pOutlineSet );
+ FcFini();
+ if( m_pLib )
+ osl_unloadModule( (oslModule)m_pLib );
+}
+
+static FontCfgWrapper* pOneInstance = NULL;
+
+FontCfgWrapper& FontCfgWrapper::get()
+{
+ if( ! pOneInstance )
+ pOneInstance = new FontCfgWrapper();
+ return *pOneInstance;
+}
+
+void FontCfgWrapper::release()
+{
+ if( pOneInstance )
+ {
+ delete pOneInstance;
+ pOneInstance = NULL;
+ }
+}
+
+#ifdef ENABLE_FONTCONFIG
+namespace
+{
+ class localizedsorter
+ {
+ rtl::OLocale maLoc;
+ public:
+ localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {}
+ FcChar8* bestname(const std::vector<lang_and_element> &elements);
+ };
+
+ FcChar8* localizedsorter::bestname(const std::vector<lang_and_element> &elements)
+ {
+ FcChar8* candidate = elements.begin()->second;
+ rtl::OString sLangMatch(rtl::OUStringToOString(maLoc.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8));
+ rtl::OString sFullMatch = sLangMatch;
+ sFullMatch += OString('-');
+ sFullMatch += rtl::OUStringToOString(maLoc.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8);
+
+ std::vector<lang_and_element>::const_iterator aEnd = elements.end();
+ bool alreadyclosematch = false;
+ for( std::vector<lang_and_element>::const_iterator aIter = elements.begin(); aIter != aEnd; ++aIter )
+ {
+ const char *pLang = (const char*)aIter->first;
+ if( rtl_str_compare( pLang, sFullMatch.getStr() ) == 0)
+ {
+ // both language and country match
+ candidate = aIter->second;
+ break;
+ }
+ else if( alreadyclosematch )
+ {
+ // override candidate only if there is a perfect match
+ continue;
+ }
+ else if( rtl_str_compare( pLang, sLangMatch.getStr()) == 0)
+ {
+ // just the language matches
+ candidate = aIter->second;
+ alreadyclosematch = true;
+ }
+ else if( rtl_str_compare( pLang, "en") == 0)
+ {
+ // fallback to the english element name
+ candidate = aIter->second;
+ }
+ }
+ return candidate;
+ }
+}
+
+//Set up maps to quickly map between a fonts best UI name and all the rest of its names, and vice versa
+void FontCfgWrapper::cacheLocalizedFontNames(FcChar8 *origfontname, FcChar8 *bestfontname, const std::vector< lang_and_element > &lang_and_elements)
+{
+ std::vector<lang_and_element>::const_iterator aEnd = lang_and_elements.end();
+ for (std::vector<lang_and_element>::const_iterator aIter = lang_and_elements.begin(); aIter != aEnd; ++aIter)
+ {
+ const char *candidate = (const char*)(aIter->second);
+ if (rtl_str_compare(candidate, (const char*)bestfontname) != 0)
+ m_aFontNameToLocalized[OString(candidate)] = OString((const char*)bestfontname);
+ }
+ if (rtl_str_compare((const char*)origfontname, (const char*)bestfontname) != 0)
+ m_aLocalizedToCanonical[OString((const char*)bestfontname)] = OString((const char*)origfontname);
+}
+
+FcResult FontCfgWrapper::LocalizedElementFromPattern(FcPattern* pPattern, FcChar8 **element,
+ const char *elementtype, const char *elementlangtype)
+{ /* e. g.: ^ FC_FAMILY ^ FC_FAMILYLANG */
+ FcChar8 *origelement;
+ FcResult eElementRes = FcPatternGetString( pPattern, elementtype, 0, &origelement );
+ *element = origelement;
+
+ if( eElementRes == FcResultMatch)
+ {
+ FcChar8* elementlang = NULL;
+ if (FcPatternGetString( pPattern, elementlangtype, 0, &elementlang ) == FcResultMatch)
+ {
+ std::vector< lang_and_element > lang_and_elements;
+ lang_and_elements.push_back(lang_and_element(elementlang, *element));
+ int k = 1;
+ while (1)
+ {
+ if (FcPatternGetString( pPattern, elementlangtype, k, &elementlang ) != FcResultMatch)
+ break;
+ if (FcPatternGetString( pPattern, elementtype, k, element ) != FcResultMatch)
+ break;
+ lang_and_elements.push_back(lang_and_element(elementlang, *element));
+ ++k;
+ }
+
+ //possible to-do, sort by UILocale instead of process locale
+ rtl_Locale* pLoc;
+ osl_getProcessLocale(&pLoc);
+ localizedsorter aSorter(pLoc);
+ *element = aSorter.bestname(lang_and_elements);
+
+ //if this element is a fontname, map the other names to this best-name
+ if (rtl_str_compare(elementtype, FC_FAMILY) == 0)
+ cacheLocalizedFontNames(origelement, *element, lang_and_elements);
+ }
+ }
+
+ return eElementRes;
+}
+
+/*
+ * PrintFontManager::initFontconfig
+ */
+bool PrintFontManager::initFontconfig()
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+ return true;
+}
+
+namespace
+{
+ weight::type convertWeight(int weight)
+ {
+ // set weight
+ if( weight <= FC_WEIGHT_THIN )
+ return weight::Thin;
+ else if( weight <= FC_WEIGHT_ULTRALIGHT )
+ return weight::UltraLight;
+ else if( weight <= FC_WEIGHT_LIGHT )
+ return weight::Light;
+ else if( weight <= FC_WEIGHT_BOOK )
+ return weight::SemiLight;
+ else if( weight <= FC_WEIGHT_NORMAL )
+ return weight::Normal;
+ else if( weight <= FC_WEIGHT_MEDIUM )
+ return weight::Medium;
+ else if( weight <= FC_WEIGHT_SEMIBOLD )
+ return weight::SemiBold;
+ else if( weight <= FC_WEIGHT_BOLD )
+ return weight::Bold;
+ else if( weight <= FC_WEIGHT_ULTRABOLD )
+ return weight::UltraBold;
+ return weight::Black;
+ }
+
+ italic::type convertSlant(int slant)
+ {
+ // set italic
+ if( slant == FC_SLANT_ITALIC )
+ return italic::Italic;
+ else if( slant == FC_SLANT_OBLIQUE )
+ return italic::Oblique;
+ return italic::Upright;
+ }
+
+ pitch::type convertSpacing(int spacing)
+ {
+ // set pitch
+ if( spacing == FC_MONO || spacing == FC_CHARCELL )
+ return pitch::Fixed;
+ return pitch::Variable;
+ }
+
+ width::type convertWidth(int width)
+ {
+ if (width == FC_WIDTH_ULTRACONDENSED)
+ return width::UltraCondensed;
+ else if (width == FC_WIDTH_EXTRACONDENSED)
+ return width::ExtraCondensed;
+ else if (width == FC_WIDTH_CONDENSED)
+ return width::Condensed;
+ else if (width == FC_WIDTH_SEMICONDENSED)
+ return width::SemiCondensed;
+ else if (width == FC_WIDTH_SEMIEXPANDED)
+ return width::SemiExpanded;
+ else if (width == FC_WIDTH_EXPANDED)
+ return width::Expanded;
+ else if (width == FC_WIDTH_EXTRAEXPANDED)
+ return width::ExtraExpanded;
+ else if (width == FC_WIDTH_ULTRAEXPANDED)
+ return width::UltraExpanded;
+ return width::Normal;
+ }
+}
+
+int PrintFontManager::countFontconfigFonts( boost::unordered_map<rtl::OString, int, rtl::OStringHash>& o_rVisitedPaths )
+{
+ int nFonts = 0;
+
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( !rWrapper.isValid() )
+ return 0;
+
+ FcFontSet* pFSet = rWrapper.getFontSet();
+ if( pFSet )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %d entries in fontconfig fontset\n", pFSet->nfont );
+#endif
+ for( int i = 0; i < pFSet->nfont; i++ )
+ {
+ FcChar8* file = NULL;
+ FcChar8* family = NULL;
+ FcChar8* style = NULL;
+ int slant = 0;
+ int weight = 0;
+ int spacing = 0;
+ int nCollectionEntry = -1;
+ FcBool outline = false;
+
+ FcResult eFileRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_FILE, 0, &file );
+ FcResult eFamilyRes = rWrapper.LocalizedElementFromPattern( pFSet->fonts[i], &family, FC_FAMILY, FC_FAMILYLANG );
+ FcResult eStyleRes = rWrapper.LocalizedElementFromPattern( pFSet->fonts[i], &style, FC_STYLE, FC_STYLELANG );
+ FcResult eSlantRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SLANT, 0, &slant );
+ FcResult eWeightRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_WEIGHT, 0, &weight );
+ FcResult eSpacRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SPACING, 0, &spacing );
+ FcResult eOutRes = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_OUTLINE, 0, &outline );
+ FcResult eIndexRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry );
+
+ if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch )
+ continue;
+
+#if (OSL_DEBUG_LEVEL > 2)
+ fprintf( stderr, "found font \"%s\" in file %s\n"
+ " weight = %d, slant = %d, style = \"%s\"\n"
+ " spacing = %d, outline = %d\n"
+ , family, file
+ , eWeightRes == FcResultMatch ? weight : -1
+ , eSpacRes == FcResultMatch ? slant : -1
+ , eStyleRes == FcResultMatch ? (const char*) style : "<nil>"
+ , eSpacRes == FcResultMatch ? spacing : -1
+ , eOutRes == FcResultMatch ? outline : -1
+ );
+#endif
+
+// OSL_ASSERT(eOutRes != FcResultMatch || outline);
+
+ // only outline fonts are usable to psprint anyway
+ if( eOutRes == FcResultMatch && ! outline )
+ continue;
+
+ if (isPreviouslyDuplicateOrObsoleted(rWrapper, pFSet, i))
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf(stderr, "Ditching %s as duplicate/obsolete\n", file);
+#endif
+ continue;
+ }
+
+ // see if this font is already cached
+ // update attributes
+ std::list< PrintFont* > aFonts;
+ OString aDir, aBase, aOrgPath( (sal_Char*)file );
+ splitPath( aOrgPath, aDir, aBase );
+
+ o_rVisitedPaths[aDir] = 1;
+
+ int nDirID = getDirectoryAtom( aDir, true );
+ if( ! m_pFontCache->getFontCacheFile( nDirID, aBase, aFonts ) )
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "file %s not cached\n", aBase.getStr() );
+#endif
+ // not known, analyze font file to get attributes
+ // not described by fontconfig (e.g. alias names, PSName)
+ std::list< OString > aDummy;
+ analyzeFontFile( nDirID, aBase, aDummy, aFonts );
+#if OSL_DEBUG_LEVEL > 1
+ if( aFonts.empty() )
+ fprintf( stderr, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath.getStr() );
+#endif
+ }
+ if( aFonts.empty() )
+ {
+ // TODO: remove fonts unusable to psprint from fontset
+ continue;
+ }
+
+ int nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( OString( (sal_Char*)family ), RTL_TEXTENCODING_UTF8 ), sal_True );
+ PrintFont* pUpdate = aFonts.front();
+ std::list<PrintFont*>::const_iterator second_font = aFonts.begin();
+ ++second_font;
+ if( second_font != aFonts.end() ) // more than one font
+ {
+ // a collection entry, get the correct index
+ if( eIndexRes == FcResultMatch && nCollectionEntry != -1 )
+ {
+ for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
+ {
+ if( (*it)->m_eType == fonttype::TrueType &&
+ static_cast<TrueTypeFontFile*>(*it)->m_nCollectionEntry == nCollectionEntry )
+ {
+ pUpdate = *it;
+ break;
+ }
+ }
+ // update collection entry
+ // additional entries will be created in the cache
+ // if this is a new index (that is if the loop above
+ // ran to the end of the list)
+ if( pUpdate->m_eType == fonttype::TrueType ) // sanity check, this should always be the case here
+ static_cast<TrueTypeFontFile*>(pUpdate)->m_nCollectionEntry = nCollectionEntry;
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "multiple fonts for file, but no index in fontconfig pattern ! (index res = %d collection entry = %d\nfile will not be used\n", eIndexRes, nCollectionEntry );
+#endif
+ // we have found more than one font in this file
+ // but fontconfig will not tell us which index is meant
+ // -> something is in disorder, do not use this font
+ pUpdate = NULL;
+ }
+ }
+
+ if( pUpdate )
+ {
+ // set family name
+ if( pUpdate->m_nFamilyName != nFamilyName )
+ {
+ }
+ if( eWeightRes == FcResultMatch )
+ pUpdate->m_eWeight = convertWeight(weight);
+ if( eSpacRes == FcResultMatch )
+ pUpdate->m_ePitch = convertSpacing(spacing);
+ if( eSlantRes == FcResultMatch )
+ pUpdate->m_eItalic = convertSlant(slant);
+ if( eStyleRes == FcResultMatch )
+ {
+ pUpdate->m_aStyleName = OStringToOUString( OString( (sal_Char*)style ), RTL_TEXTENCODING_UTF8 );
+ }
+
+ // update font cache
+ m_pFontCache->updateFontCacheEntry( pUpdate, false );
+ // sort into known fonts
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = pUpdate;
+ m_aFontFileToFontID[ aBase ].insert( aFont );
+ nFonts++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "inserted font %s as fontID %d\n", family, aFont );
+#endif
+ }
+ // clean up the fonts we did not put into the list
+ for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
+ {
+ if( *it != pUpdate )
+ {
+ m_pFontCache->updateFontCacheEntry( *it, false ); // prepare a cache entry for a collection item
+ delete *it;
+ }
+ }
+ }
+ }
+
+ // how does one get rid of the config ?
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts );
+#endif
+ return nFonts;
+}
+
+void PrintFontManager::deinitFontconfig()
+{
+ FontCfgWrapper::release();
+}
+
+int PrintFontManager::FreeTypeCharIndex( void *pFace, sal_uInt32 aChar )
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ return rWrapper.isValid() ? rWrapper.FcFreeTypeCharIndex( (FT_Face)pFace, aChar ) : 0;
+}
+
+bool PrintFontManager::addFontconfigDir( const rtl::OString& rDirName )
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+
+ // workaround for a stability problems in older FC versions
+ // when handling application specifc fonts
+ const int nVersion = rWrapper.FcGetVersion();
+ if( nVersion <= 20400 )
+ return false;
+ const char* pDirName = (const char*)rDirName.getStr();
+ bool bDirOk = (rWrapper.FcConfigAppFontAddDir( rWrapper.FcConfigGetCurrent(), (FcChar8*)pDirName ) == FcTrue);
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bDirOk );
+#endif
+
+ if( !bDirOk )
+ return false;
+
+ // load dir-specific fc-config file too if available
+ const rtl::OString aConfFileName = rDirName + "/fc_local.conf";
+ FILE* pCfgFile = fopen( aConfFileName.getStr(), "rb" );
+ if( pCfgFile )
+ {
+ fclose( pCfgFile);
+ bool bCfgOk = rWrapper.FcConfigParseAndLoad( rWrapper.FcConfigGetCurrent(),
+ (FcChar8*)aConfFileName.getStr(), FcTrue );
+ if( !bCfgOk )
+ fprintf( stderr, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName.getStr(), bCfgOk );
+ }
+
+ return true;
+}
+
+static void addtopattern(FontCfgWrapper& rWrapper, FcPattern *pPattern,
+ italic::type eItalic, weight::type eWeight, width::type eWidth, pitch::type ePitch)
+{
+ if( eItalic != italic::Unknown )
+ {
+ int nSlant = FC_SLANT_ROMAN;
+ switch( eItalic )
+ {
+ case italic::Italic: nSlant = FC_SLANT_ITALIC;break;
+ case italic::Oblique: nSlant = FC_SLANT_OBLIQUE;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_SLANT, nSlant );
+ }
+ if( eWeight != weight::Unknown )
+ {
+ int nWeight = FC_WEIGHT_NORMAL;
+ switch( eWeight )
+ {
+ case weight::Thin: nWeight = FC_WEIGHT_THIN;break;
+ case weight::UltraLight: nWeight = FC_WEIGHT_ULTRALIGHT;break;
+ case weight::Light: nWeight = FC_WEIGHT_LIGHT;break;
+ case weight::SemiLight: nWeight = FC_WEIGHT_BOOK;break;
+ case weight::Normal: nWeight = FC_WEIGHT_NORMAL;break;
+ case weight::Medium: nWeight = FC_WEIGHT_MEDIUM;break;
+ case weight::SemiBold: nWeight = FC_WEIGHT_SEMIBOLD;break;
+ case weight::Bold: nWeight = FC_WEIGHT_BOLD;break;
+ case weight::UltraBold: nWeight = FC_WEIGHT_ULTRABOLD;break;
+ case weight::Black: nWeight = FC_WEIGHT_BLACK;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_WEIGHT, nWeight );
+ }
+ if( eWidth != width::Unknown )
+ {
+ int nWidth = FC_WIDTH_NORMAL;
+ switch( eWidth )
+ {
+ case width::UltraCondensed: nWidth = FC_WIDTH_ULTRACONDENSED;break;
+ case width::ExtraCondensed: nWidth = FC_WIDTH_EXTRACONDENSED;break;
+ case width::Condensed: nWidth = FC_WIDTH_CONDENSED;break;
+ case width::SemiCondensed: nWidth = FC_WIDTH_SEMICONDENSED;break;
+ case width::Normal: nWidth = FC_WIDTH_NORMAL;break;
+ case width::SemiExpanded: nWidth = FC_WIDTH_SEMIEXPANDED;break;
+ case width::Expanded: nWidth = FC_WIDTH_EXPANDED;break;
+ case width::ExtraExpanded: nWidth = FC_WIDTH_EXTRAEXPANDED;break;
+ case width::UltraExpanded: nWidth = FC_WIDTH_ULTRACONDENSED;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_WIDTH, nWidth );
+ }
+ if( ePitch != pitch::Unknown )
+ {
+ int nSpacing = FC_PROPORTIONAL;
+ switch( ePitch )
+ {
+ case pitch::Fixed: nSpacing = FC_MONO;break;
+ case pitch::Variable: nSpacing = FC_PROPORTIONAL;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_SPACING, nSpacing );
+ if (nSpacing == FC_MONO)
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)"monospace");
+ }
+}
+
+rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName,
+ rtl::OUString& rMissingCodes, const rtl::OString &rLangAttrib,
+ italic::type &rItalic, weight::type &rWeight,
+ width::type &rWidth, pitch::type &rPitch) const
+{
+ rtl::OUString aName;
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return aName;
+
+ // build pattern argument for fontconfig query
+ FcPattern* pPattern = rWrapper.FcPatternCreate();
+
+ // Prefer scalable fonts
+ rWrapper.FcPatternAddBool( pPattern, FC_SCALABLE, FcTrue );
+
+ const rtl::OString aTargetName = rtl::OUStringToOString( rFontName, RTL_TEXTENCODING_UTF8 );
+ const FcChar8* pTargetNameUtf8 = (FcChar8*)aTargetName.getStr();
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, pTargetNameUtf8 );
+
+ if( rLangAttrib.getLength() )
+ {
+ const FcChar8* pLangAttribUtf8;
+ if (rLangAttrib.equalsIgnoreAsciiCase(OString(RTL_CONSTASCII_STRINGPARAM("pa-in"))))
+ pLangAttribUtf8 = (FcChar8*)"pa";
+ else
+ pLangAttribUtf8 = (FcChar8*)rLangAttrib.getStr();
+ rWrapper.FcPatternAddString( pPattern, FC_LANG, pLangAttribUtf8 );
+ }
+
+ // Add required Unicode characters, if any
+ if ( rMissingCodes.getLength() )
+ {
+ FcCharSet *unicodes = rWrapper.FcCharSetCreate();
+ for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
+ {
+ // also handle unicode surrogates
+ const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
+ rWrapper.FcCharSetAddChar( unicodes, nCode );
+ }
+ rWrapper.FcPatternAddCharSet( pPattern, FC_CHARSET, unicodes);
+ rWrapper.FcCharSetDestroy( unicodes );
+ }
+
+ addtopattern(rWrapper, pPattern, rItalic, rWeight, rWidth, rPitch);
+
+ // query fontconfig for a substitute
+ rWrapper.FcConfigSubstitute( rWrapper.FcConfigGetCurrent(), pPattern, FcMatchPattern );
+ rWrapper.FcDefaultSubstitute( pPattern );
+
+ // process the result of the fontconfig query
+ FcResult eResult = FcResultNoMatch;
+ FcFontSet* pFontSet = rWrapper.getFontSet();
+ FcPattern* pResult = rWrapper.FcFontSetMatch( rWrapper.FcConfigGetCurrent(), &pFontSet, 1, pPattern, &eResult );
+ rWrapper.FcPatternDestroy( pPattern );
+
+ FcFontSet* pSet = NULL;
+ if( pResult )
+ {
+ pSet = rWrapper.FcFontSetCreate();
+ // info: destroying the pSet destroys pResult implicitly
+ // since pResult was "added" to pSet
+ rWrapper.FcFontSetAdd( pSet, pResult );
+ }
+
+ if( pSet )
+ {
+ if( pSet->nfont > 0 )
+ {
+ //extract the closest match
+ FcChar8* family = NULL;
+ FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family );
+
+ // get the family name
+ if( eFileRes == FcResultMatch )
+ {
+ OString sFamily((sal_Char*)family);
+ boost::unordered_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aFontNameToLocalized.find(sFamily);
+ if (aI != rWrapper.m_aFontNameToLocalized.end())
+ sFamily = aI->second;
+ aName = rtl::OStringToOUString( sFamily, RTL_TEXTENCODING_UTF8 );
+
+
+ int val = 0;
+ if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WEIGHT, 0, &val))
+ rWeight = convertWeight(val);
+ if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_SLANT, 0, &val))
+ rItalic = convertSlant(val);
+ if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_SPACING, 0, &val))
+ rPitch = convertSpacing(val);
+ if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WIDTH, 0, &val))
+ rWidth = convertWidth(val);
+ }
+
+ // update rMissingCodes by removing resolved unicodes
+ if( rMissingCodes.getLength() > 0 )
+ {
+ sal_uInt32* pRemainingCodes = (sal_uInt32*)alloca( rMissingCodes.getLength() * sizeof(sal_uInt32) );
+ int nRemainingLen = 0;
+ FcCharSet* unicodes;
+ if( !rWrapper.FcPatternGetCharSet( pSet->fonts[0], FC_CHARSET, 0, &unicodes ) )
+ {
+ for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
+ {
+ // also handle unicode surrogates
+ const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
+ if( rWrapper.FcCharSetHasChar( unicodes, nCode ) != FcTrue )
+ pRemainingCodes[ nRemainingLen++ ] = nCode;
+ }
+ }
+ rMissingCodes = OUString( pRemainingCodes, nRemainingLen );
+ }
+ }
+
+ rWrapper.FcFontSetDestroy( pSet );
+ }
+
+ return aName;
+}
+
+class FontConfigFontOptions : public ImplFontOptions
+{
+public:
+ FontConfigFontOptions() : mpPattern(0) {}
+ ~FontConfigFontOptions()
+ {
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( rWrapper.isValid() )
+ rWrapper.FcPatternDestroy( mpPattern );
+ }
+ virtual void *GetPattern(void * face, bool bEmbolden) const
+ {
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( rWrapper.isValid() )
+ {
+ rWrapper.FcPatternAddFTFace(mpPattern, FC_FT_FACE, static_cast<FT_Face>(face));
+ rWrapper.FcPatternAddBool(mpPattern, FC_EMBOLDEN, bEmbolden ? FcTrue : FcFalse);
+ }
+ return mpPattern;
+ }
+ FcPattern* mpPattern;
+};
+
+ImplFontOptions* PrintFontManager::getFontOptions(
+ const FastPrintFontInfo& rInfo, int nSize, void (*subcallback)(void*)) const
+{
+#ifndef ENABLE_FONTCONFIG
+ (void)rInfo;(void)nSize;(void)subcallback;(void)rOptions;
+ return NULL;
+#else // ENABLE_FONTCONFIG
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return NULL;
+
+ FontConfigFontOptions* pOptions = NULL;
+ FcConfig* pConfig = rWrapper.FcConfigGetCurrent();
+ FcPattern* pPattern = rWrapper.FcPatternCreate();
+
+ OString sFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
+
+ boost::unordered_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aLocalizedToCanonical.find(sFamily);
+ if (aI != rWrapper.m_aLocalizedToCanonical.end())
+ sFamily = aI->second;
+ if( sFamily.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)sFamily.getStr() );
+
+ addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
+ rWrapper.FcPatternAddDouble( pPattern, FC_PIXEL_SIZE, nSize);
+
+ FcBool embitmap = true, antialias = true, autohint = true, hinting = true;
+ int hintstyle = FC_HINT_FULL;
+
+ rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern );
+ if (subcallback) subcallback(pPattern);
+ rWrapper.FcDefaultSubstitute( pPattern );
+
+ FcResult eResult = FcResultNoMatch;
+ FcFontSet* pFontSet = rWrapper.getFontSet();
+ FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
+ if( pResult )
+ {
+ FcResult eEmbeddedBitmap = rWrapper.FcPatternGetBool(pResult,
+ FC_EMBEDDED_BITMAP, 0, &embitmap);
+ FcResult eAntialias = rWrapper.FcPatternGetBool(pResult,
+ FC_ANTIALIAS, 0, &antialias);
+ FcResult eAutoHint = rWrapper.FcPatternGetBool(pResult,
+ FC_AUTOHINT, 0, &autohint);
+ FcResult eHinting = rWrapper.FcPatternGetBool(pResult,
+ FC_HINTING, 0, &hinting);
+ /*FcResult eHintStyle =*/ rWrapper.FcPatternGetInteger(pResult,
+ FC_HINT_STYLE, 0, &hintstyle);
+
+ pOptions = new FontConfigFontOptions;
+
+ pOptions->mpPattern = pResult;
+
+ if( eEmbeddedBitmap == FcResultMatch )
+ pOptions->meEmbeddedBitmap = embitmap ? EMBEDDEDBITMAP_TRUE : EMBEDDEDBITMAP_FALSE;
+ if( eAntialias == FcResultMatch )
+ pOptions->meAntiAlias = antialias ? ANTIALIAS_TRUE : ANTIALIAS_FALSE;
+ if( eAutoHint == FcResultMatch )
+ pOptions->meAutoHint = autohint ? AUTOHINT_TRUE : AUTOHINT_FALSE;
+ if( eHinting == FcResultMatch )
+ pOptions->meHinting = hinting ? HINTING_TRUE : HINTING_FALSE;
+ switch (hintstyle)
+ {
+ case FC_HINT_NONE: pOptions->meHintStyle = HINT_NONE; break;
+ case FC_HINT_SLIGHT: pOptions->meHintStyle = HINT_SLIGHT; break;
+ case FC_HINT_MEDIUM: pOptions->meHintStyle = HINT_MEDIUM; break;
+ default: // fall through
+ case FC_HINT_FULL: pOptions->meHintStyle = HINT_FULL; break;
+ }
+ }
+
+ // cleanup
+ rWrapper.FcPatternDestroy( pPattern );
+
+ return pOptions;
+#endif
+}
+
+bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale )
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+
+ FcConfig* pConfig = rWrapper.FcConfigGetCurrent();
+ FcPattern* pPattern = rWrapper.FcPatternCreate();
+
+ OString aLangAttrib;
+ // populate pattern with font characteristics
+ if( rLocale.Language.getLength() )
+ {
+ OUStringBuffer aLang(6);
+ aLang.append( rLocale.Language );
+ if( rLocale.Country.getLength() )
+ {
+ aLang.append( sal_Unicode('-') );
+ aLang.append( rLocale.Country );
+ }
+ aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
+ }
+ if( aLangAttrib.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr() );
+
+ OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
+ if( aFamily.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr() );
+
+ addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
+
+ rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern );
+ rWrapper.FcDefaultSubstitute( pPattern );
+ FcResult eResult = FcResultNoMatch;
+ FcFontSet *pFontSet = rWrapper.getFontSet();
+ FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
+ bool bSuccess = false;
+ if( pResult )
+ {
+ FcFontSet* pSet = rWrapper.FcFontSetCreate();
+ rWrapper.FcFontSetAdd( pSet, pResult );
+ if( pSet->nfont > 0 )
+ {
+ //extract the closest match
+ FcChar8* file = NULL;
+ FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FILE, 0, &file );
+ if( eFileRes == FcResultMatch )
+ {
+ OString aDir, aBase, aOrgPath( (sal_Char*)file );
+ splitPath( aOrgPath, aDir, aBase );
+ int nDirID = getDirectoryAtom( aDir, true );
+ fontID aFont = findFontFileID( nDirID, aBase );
+ if( aFont > 0 )
+ bSuccess = getFontFastInfo( aFont, rInfo );
+ }
+ }
+ // info: destroying the pSet destroys pResult implicitly
+ // since pResult was "added" to pSet
+ rWrapper.FcFontSetDestroy( pSet );
+ }
+
+ // cleanup
+ rWrapper.FcPatternDestroy( pPattern );
+
+ return bSuccess;
+}
+
+#else // ENABLE_FONTCONFIG not defined
+
+bool PrintFontManager::initFontconfig()
+{
+ return false;
+}
+
+int PrintFontManager::countFontconfigFonts( boost::unordered_map<rtl::OString, int, rtl::OStringHash>& )
+{
+ return 0;
+}
+
+void PrintFontManager::deinitFontconfig()
+{}
+
+bool PrintFontManager::addFontconfigDir( const rtl::OString& )
+{
+ return false;
+}
+
+bool PrintFontManager::matchFont( FastPrintFontInfo&, const com::sun::star::lang::Locale& )
+{
+ return false;
+}
+
+int PrintFontManager::FreeTypeCharIndex( void*, sal_uInt32 )
+{
+ return 0;
+}
+
+rtl::OUString PrintFontManager::Substitute( const rtl::OUString&,
+ rtl::OUString&, const rtl::OString&, italic::type, weight::type, width::type, pitch::type) const
+{
+ rtl::OUString aName;
+ return aName;
+}
+
+#endif // ENABLE_FONTCONFIG
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/fontmanager/fontmanager.cxx b/vcl/unx/generic/fontmanager/fontmanager.cxx
new file mode 100644
index 000000000000..5b7ef936d5ca
--- /dev/null
+++ b/vcl/unx/generic/fontmanager/fontmanager.cxx
@@ -0,0 +1,4132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <unistd.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <osl/thread.h>
+
+#include "unotools/atom.hxx"
+
+#include "fontcache.hxx"
+#include "fontsubset.hxx"
+#include "impfont.hxx"
+#include "svdata.hxx"
+#include "salinst.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/ppdparser.hxx"
+
+#include "tools/urlobj.hxx"
+#include "tools/stream.hxx"
+#include "tools/debug.hxx"
+#include "tools/config.hxx"
+
+#include "osl/file.hxx"
+#include "osl/process.h"
+
+#include "rtl/tencinfo.h"
+#include "rtl/ustrbuf.hxx"
+#include "rtl/strbuf.hxx"
+
+#include <sal/macros.h>
+
+#include "i18npool/mslangid.hxx"
+
+
+#include "parseAFM.hxx"
+#include "sft.hxx"
+
+#if OSL_DEBUG_LEVEL > 1
+#include <sys/times.h>
+#include <stdio.h>
+#endif
+
+#include "sal/alloca.h"
+
+#include <set>
+#include <boost/unordered_set.hpp>
+#include <algorithm>
+
+#include "adobeenc.tab" // get encoding table for AFM metrics
+
+#ifdef CALLGRIND_COMPILE
+#include <valgrind/callgrind.h>
+#endif
+
+#include "comphelper/processfactory.hxx"
+#include "com/sun/star/beans/XMaterialHolder.hpp"
+#include "com/sun/star/beans/NamedValue.hpp"
+
+#define PRINTER_METRICDIR "fontmetric"
+
+namespace {
+
+namespace css = com::sun::star;
+
+}
+
+using namespace vcl;
+using namespace utl;
+using namespace psp;
+using namespace osl;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+
+using ::rtl::OUString;
+using ::rtl::OString;
+using ::rtl::OStringHash;
+using ::rtl::OStringBuffer;
+using ::rtl::OUStringBuffer;
+using ::rtl::OUStringHash;
+using ::rtl::OStringToOUString;
+using ::rtl::OUStringToOString;
+
+/*
+ * static helpers
+ */
+
+inline sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
+{
+ sal_uInt16 nRet = (sal_uInt16)pBuffer[1] |
+ (((sal_uInt16)pBuffer[0]) << 8);
+ pBuffer+=2;
+ return nRet;
+}
+
+inline sal_uInt32 getUInt32BE( const sal_uInt8*& pBuffer )
+{
+ sal_uInt32 nRet = (((sal_uInt32)pBuffer[0]) << 24) |
+ (((sal_uInt32)pBuffer[1]) << 16) |
+ (((sal_uInt32)pBuffer[2]) << 8) |
+ (((sal_uInt32)pBuffer[3]) );
+ pBuffer += 4;
+ return nRet;
+}
+
+static italic::type parseItalic( const ByteString& rItalic )
+{
+ italic::type eItalic = italic::Unknown;
+ if( rItalic.EqualsIgnoreCaseAscii( "i" ) )
+ eItalic = italic::Italic;
+ else if( rItalic.EqualsIgnoreCaseAscii( "o" ) )
+ eItalic = italic::Oblique;
+ else
+ eItalic = italic::Upright;
+ return eItalic;
+}
+
+// -------------------------------------------------------------------------
+
+static weight::type parseWeight( const ByteString& rWeight )
+{
+ weight::type eWeight = weight::Unknown;
+ if( rWeight.Search( "bold" ) != STRING_NOTFOUND )
+ {
+ if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi
+ eWeight = weight::SemiBold;
+ else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND )
+ eWeight = weight::UltraBold;
+ else
+ eWeight = weight::Bold;
+ }
+ else if( rWeight.Search( "heavy" ) != STRING_NOTFOUND )
+ eWeight = weight::Bold;
+ else if( rWeight.Search( "light" ) != STRING_NOTFOUND )
+ {
+ if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi
+ eWeight = weight::SemiLight;
+ else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND )
+ eWeight = weight::UltraLight;
+ else
+ eWeight = weight::Light;
+ }
+ else if( rWeight.Search( "black" ) != STRING_NOTFOUND )
+ eWeight = weight::Black;
+ else if( rWeight.Equals( "demi" ) )
+ eWeight = weight::SemiBold;
+ else if( rWeight.Equals( "book" ) ||
+ rWeight.Equals( "semicondensed" ) )
+ eWeight = weight::Light;
+ else if( rWeight.Equals( "medium" ) || rWeight.Equals( "roman" ) )
+ eWeight = weight::Medium;
+ else
+ eWeight = weight::Normal;
+ return eWeight;
+}
+
+// -------------------------------------------------------------------------
+
+static width::type parseWidth( const ByteString& rWidth )
+{
+ width::type eWidth = width::Unknown;
+ if( rWidth.Equals( "bold" ) ||
+ rWidth.Equals( "semiexpanded" ) )
+ eWidth = width::SemiExpanded;
+ else if( rWidth.Equals( "condensed" ) ||
+ rWidth.Equals( "narrow" ) )
+ eWidth = width::Condensed;
+ else if( rWidth.Equals( "double wide" ) ||
+ rWidth.Equals( "extraexpanded" ) ||
+ rWidth.Equals( "ultraexpanded" ) )
+ eWidth = width::UltraExpanded;
+ else if( rWidth.Equals( "expanded" ) ||
+ rWidth.Equals( "wide" ) )
+ eWidth = width::Expanded;
+ else if( rWidth.Equals( "extracondensed" ) )
+ eWidth = width::ExtraCondensed;
+ else if( rWidth.Equals( "semicondensed" ) )
+ eWidth = width::SemiCondensed;
+ else if( rWidth.Equals( "ultracondensed" ) )
+ eWidth = width::UltraCondensed;
+ else
+ eWidth = width::Normal;
+
+ return eWidth;
+}
+
+// -------------------------------------------------------------------------
+bool PrintFontManager::XLFDEntry::operator<(const PrintFontManager::XLFDEntry& rRight) const
+{
+ sal_Int32 nCmp = 0;
+ if( (nMask & MaskFamily) && (rRight.nMask & MaskFamily) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFamily.pData->buffer,
+ aFamily.pData->length,
+ rRight.aFamily.pData->buffer,
+ rRight.aFamily.pData->length );
+ if( nCmp != 0 )
+ return nCmp < 0;
+ }
+
+ if( (nMask & MaskFoundry) && (rRight.nMask & MaskFoundry) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFoundry.pData->buffer,
+ aFoundry.pData->length,
+ rRight.aFoundry.pData->buffer,
+ rRight.aFoundry.pData->length );
+ if( nCmp != 0 )
+ return nCmp < 0;
+ }
+
+ if( (nMask & MaskItalic) && (rRight.nMask & MaskItalic) )
+ {
+ if( eItalic != rRight.eItalic )
+ return (int)eItalic < (int)rRight.eItalic;
+ }
+
+ if( (nMask & MaskWeight) && (rRight.nMask & MaskWeight) )
+ {
+ if( eWeight != rRight.eWeight )
+ return (int)eWeight < (int)rRight.eWeight;
+ }
+
+ if( (nMask & MaskWidth) && (rRight.nMask & MaskWidth) )
+ {
+ if( eWidth != rRight.eWidth )
+ return (int)eWidth < (int)rRight.eWidth;
+ }
+
+ if( (nMask & MaskPitch) && (rRight.nMask & MaskPitch) )
+ {
+ if( ePitch != rRight.ePitch )
+ return (int)ePitch < (int)rRight.ePitch;
+ }
+
+ if( (nMask & MaskAddStyle) && (rRight.nMask & MaskAddStyle) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aAddStyle.pData->buffer,
+ aAddStyle.pData->length,
+ rRight.aAddStyle.pData->buffer,
+ rRight.aAddStyle.pData->length );
+ if( nCmp != 0 )
+ return nCmp < 0;
+ }
+
+ if( (nMask & MaskEncoding) && (rRight.nMask & MaskEncoding) )
+ {
+ if( aEncoding != rRight.aEncoding )
+ return aEncoding < rRight.aEncoding;
+ }
+
+ return false;
+}
+
+bool PrintFontManager::XLFDEntry::operator==(const PrintFontManager::XLFDEntry& rRight) const
+{
+ sal_Int32 nCmp = 0;
+ if( (nMask & MaskFamily) && (rRight.nMask & MaskFamily) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFamily.pData->buffer,
+ aFamily.pData->length,
+ rRight.aFamily.pData->buffer,
+ rRight.aFamily.pData->length );
+ if( nCmp != 0 )
+ return false;
+ }
+
+ if( (nMask & MaskFoundry) && (rRight.nMask & MaskFoundry) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFoundry.pData->buffer,
+ aFoundry.pData->length,
+ rRight.aFoundry.pData->buffer,
+ rRight.aFoundry.pData->length );
+ if( nCmp != 0 )
+ return false;
+ }
+
+ if( (nMask & MaskItalic) && (rRight.nMask & MaskItalic) )
+ {
+ if( eItalic != rRight.eItalic )
+ return false;
+ }
+
+ if( (nMask & MaskWeight) && (rRight.nMask & MaskWeight) )
+ {
+ if( eWeight != rRight.eWeight )
+ return false;
+ }
+
+ if( (nMask & MaskWidth) && (rRight.nMask & MaskWidth) )
+ {
+ if( eWidth != rRight.eWidth )
+ return false;
+ }
+
+ if( (nMask & MaskPitch) && (rRight.nMask & MaskPitch) )
+ {
+ if( ePitch != rRight.ePitch )
+ return false;
+ }
+
+ if( (nMask & MaskAddStyle) && (rRight.nMask & MaskAddStyle) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aAddStyle.pData->buffer,
+ aAddStyle.pData->length,
+ rRight.aAddStyle.pData->buffer,
+ rRight.aAddStyle.pData->length );
+ if( nCmp != 0 )
+ return false;
+ }
+
+ if( (nMask & MaskEncoding) && (rRight.nMask & MaskEncoding) )
+ {
+ if( aEncoding != rRight.aEncoding )
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * PrintFont implementations
+ */
+PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) :
+ m_eType( eType ),
+ m_nFamilyName( 0 ),
+ m_nPSName( 0 ),
+ m_eItalic( italic::Unknown ),
+ m_eWidth( width::Unknown ),
+ m_eWeight( weight::Unknown ),
+ m_ePitch( pitch::Unknown ),
+ m_aEncoding( RTL_TEXTENCODING_DONTKNOW ),
+ m_bFontEncodingOnly( false ),
+ m_pMetrics( NULL ),
+ m_nAscend( 0 ),
+ m_nDescend( 0 ),
+ m_nLeading( 0 ),
+ m_nXMin( 0 ),
+ m_nYMin( 0 ),
+ m_nXMax( 0 ),
+ m_nYMax( 0 ),
+ m_bHaveVerticalSubstitutedGlyphs( false ),
+ m_bUserOverride( false )
+{
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::PrintFont::~PrintFont()
+{
+ if( m_pMetrics )
+ delete m_pMetrics;
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::Type1FontFile::~Type1FontFile()
+{
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::TrueTypeFontFile::TrueTypeFontFile()
+: PrintFont( fonttype::TrueType )
+, m_nDirectory( 0 )
+, m_nCollectionEntry(-1)
+, m_nTypeFlags( TYPEFLAG_INVALID )
+{}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile()
+{
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::BuiltinFont::~BuiltinFont()
+{
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::Type1FontFile::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
+{
+ return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::BuiltinFont::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
+{
+ return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* pProvider )
+{
+ bool bSuccess = false;
+
+ ByteString aFile( PrintFontManager::get().getFontFile( this ) );
+
+ TrueTypeFont* pTTFont = NULL;
+
+ if( OpenTTFontFile( aFile.GetBuffer(), m_nCollectionEntry < 0 ? 0 : m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ if( ! m_pMetrics )
+ {
+ m_pMetrics = new PrintFontMetrics;
+ memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages));
+ }
+ m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 ));
+ int i;
+ sal_uInt16 table[256], table_vert[256];
+
+ for( i = 0; i < 256; i++ )
+ table[ i ] = 256*nPage + i;
+
+ int nCharacters = nPage < 255 ? 256 : 254;
+ MapString( pTTFont, table, nCharacters, NULL, 0 );
+ TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 0 );
+ if( pMetrics )
+ {
+ for( i = 0; i < nCharacters; i++ )
+ {
+ if( table[i] )
+ {
+ CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ];
+ rChar.width = pMetrics[ i ].adv;
+ rChar.height = m_aGlobalMetricX.height;
+ }
+ }
+
+ free( pMetrics );
+ }
+
+ for( i = 0; i < 256; i++ )
+ table_vert[ i ] = 256*nPage + i;
+ MapString( pTTFont, table_vert, nCharacters, NULL, 1 );
+ pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 1 );
+ if( pMetrics )
+ {
+ for( i = 0; i < nCharacters; i++ )
+ {
+ if( table_vert[i] )
+ {
+ CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ];
+ rChar.width = m_aGlobalMetricY.width;
+ rChar.height = pMetrics[ i ].adv;
+ if( table_vert[i] != table[i] )
+ m_pMetrics->m_bVerticalSubstitutions[ nPage*256 + i ] = 1;
+ }
+ }
+ free( pMetrics );
+ }
+
+ if( ! m_pMetrics->m_bKernPairsQueried )
+ {
+ m_pMetrics->m_bKernPairsQueried = true;
+ // this is really a hack
+ // in future MapString/KernGlyphs should be used
+ // but vcl is not in a state where that could be used
+ // so currently we get kernpairs by accessing the raw data
+ struct _TrueTypeFont* pImplTTFont = (struct _TrueTypeFont*)pTTFont;
+
+ //-----------------------------------------------------------------
+ // Kerning: KT_MICROSOFT
+ //-----------------------------------------------------------------
+ if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_MICROSOFT )
+ {
+ // create a glyph -> character mapping
+ ::boost::unordered_map< sal_uInt16, sal_Unicode > aGlyphMap;
+ ::boost::unordered_map< sal_uInt16, sal_Unicode >::iterator left, right;
+ for( i = 21; i < 0xfffd; i++ )
+ {
+ sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
+ if( nGlyph != 0 )
+ aGlyphMap[ nGlyph ] = (sal_Unicode)i;
+ }
+
+
+ KernPair aPair;
+ for( i = 0; i < (int)pImplTTFont->nkern; i++ )
+ {
+ const sal_uInt8* pTable = pImplTTFont->kerntables[i];
+
+ /*sal_uInt16 nVersion =*/ getUInt16BE( pTable );
+ /*sal_uInt16 nLength =*/ getUInt16BE( pTable );
+ sal_uInt16 nCoverage = getUInt16BE( pTable );
+
+ aPair.kern_x = 0;
+ aPair.kern_y = 0;
+ switch( nCoverage >> 8 )
+ {
+ case 0:
+ {
+ sal_uInt16 nPairs = getUInt16BE( pTable );
+ pTable += 6;
+ for( int n = 0; n < nPairs; n++ )
+ {
+ sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
+ sal_uInt16 nRightGlyph = getUInt16BE( pTable );
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
+
+ left = aGlyphMap.find( nLeftGlyph );
+ right = aGlyphMap.find( nRightGlyph );
+ if( left != aGlyphMap.end() && right != aGlyphMap.end() )
+ {
+ aPair.first = left->second;
+ aPair.second = right->second;
+ switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case 2:
+ {
+ const sal_uInt8* pSubTable = pTable;
+ /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
+ sal_uInt16 nOfLeft = getUInt16BE( pTable );
+ sal_uInt16 nOfRight = getUInt16BE( pTable );
+ /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
+ const sal_uInt8* pTmp = pSubTable + nOfLeft;
+ sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
+ sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
+ pTmp = pSubTable + nOfRight;
+ sal_uInt16 nFirstRight = getUInt16BE( pTmp );
+ sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
+
+ // int nPairs = (int)(nLastLeft-nFirstLeft+1)*(int)(nLastRight-nFirstRight+1);
+ for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
+ {
+ for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
+ {
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
+ switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // Kerning: KT_APPLE_NEW
+ //-----------------------------------------------------------------
+ if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_APPLE_NEW )
+ {
+ // create a glyph -> character mapping
+ ::boost::unordered_map< sal_uInt16, sal_Unicode > aGlyphMap;
+ ::boost::unordered_map< sal_uInt16, sal_Unicode >::iterator left, right;
+ for( i = 21; i < 0xfffd; i++ )
+ {
+ sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
+ if( nGlyph != 0 )
+ aGlyphMap[ nGlyph ] = (sal_Unicode)i;
+ }
+
+ // Loop through each of the 'kern' subtables
+ KernPair aPair;
+ for( i = 0; (unsigned int)i < pImplTTFont->nkern; i++ )
+ {
+ const sal_uInt8* pTable = pImplTTFont->kerntables[i];
+
+ /*sal_uInt32 nLength =*/ getUInt32BE( pTable );
+ sal_uInt16 nCoverage = getUInt16BE( pTable );
+ /*sal_uInt16 nTupleIndex =*/ getUInt16BE( pTable );
+
+ // Get kerning type
+ // sal_Bool bKernVertical = nCoverage & 0x8000;
+ // sal_Bool bKernCrossStream = nCoverage & 0x4000;
+ // sal_Bool bKernVariation = nCoverage & 0x2000;
+
+ // Kerning sub-table format, 0 through 3
+ sal_uInt8 nSubTableFormat = nCoverage & 0x00FF;
+
+ aPair.kern_x = 0;
+ aPair.kern_y = 0;
+ switch( nSubTableFormat )
+ {
+ case 0:
+ {
+ // Grab the # of kern pairs but skip over the:
+ // searchRange
+ // entrySelector
+ // rangeShift
+ sal_uInt16 nPairs = getUInt16BE( pTable );
+ pTable += 6;
+
+ for( int n = 0; n < nPairs; n++ )
+ {
+ sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
+ sal_uInt16 nRightGlyph = getUInt16BE( pTable );
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
+
+ left = aGlyphMap.find( nLeftGlyph );
+ right = aGlyphMap.find( nRightGlyph );
+ if( left != aGlyphMap.end() && right != aGlyphMap.end() )
+ {
+ aPair.first = left->second;
+ aPair.second = right->second;
+
+ // Only support horizontal kerning for now
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ aPair.kern_y = 0;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+
+/* switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+*/
+ }
+ }
+ }
+ break;
+
+ case 2:
+ {
+ const sal_uInt8* pSubTable = pTable;
+ /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
+ sal_uInt16 nOfLeft = getUInt16BE( pTable );
+ sal_uInt16 nOfRight = getUInt16BE( pTable );
+ /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
+ const sal_uInt8* pTmp = pSubTable + nOfLeft;
+ sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
+ sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
+ pTmp = pSubTable + nOfRight;
+ sal_uInt16 nFirstRight = getUInt16BE( pTmp );
+ sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
+
+ for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
+ {
+ for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
+ {
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
+ switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ fprintf( stderr, "Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
+ break;
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %" SAL_PRI_SIZET "u/%" SAL_PRI_SIZET "u kern pairs for %s\n",
+ m_pMetrics->m_aXKernPairs.size(),
+ m_pMetrics->m_aYKernPairs.size(),
+ OUStringToOString( pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName ), RTL_TEXTENCODING_MS_1252 ).getStr() );
+#else
+ (void) pProvider; /* avoid warnings */
+#endif
+ }
+
+ CloseTTFont( pTTFont );
+ bSuccess = true;
+ }
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+/* #i73387# There seem to be fonts with a rather unwell chosen family name
+* consider e.g. "Helvetica Narrow" which defines its family as "Helvetica"
+* It can really only be distinguished by its PSName and FullName. Both of
+* which are not user presentable in OOo. So replace it by something sensible.
+*
+* If other fonts feature this behaviour, insert them to the map.
+*/
+static bool familyNameOverride( const OUString& i_rPSname, OUString& o_rFamilyName )
+{
+ static boost::unordered_map< OUString, OUString, OUStringHash > aPSNameToFamily( 16 );
+ if( aPSNameToFamily.empty() ) // initialization
+ {
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Bold" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-BoldOblique" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Oblique" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ }
+ boost::unordered_map<OUString,OUString,OUStringHash>::const_iterator it =
+ aPSNameToFamily.find( i_rPSname );
+ bool bReplaced = (it != aPSNameToFamily.end() );
+ if( bReplaced )
+ o_rFamilyName = it->second;
+ return bReplaced;
+};
+
+bool PrintFontManager::PrintFont::readAfmMetrics( const OString& rFileName, MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+
+ FontInfo* pInfo = NULL;
+ parseFile( rFileName.getStr(), &pInfo, P_ALL );
+ if( ! pInfo || ! pInfo->numOfChars )
+ {
+ if( pInfo )
+ freeFontInfo( pInfo );
+ return false;
+ }
+
+ m_aEncodingVector.clear();
+ // fill in global info
+
+ // PSName
+ OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) );
+ m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, sal_True );
+
+ // family name (if not already set)
+ OUString aFamily;
+ if( ! m_nFamilyName )
+ {
+ aFamily = OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 );
+ if( ! aFamily.getLength() )
+ {
+ aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 );
+ sal_Int32 nIndex = 0;
+ aFamily = aFamily.getToken( 0, '-', nIndex );
+ }
+ familyNameOverride( aPSName, aFamily );
+ m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, sal_True );
+ }
+ else
+ aFamily = pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName );
+
+ // style name: if fullname begins with family name
+ // interpret the rest of fullname as style
+ if( ! m_aStyleName.getLength() && pInfo->gfi->fullName && *pInfo->gfi->fullName )
+ {
+ OUString aFullName( OStringToOUString( pInfo->gfi->fullName, RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( aFullName.indexOf( aFamily ) == 0 )
+ m_aStyleName = WhitespaceToSpace( aFullName.copy( aFamily.getLength() ) );
+ }
+
+ // italic
+ if( pInfo->gfi->italicAngle > 0 )
+ m_eItalic = italic::Oblique;
+ else if( pInfo->gfi->italicAngle < 0 )
+ m_eItalic = italic::Italic;
+ else
+ m_eItalic = italic::Upright;
+
+ // weight
+ ByteString aLowerWeight( pInfo->gfi->weight );
+ aLowerWeight.ToLowerAscii();
+ m_eWeight = parseWeight( aLowerWeight );
+
+ // pitch
+ m_ePitch = pInfo->gfi->isFixedPitch ? pitch::Fixed : pitch::Variable;
+
+ // encoding - only set if unknown
+ int nAdobeEncoding = 0;
+ if( pInfo->gfi->encodingScheme )
+ {
+ if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) )
+ nAdobeEncoding = 1;
+ else if( !strcmp( pInfo->gfi->encodingScheme, "ISO10646-1" ) )
+ {
+ nAdobeEncoding = 1;
+ m_aEncoding = RTL_TEXTENCODING_UNICODE;
+ }
+ else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") )
+ nAdobeEncoding = 2;
+ else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") )
+ nAdobeEncoding = 3;
+
+ if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ m_aEncoding = nAdobeEncoding == 1 ?
+ RTL_TEXTENCODING_ADOBE_STANDARD : RTL_TEXTENCODING_SYMBOL;
+ }
+ else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ m_aEncoding = RTL_TEXTENCODING_ADOBE_STANDARD;
+
+ // try to parse the font name and decide wether it might be a
+ // japanese font. Who invented this PITA ?
+ OUString aPSNameLastToken( aPSName.copy( aPSName.lastIndexOf( '-' )+1 ) );
+ if( ! aPSNameLastToken.compareToAscii( "H" ) ||
+ ! aPSNameLastToken.compareToAscii( "V" ) )
+ {
+ static const char* pEncs[] =
+ {
+ "EUC",
+ "RKSJ",
+ "SJ"
+ };
+ static const rtl_TextEncoding aEncs[] =
+ {
+ RTL_TEXTENCODING_EUC_JP,
+ RTL_TEXTENCODING_SHIFT_JIS,
+ RTL_TEXTENCODING_JIS_X_0208
+ };
+
+ for( unsigned int enc = 0; enc < SAL_N_ELEMENTS( aEncs ) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ )
+ {
+ sal_Int32 nIndex = 0, nOffset = 1;
+ do
+ {
+ OUString aToken( aPSName.getToken( nOffset, '-', nIndex ) );
+ if( nIndex == -1 )
+ break;
+ nOffset = 0;
+ if( ! aToken.compareToAscii( pEncs[enc] ) )
+ {
+ m_aEncoding = aEncs[ enc ];
+ m_bFontEncodingOnly = true;
+ }
+ } while( nIndex != -1 );
+ }
+
+ // default is jis
+ if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ m_aEncoding = RTL_TEXTENCODING_JIS_X_0208;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName );
+#endif
+ }
+
+ // hack for GB encoded builtin fonts posing as FontSpecific
+ if( m_eType == fonttype::Builtin && ( nAdobeEncoding == 3 || nAdobeEncoding == 0 ) )
+ {
+ int nLen = aFamily.getLength();
+ if( nLen > 2 &&
+ aFamily.getStr()[ nLen-2 ] == 'G' &&
+ aFamily.getStr()[ nLen-1 ] == 'B' &&
+ pInfo->numOfChars > 255 )
+ {
+ m_aEncoding = RTL_TEXTENCODING_GBK;
+ m_bFontEncodingOnly = true;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found builtin font %s with GBK encoding\n", pInfo->gfi->fontName );
+#endif
+ }
+ }
+
+ // #i37313# check if Fontspecific is not rather some character encoding
+ if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
+ {
+ bool bYFound = false;
+ bool bQFound = false;
+ CharMetricInfo* pChar = pInfo->cmi;
+ for( int j = 0; j < pInfo->numOfChars && ! (bYFound && bQFound); j++ )
+ {
+ if( pChar[j].name )
+ {
+ if( pChar[j].name[0] == 'Y' && pChar[j].name[1] == 0 )
+ bYFound = true;
+ else if( pChar[j].name[0] == 'Q' && pChar[j].name[1] == 0 )
+ bQFound = true;
+ }
+ }
+ if( bQFound && bYFound )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "setting FontSpecific font %s (file %s) to unicode\n",
+ pInfo->gfi->fontName,
+ rFileName.getStr()
+ );
+ #endif
+ nAdobeEncoding = 4;
+ m_aEncoding = RTL_TEXTENCODING_UNICODE;
+ bFillEncodingvector = false; // will be filled anyway, don't do the work twice
+ }
+ }
+
+ // ascend
+ m_nAscend = pInfo->gfi->fontBBox.ury;
+
+ // descend
+ // descends have opposite sign of our definition
+ m_nDescend = -pInfo->gfi->fontBBox.lly;
+
+ // fallback to ascender, descender
+ // interesting: the BBox seems to describe Ascender and Descender better
+ // as we understand it
+ if( m_nAscend == 0 )
+ m_nAscend = pInfo->gfi->ascender;
+ if( m_nDescend == 0)
+ m_nDescend = -pInfo->gfi->descender;
+
+ m_nLeading = m_nAscend + m_nDescend - 1000;
+
+ if( m_pMetrics )
+ delete m_pMetrics;
+ m_pMetrics = new PrintFontMetrics;
+ // mark all pages as queried (or clear if only global font info queiried)
+ memset( m_pMetrics->m_aPages, bOnlyGlobalAttributes ? 0 : 0xff, sizeof( m_pMetrics->m_aPages ) );
+
+ m_aGlobalMetricX.width = m_aGlobalMetricY.width =
+ pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx;
+ m_aGlobalMetricX.height = m_aGlobalMetricY.height =
+ pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury;
+
+ m_nXMin = pInfo->gfi->fontBBox.llx;
+ m_nYMin = pInfo->gfi->fontBBox.lly;
+ m_nXMax = pInfo->gfi->fontBBox.urx;
+ m_nYMax = pInfo->gfi->fontBBox.ury;
+
+ if( bFillEncodingvector || !bOnlyGlobalAttributes )
+ {
+ // fill in character metrics
+
+ // first transform the character codes to unicode
+ // note: this only works with single byte encodings
+ sal_Unicode* pUnicodes = (sal_Unicode*)alloca( pInfo->numOfChars * sizeof(sal_Unicode));
+ CharMetricInfo* pChar = pInfo->cmi;
+ int i;
+
+ for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
+ {
+ if( nAdobeEncoding == 4 )
+ {
+ if( pChar->name )
+ {
+ pUnicodes[i] = 0;
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ {
+ m_aEncodingVector[ *it ] = pChar->code;
+ if( pChar->code == -1 )
+ m_aNonEncoded[ *it ] = pChar->name;
+ if( ! pUnicodes[i] ) // map the first
+ pUnicodes[i] = *it;
+ }
+ }
+ }
+ }
+ else if( pChar->code != -1 )
+ {
+ if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
+ {
+ pUnicodes[i] = pChar->code + 0xf000;
+ if( bFillEncodingvector )
+ m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
+ continue;
+ }
+
+ if( m_aEncoding == RTL_TEXTENCODING_UNICODE )
+ {
+ pUnicodes[i] = (sal_Unicode)pChar->code;
+ continue;
+ }
+
+ ByteString aTranslate;
+ if( pChar->code & 0xff000000 )
+ aTranslate += (char)(pChar->code >> 24 );
+ if( pChar->code & 0xffff0000 )
+ aTranslate += (char)((pChar->code & 0x00ff0000) >> 16 );
+ if( pChar->code & 0xffffff00 )
+ aTranslate += (char)((pChar->code & 0x0000ff00) >> 8 );
+ aTranslate += (char)(pChar->code & 0xff);
+ String aUni( aTranslate, m_aEncoding );
+ pUnicodes[i] = *aUni.GetBuffer();
+ }
+ else
+ pUnicodes[i] = 0;
+ }
+
+ // now fill in the character metrics
+ // parseAFM.cxx effectively only supports direction 0 (horizontal)
+ pChar = pInfo->cmi;
+ CharacterMetric aMetric;
+ for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
+ {
+ if( pChar->code == -1 && ! pChar->name )
+ continue;
+
+ if( bFillEncodingvector && pChar->name )
+ {
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ {
+ m_aEncodingVector[ *it ] = pChar->code;
+ if( pChar->code == -1 )
+ m_aNonEncoded[ *it ] = pChar->name;
+ }
+ }
+ }
+
+ aMetric.width = pChar->wx ? pChar->wx : pChar->charBBox.urx;
+ aMetric.height = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly;
+ if( aMetric.width == 0 && aMetric.height == 0 )
+ // guess something for e.g. space
+ aMetric.width = m_aGlobalMetricX.width/4;
+
+ if( ( nAdobeEncoding == 0 ) ||
+ ( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) )
+ {
+ if( pChar->code != -1 )
+ {
+ m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric;
+ if( bFillEncodingvector )
+ m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
+ }
+ else if( pChar->name )
+ {
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ m_pMetrics->m_aMetrics[ *it ] = aMetric;
+ }
+ }
+ }
+ else if( nAdobeEncoding == 1 || nAdobeEncoding == 2 || nAdobeEncoding == 4)
+ {
+ if( pChar->name )
+ {
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ m_pMetrics->m_aMetrics[ *it ] = aMetric;
+ }
+ }
+ else if( pChar->code != -1 )
+ {
+ ::std::pair< ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator,
+ ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator >
+ aCodes = rManager.getUnicodeFromAdobeCode( pChar->code );
+ while( aCodes.first != aCodes.second )
+ {
+ if( (*aCodes.first).second != 0 )
+ {
+ m_pMetrics->m_aMetrics[ (*aCodes.first).second ] = aMetric;
+ if( bFillEncodingvector )
+ m_aEncodingVector[ (*aCodes.first).second ] = pChar->code;
+ }
+ ++aCodes.first;
+ }
+ }
+ }
+ else if( nAdobeEncoding == 3 )
+ {
+ if( pChar->code != -1 )
+ {
+ sal_Unicode code = 0xf000 + pChar->code;
+ m_pMetrics->m_aMetrics[ code ] = aMetric;
+ // maybe should try to find the name in the convtabs ?
+ if( bFillEncodingvector )
+ m_aEncodingVector[ code ] = pChar->code;
+ }
+ }
+ }
+
+ m_pMetrics->m_aXKernPairs.clear();
+ m_pMetrics->m_aYKernPairs.clear();
+
+ // now fill in the kern pairs
+ // parseAFM.cxx effectively only supports direction 0 (horizontal)
+ PairKernData* pKern = pInfo->pkd;
+ KernPair aPair;
+ for( i = 0; i < pInfo->numOfPairs; i++, pKern++ )
+ {
+ // #i37703# broken kern table
+ if( ! pKern->name1 || ! pKern->name2 )
+ continue;
+
+ aPair.first = 0;
+ aPair.second = 0;
+ // currently we have to find the adobe character names
+ // in the already parsed character metrics to find
+ // the corresponding UCS2 code which is a bit dangerous
+ // since the character names are not required
+ // in the metric descriptions
+ pChar = pInfo->cmi;
+ for( int j = 0;
+ j < pInfo->numOfChars && ( aPair.first == 0 || aPair.second == 0 );
+ j++, pChar++ )
+ {
+ if( pChar->code != -1 )
+ {
+ if( ! strcmp( pKern->name1, pChar->name ? pChar->name : "" ) )
+ aPair.first = pUnicodes[ j ];
+ if( ! strcmp( pKern->name2, pChar->name ? pChar->name : "" ) )
+ aPair.second = pUnicodes[ j ];
+ }
+ }
+ if( aPair.first && aPair.second )
+ {
+ aPair.kern_x = pKern->xamt;
+ aPair.kern_y = pKern->yamt;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ }
+ }
+ m_pMetrics->m_bKernPairsQueried = true;
+ }
+
+ freeFontInfo( pInfo );
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::s_aEmptyOString;
+
+/*
+ * one instance only
+ */
+PrintFontManager& PrintFontManager::get()
+{
+ static PrintFontManager* pManager = NULL;
+ if( ! pManager )
+ {
+ static PrintFontManager theManager;
+ pManager = &theManager;
+ pManager->initialize();
+ }
+ return *pManager;
+}
+
+// -------------------------------------------------------------------------
+
+/*
+ * the PrintFontManager
+ */
+
+PrintFontManager::PrintFontManager() :
+ m_nNextFontID( 1 ),
+ m_pAtoms( new MultiAtomProvider() ),
+ m_nNextDirAtom( 1 ),
+ m_pFontCache( NULL ),
+ m_bFontconfigSuccess( false )
+{
+ for( unsigned int i = 0; i < SAL_N_ELEMENTS( aAdobeCodes ); i++ )
+ {
+ m_aUnicodeToAdobename.insert( ::boost::unordered_multimap< sal_Unicode, ::rtl::OString >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].pAdobename ) );
+ m_aAdobenameToUnicode.insert( ::boost::unordered_multimap< ::rtl::OString, sal_Unicode, ::rtl::OStringHash >::value_type( aAdobeCodes[i].pAdobename, aAdobeCodes[i].aUnicode ) );
+ if( aAdobeCodes[i].aAdobeStandardCode )
+ {
+ m_aUnicodeToAdobecode.insert( ::boost::unordered_multimap< sal_Unicode, sal_uInt8 >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].aAdobeStandardCode ) );
+ m_aAdobecodeToUnicode.insert( ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::value_type( aAdobeCodes[i].aAdobeStandardCode, aAdobeCodes[i].aUnicode ) );
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::~PrintFontManager()
+{
+ deinitFontconfig();
+ for( ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ delete (*it).second;
+ delete m_pAtoms;
+ if( m_pFontCache )
+ delete m_pFontCache;
+}
+
+// -------------------------------------------------------------------------
+
+const OString& PrintFontManager::getDirectory( int nAtom ) const
+{
+ ::boost::unordered_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
+ return it != m_aAtomToDir.end() ? it->second : s_aEmptyOString;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate )
+{
+ int nAtom = 0;
+ ::boost::unordered_map< OString, int, OStringHash >::const_iterator it
+ ( m_aDirToAtom.find( rDirectory ) );
+ if( it != m_aDirToAtom.end() )
+ nAtom = it->second;
+ else if( bCreate )
+ {
+ nAtom = m_nNextDirAtom++;
+ m_aDirToAtom[ rDirectory ] = nAtom;
+ m_aAtomToDir[ nAtom ] = rDirectory;
+ }
+ return nAtom;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::addFontFile( const ::rtl::OString& rFileName, int /*nFaceNum*/ )
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ OString aName( OUStringToOString( aPath.GetName(), aEncoding ) );
+ OString aDir( OUStringToOString( aPath.GetPath(), aEncoding ) );
+
+ int nDirID = getDirectoryAtom( aDir, true );
+ fontID nFontId = findFontFileID( nDirID, aName );
+ if( !nFontId )
+ {
+ ::std::list< PrintFont* > aNewFonts;
+ if( analyzeFontFile( nDirID, aName, ::std::list<OString>(), aNewFonts ) )
+ {
+ for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin();
+ it != aNewFonts.end(); ++it )
+ {
+ m_aFonts[ nFontId = m_nNextFontID++ ] = *it;
+ m_aFontFileToFontID[ aName ].insert( nFontId );
+ m_pFontCache->updateFontCacheEntry( *it, true );
+ }
+ }
+ }
+ return nFontId;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, const ::std::list<OString>& rXLFDs, ::std::list< PrintFontManager::PrintFont* >& rNewFonts ) const
+{
+ rNewFonts.clear();
+
+ OString aDir( getDirectory( nDirID ) );
+
+ OString aFullPath( aDir );
+ aFullPath += "/";
+ aFullPath += rFontFile;
+
+ // #i1872# reject unreadable files
+ if( access( aFullPath.getStr(), R_OK ) )
+ return false;
+
+ ByteString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
+ if( aExt.EqualsIgnoreCaseAscii( "pfb" ) || aExt.EqualsIgnoreCaseAscii( "pfa" ) )
+ {
+ // check for corresponding afm metric
+ // first look for an adjacent file
+ static const char* pSuffix[] = { ".afm", ".AFM" };
+
+ for( unsigned int i = 0; i < SAL_N_ELEMENTS(pSuffix); i++ )
+ {
+ ByteString aName( rFontFile );
+ aName.Erase( aName.Len()-4 );
+ aName.Append( pSuffix[i] );
+
+ ByteString aFilePath( aDir );
+ aFilePath.Append( '/' );
+ aFilePath.Append( aName );
+
+ ByteString aAfmFile;
+ if( access( aFilePath.GetBuffer(), R_OK ) )
+ {
+ // try in subdirectory afm instead
+ aFilePath = aDir;
+ aFilePath.Append( "/afm/" );
+ aFilePath.Append( aName );
+
+ if( ! access( aFilePath.GetBuffer(), R_OK ) )
+ {
+ aAfmFile = "afm/";
+ aAfmFile += aName;
+ }
+ }
+ else
+ aAfmFile = aName;
+
+ if( aAfmFile.Len() )
+ {
+ Type1FontFile* pFont = new Type1FontFile();
+ pFont->m_nDirectory = nDirID;
+
+ pFont->m_aFontFile = rFontFile;
+ pFont->m_aMetricFile = aAfmFile;
+
+ if( ! pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true ) )
+ {
+ delete pFont;
+ pFont = NULL;
+ }
+ if( pFont && rXLFDs.size() )
+ getFontAttributesFromXLFD( pFont, rXLFDs );
+ if( pFont )
+ rNewFonts.push_back( pFont );
+ break;
+ }
+ }
+ }
+ else if( aExt.EqualsIgnoreCaseAscii( "afm" ) )
+ {
+ ByteString aFilePath( aDir );
+ aFilePath.Append( '/' );
+ aFilePath.Append( ByteString( rFontFile ) );
+ BuiltinFont* pFont = new BuiltinFont();
+ pFont->m_nDirectory = nDirID;
+ pFont->m_aMetricFile = rFontFile;
+ if( pFont->readAfmMetrics( aFilePath, m_pAtoms, false, true ) )
+ rNewFonts.push_back( pFont );
+ else
+ delete pFont;
+ }
+ else if( aExt.EqualsIgnoreCaseAscii( "ttf" )
+ || aExt.EqualsIgnoreCaseAscii( "tte" ) // #i33947# for Gaiji support
+ || aExt.EqualsIgnoreCaseAscii( "otf" ) ) // check for TTF- and PS-OpenType too
+ {
+ TrueTypeFontFile* pFont = new TrueTypeFontFile();
+ pFont->m_nDirectory = nDirID;
+ pFont->m_aFontFile = rFontFile;
+ pFont->m_nCollectionEntry = -1;
+
+ if( rXLFDs.size() )
+ getFontAttributesFromXLFD( pFont, rXLFDs );
+ // need to read the font anyway to get aliases inside the font file
+ if( ! analyzeTrueTypeFile( pFont ) )
+ {
+ delete pFont;
+ pFont = NULL;
+ }
+ else
+ rNewFonts.push_back( pFont );
+ }
+ else if( aExt.EqualsIgnoreCaseAscii( "ttc" ) )
+ {
+ // get number of ttc entries
+ int nLength = CountTTCFonts( aFullPath.getStr() );
+ if( nLength )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s contains %d fonts\n", aFullPath.getStr(), nLength );
+#endif
+ for( int i = 0; i < nLength; i++ )
+ {
+ TrueTypeFontFile* pFont = new TrueTypeFontFile();
+ pFont->m_nDirectory = nDirID;
+ pFont->m_aFontFile = rFontFile;
+ pFont->m_nCollectionEntry = i;
+ if( nLength == 1 )
+ getFontAttributesFromXLFD( pFont, rXLFDs );
+ if( ! analyzeTrueTypeFile( pFont ) )
+ {
+ delete pFont;
+ pFont = NULL;
+ }
+ else
+ rNewFonts.push_back( pFont );
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "CountTTCFonts( \"%s/%s\" ) failed\n", getDirectory(nDirID).getStr(), rFontFile.getStr() );
+#endif
+ }
+ return ! rNewFonts.empty();
+}
+
+// -------------------------------------------------------------------------
+
+fontID PrintFontManager::findFontBuiltinID( int nPSNameAtom ) const
+{
+ fontID nID = 0;
+ ::boost::unordered_map< fontID, PrintFont* >::const_iterator it;
+ for( it = m_aFonts.begin(); nID == 0 && it != m_aFonts.end(); ++it )
+ {
+ if( it->second->m_eType == fonttype::Builtin &&
+ it->second->m_nPSName == nPSNameAtom )
+ nID = it->first;
+ }
+ return nID;
+}
+
+// -------------------------------------------------------------------------
+
+fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile ) const
+{
+ fontID nID = 0;
+
+ ::boost::unordered_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
+ if( set_it != m_aFontFileToFontID.end() )
+ {
+ for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end() && ! nID; ++font_it )
+ {
+ ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
+ if( it != m_aFonts.end() )
+ {
+ switch( it->second->m_eType )
+ {
+ case fonttype::Type1:
+ {
+ Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
+ if( pFont->m_nDirectory == nDirID &&
+ pFont->m_aFontFile == rFontFile )
+ nID = it->first;
+ }
+ break;
+ case fonttype::TrueType:
+ {
+ TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
+ if( pFont->m_nDirectory == nDirID &&
+ pFont->m_aFontFile == rFontFile )
+ nID = it->first;
+ }
+ break;
+ case fonttype::Builtin:
+ if( static_cast<const BuiltinFont*>((*it).second)->m_nDirectory == nDirID &&
+ static_cast<const BuiltinFont*>((*it).second)->m_aMetricFile == rFontFile )
+ nID = it->first;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return nID;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::parseXLFD( const OString& rXLFD, XLFDEntry& rEntry )
+{
+ sal_Int32 nIndex = 0;
+ OString aFoundry = WhitespaceToSpace( rXLFD.getToken( 1, '-', nIndex ) );
+ if( nIndex < 0 ) return false;
+ OString aFamilyXLFD = WhitespaceToSpace( rXLFD.getToken( 0, '-', nIndex ) );
+ if( nIndex < 0 ) return false;
+ OString aWeight = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aSlant = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aWidth = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aAddStyle = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aPitch = rXLFD.getToken( 4, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aRegEnc = WhitespaceToSpace( rXLFD.getToken( 1, '-', nIndex ).toAsciiLowerCase() );
+ if( nIndex < 0 ) return false;
+ OString aEnc = WhitespaceToSpace( rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase() );
+
+ // capitalize words
+ sal_Int32 nFamIndex = 0;
+ OStringBuffer aFamilyName;
+ while( nFamIndex >= 0 )
+ {
+ OString aToken = aFamilyXLFD.getToken( 0, ' ', nFamIndex );
+ sal_Char aFirst = aToken.toChar();
+ if( aFirst >= 'a' && aFirst <= 'z' )
+ aFirst = aFirst - 'a' + 'A';
+ OStringBuffer aNewToken( aToken.getLength() );
+ aNewToken.append( aToken );
+ aNewToken.setCharAt( 0, aFirst );
+ if( aFamilyName.getLength() > 0 )
+ aFamilyName.append( ' ' );
+ aFamilyName.append( aNewToken.makeStringAndClear() );
+ }
+
+ rEntry.aFoundry = aFoundry;
+ rEntry.aFamily = aFamilyName.makeStringAndClear();
+ rEntry.aAddStyle = aAddStyle;
+ // evaluate weight
+ rEntry.eWeight = parseWeight( aWeight );
+ // evaluate slant
+ rEntry.eItalic = parseItalic( aSlant );
+ // evaluate width
+ rEntry.eWidth = parseWidth( aWidth );
+
+ // evaluate pitch
+ if( aPitch.toChar() == 'c' || aPitch.toChar() == 'm' )
+ rEntry.ePitch = pitch::Fixed;
+ else
+ rEntry.ePitch = pitch::Variable;
+
+ OString aToken = aEnc.toAsciiLowerCase();
+ // get encoding
+ if( aAddStyle.indexOf( "symbol" ) != -1 )
+ rEntry.aEncoding = RTL_TEXTENCODING_SYMBOL;
+ else
+ {
+ if( aToken.equals( "symbol" ) )
+ rEntry.aEncoding = RTL_TEXTENCODING_SYMBOL;
+ else
+ {
+ OStringBuffer aCharset( aRegEnc.getLength() + aEnc.getLength() + 1 );
+ aCharset.append( aRegEnc );
+ aCharset.append( '-' );
+ aCharset.append( aEnc );
+ rEntry.aEncoding = rtl_getTextEncodingFromUnixCharset( aCharset.getStr() );
+ }
+ }
+
+ // set correct mask flags
+ rEntry.nMask = 0;
+ if( rEntry.aFoundry != "*" ) rEntry.nMask |= XLFDEntry::MaskFoundry;
+ if( rEntry.aFamily != "*" ) rEntry.nMask |= XLFDEntry::MaskFamily;
+ if( rEntry.aAddStyle != "*" ) rEntry.nMask |= XLFDEntry::MaskAddStyle;
+ if( aWeight != "*" ) rEntry.nMask |= XLFDEntry::MaskWeight;
+ if( aSlant != "*" ) rEntry.nMask |= XLFDEntry::MaskItalic;
+ if( aWidth != "*" ) rEntry.nMask |= XLFDEntry::MaskWidth;
+ if( aPitch != "*" ) rEntry.nMask |= XLFDEntry::MaskPitch;
+ if( aRegEnc != "*" && aEnc != "*" ) rEntry.nMask |= XLFDEntry::MaskEncoding;
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::parseXLFD_appendAliases( const std::list< OString >& rXLFDs, std::list< XLFDEntry >& rEntries ) const
+{
+ for( std::list< OString >::const_iterator it = rXLFDs.begin(); it != rXLFDs.end(); ++it )
+ {
+ XLFDEntry aEntry;
+ if( ! parseXLFD(*it, aEntry) )
+ continue;
+ rEntries.push_back( aEntry );
+ std::map< XLFDEntry, std::list< XLFDEntry > >::const_iterator alias_it =
+ m_aXLFD_Aliases.find( aEntry );
+ if( alias_it != m_aXLFD_Aliases.end() )
+ {
+ rEntries.insert( rEntries.end(), alias_it->second.begin(), alias_it->second.end() );
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::getFontAttributesFromXLFD( PrintFont* pFont, const std::list< OString >& rXLFDs ) const
+{
+ bool bFamilyName = false;
+
+ std::list< XLFDEntry > aXLFDs;
+
+ parseXLFD_appendAliases( rXLFDs, aXLFDs );
+
+ for( std::list< XLFDEntry >::const_iterator it = aXLFDs.begin();
+ it != aXLFDs.end(); ++it )
+ {
+ // set family name or alias
+ int nFam =
+ m_pAtoms->getAtom( ATOM_FAMILYNAME,
+ OStringToOUString( it->aFamily, it->aAddStyle.indexOf( "utf8" ) != -1 ? RTL_TEXTENCODING_UTF8 : RTL_TEXTENCODING_ISO_8859_1 ),
+ sal_True );
+ if( ! bFamilyName )
+ {
+ bFamilyName = true;
+ pFont->m_nFamilyName = nFam;
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1:
+ static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ case fonttype::TrueType:
+ static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // make sure that aliases are unique
+ if( nFam != pFont->m_nFamilyName )
+ {
+ std::list< int >::const_iterator al_it;
+ for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nFam; ++al_it )
+ ;
+ if( al_it == pFont->m_aAliases.end() )
+ pFont->m_aAliases.push_back( nFam );
+
+ }
+ // for the rest of the attributes there can only be one value;
+ // we'll trust the first one
+ continue;
+ }
+
+ // fill in weight
+ pFont->m_eWeight = it->eWeight;
+ // fill in slant
+ pFont->m_eItalic = it->eItalic;
+ // fill in width
+ pFont->m_eWidth = it->eWidth;
+ // fill in pitch
+ pFont->m_ePitch = it->ePitch;
+ // fill in encoding
+ pFont->m_aEncoding = it->aEncoding;
+ }
+
+ // handle iso8859-1 as ms1252 to fill the "gap" starting at 0x80
+ if( pFont->m_aEncoding == RTL_TEXTENCODING_ISO_8859_1 )
+ pFont->m_aEncoding = RTL_TEXTENCODING_MS_1252;
+ if( rXLFDs.begin() != rXLFDs.end() )
+ {
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1:
+ static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ case fonttype::TrueType:
+ static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ default: break;
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::getXLFD( PrintFont* pFont ) const
+{
+ if( pFont->m_eType == fonttype::Type1 )
+ {
+ if( static_cast<Type1FontFile*>(pFont)->m_aXLFD.getLength() )
+ return static_cast<Type1FontFile*>(pFont)->m_aXLFD;
+ }
+ if( pFont->m_eType == fonttype::TrueType )
+ {
+ if( static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD.getLength() )
+ return static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD;
+ }
+
+ OStringBuffer aXLFD( 128 );
+
+ aXLFD.append( "-misc-" );
+ ByteString aFamily( String( m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ) ), RTL_TEXTENCODING_UTF8 );
+ aFamily.SearchAndReplaceAll( '-',' ' );
+ aFamily.SearchAndReplaceAll( '?',' ' );
+ aFamily.SearchAndReplaceAll( '*',' ' );
+ aXLFD.append( OString( aFamily ) );
+ aXLFD.append( '-' );
+ switch( pFont->m_eWeight )
+ {
+ case weight::Thin: aXLFD.append("thin");break;
+ case weight::UltraLight: aXLFD.append("ultralight");break;
+ case weight::Light: aXLFD.append("light");break;
+ case weight::SemiLight: aXLFD.append("semilight");break;
+ case weight::Normal: aXLFD.append("normal");break;
+ case weight::Medium: aXLFD.append("medium");break;
+ case weight::SemiBold: aXLFD.append("semibold");break;
+ case weight::Bold: aXLFD.append("bold");break;
+ case weight::UltraBold: aXLFD.append("ultrabold");break;
+ case weight::Black: aXLFD.append("black");break;
+ default: break;
+ }
+ aXLFD.append('-');
+ switch( pFont->m_eItalic )
+ {
+ case italic::Upright: aXLFD.append('r');break;
+ case italic::Oblique: aXLFD.append('o');break;
+ case italic::Italic: aXLFD.append('i');break;
+ default: break;
+ }
+ aXLFD.append('-');
+ switch( pFont->m_eWidth )
+ {
+ case width::UltraCondensed: aXLFD.append("ultracondensed");break;
+ case width::ExtraCondensed: aXLFD.append("extracondensed");break;
+ case width::Condensed: aXLFD.append("condensed");break;
+ case width::SemiCondensed: aXLFD.append("semicondensed");break;
+ case width::Normal: aXLFD.append("normal");break;
+ case width::SemiExpanded: aXLFD.append("semiexpanded");break;
+ case width::Expanded: aXLFD.append("expanded");break;
+ case width::ExtraExpanded: aXLFD.append("extraexpanded");break;
+ case width::UltraExpanded: aXLFD.append("ultraexpanded");break;
+ default: break;
+ }
+ aXLFD.append("-utf8-0-0-0-0-");
+ aXLFD.append( pFont->m_ePitch == pitch::Fixed ? "m" : "p" );
+ aXLFD.append("-0-");
+ const char* pEnc = rtl_getBestUnixCharsetFromTextEncoding( pFont->m_aEncoding );
+ if( ! pEnc )
+ {
+ if( pFont->m_aEncoding == RTL_TEXTENCODING_ADOBE_STANDARD )
+ pEnc = "adobe-standard";
+ else
+ pEnc = "iso8859-1";
+ }
+ aXLFD .append( pEnc );
+
+ return aXLFD.makeStringAndClear();
+}
+
+// -------------------------------------------------------------------------
+
+OUString PrintFontManager::convertTrueTypeName( void* pRecord ) const
+{
+ NameRecord* pNameRecord = (NameRecord*)pRecord;
+ OUString aValue;
+ if(
+ ( pNameRecord->platformID == 3 && ( pNameRecord->encodingID == 0 || pNameRecord->encodingID == 1 ) ) // MS, Unicode
+ ||
+ ( pNameRecord->platformID == 0 ) // Apple, Unicode
+ )
+ {
+ OUStringBuffer aName( pNameRecord->slen/2 );
+ const sal_uInt8* pNameBuffer = pNameRecord->sptr;
+ for(int n = 0; n < pNameRecord->slen/2; n++ )
+ aName.append( (sal_Unicode)getUInt16BE( pNameBuffer ) );
+ aValue = aName.makeStringAndClear();
+ }
+ else if( pNameRecord->platformID == 3 )
+ {
+ if( pNameRecord->encodingID >= 2 && pNameRecord->encodingID <= 6 )
+ {
+ /*
+ * and now for a special kind of madness:
+ * some fonts encode their byte value string as BE uint16
+ * (leading to stray zero bytes in the string)
+ * while others code two bytes as a uint16 and swap to BE
+ */
+ OStringBuffer aName;
+ const sal_uInt8* pNameBuffer = pNameRecord->sptr;
+ for(int n = 0; n < pNameRecord->slen/2; n++ )
+ {
+ sal_Unicode aCode = (sal_Unicode)getUInt16BE( pNameBuffer );
+ sal_Char aChar = aCode >> 8;
+ if( aChar )
+ aName.append( aChar );
+ aChar = aCode & 0x00ff;
+ if( aChar )
+ aName.append( aChar );
+ }
+ switch( pNameRecord->encodingID )
+ {
+ case 2:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_932 );
+ break;
+ case 3:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_936 );
+ break;
+ case 4:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_950 );
+ break;
+ case 5:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_949 );
+ break;
+ case 6:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_1361 );
+ break;
+ }
+ }
+ }
+ return aValue;
+}
+
+//fdo#33349.There exists an archaic Berling Antiqua font which has a "Times New
+//Roman" name field in it. We don't want the "Times New Roman" name to take
+//precedence in this case. We take Berling Antiqua as a higher priority name,
+//and erase the "Times New Roman" name
+namespace
+{
+ bool isBadTNR(const OUString &rName, ::std::set< OUString >& rSet)
+ {
+ bool bRet = false;
+ if (rName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Berling Antiqua")))
+ {
+ ::std::set< OUString >::iterator aEnd = rSet.end();
+ ::std::set< OUString >::iterator aI = rSet.find(OUString(RTL_CONSTASCII_USTRINGPARAM("Times New Roman")));
+ if (aI != aEnd)
+ {
+ bRet = true;
+ rSet.erase(aI);
+ }
+ }
+ return bRet;
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont, ::std::list< OUString >& rNames ) const
+{
+ OUString aFamily;
+
+ rNames.clear();
+ ::std::set< OUString > aSet;
+
+ NameRecord* pNameRecords = NULL;
+ int nNameRecords = GetTTNameRecords( (TrueTypeFont*)pTTFont, &pNameRecords );
+ if( nNameRecords && pNameRecords )
+ {
+ LanguageType aLang = MsLangId::getSystemLanguage();
+ int nLastMatch = -1;
+ for( int i = 0; i < nNameRecords; i++ )
+ {
+ if( pNameRecords[i].nameID != 1 || pNameRecords[i].sptr == NULL )
+ continue;
+ int nMatch = -1;
+ if( pNameRecords[i].platformID == 0 ) // Unicode
+ nMatch = 4000;
+ else if( pNameRecords[i].platformID == 3 )
+ {
+ // this bases on the LanguageType actually being a Win LCID
+ if( pNameRecords[i].languageID == aLang )
+ nMatch = 8000;
+ else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
+ nMatch = 2000;
+ else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH ||
+ pNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
+ nMatch = 1500;
+ else
+ nMatch = 1000;
+ }
+ OUString aName = convertTrueTypeName( pNameRecords + i );
+ aSet.insert( aName );
+ if( nMatch > nLastMatch || isBadTNR(aName, aSet) )
+ {
+ nLastMatch = nMatch;
+ aFamily = aName;
+ }
+ }
+ DisposeNameRecords( pNameRecords, nNameRecords );
+ }
+ if( aFamily.getLength() )
+ {
+ rNames.push_front( aFamily );
+ for( ::std::set< OUString >::const_iterator it = aSet.begin(); it != aSet.end(); ++it )
+ if( *it != aFamily )
+ rNames.push_back( *it );
+ }
+ return;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const
+{
+ bool bSuccess = false;
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ ByteString aFile = getFontFile( pFont );
+ TrueTypeFont* pTTFont = NULL;
+
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ TTGlobalFontInfo aInfo;
+ GetTTGlobalFontInfo( pTTFont, & aInfo );
+
+ ::std::list< OUString > aNames;
+ analyzeTrueTypeFamilyName( pTTFont, aNames );
+
+ // set family name from XLFD if possible
+ if( ! pFont->m_nFamilyName )
+ {
+ if( aNames.begin() != aNames.end() )
+ {
+ pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, aNames.front(), sal_True );
+ aNames.pop_front();
+ }
+ else
+ {
+ sal_Int32 dotIndex;
+
+ // poor font does not have a family name
+ // name it to file name minus the extension
+ dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' );
+ if ( dotIndex == -1 )
+ dotIndex = pTTFontFile->m_aFontFile.getLength();
+
+ pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), sal_True );
+ }
+ }
+ for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it )
+ {
+ if( it->getLength() )
+ {
+ int nAlias = m_pAtoms->getAtom( ATOM_FAMILYNAME, *it, sal_True );
+ if( nAlias != pFont->m_nFamilyName )
+ {
+ std::list< int >::const_iterator al_it;
+ for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nAlias; ++al_it )
+ ;
+ if( al_it == pFont->m_aAliases.end() )
+ pFont->m_aAliases.push_back( nAlias );
+ }
+ }
+ }
+
+ if( aInfo.usubfamily )
+ pFont->m_aStyleName = OUString( aInfo.usubfamily );
+
+ pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, String( ByteString( aInfo.psname ), aEncoding ), sal_True );
+ switch( aInfo.weight )
+ {
+ case FW_THIN: pFont->m_eWeight = weight::Thin; break;
+ case FW_EXTRALIGHT: pFont->m_eWeight = weight::UltraLight; break;
+ case FW_LIGHT: pFont->m_eWeight = weight::Light; break;
+ case FW_MEDIUM: pFont->m_eWeight = weight::Medium; break;
+ case FW_SEMIBOLD: pFont->m_eWeight = weight::SemiBold; break;
+ case FW_BOLD: pFont->m_eWeight = weight::Bold; break;
+ case FW_EXTRABOLD: pFont->m_eWeight = weight::UltraBold; break;
+ case FW_BLACK: pFont->m_eWeight = weight::Black; break;
+
+ case FW_NORMAL:
+ default: pFont->m_eWeight = weight::Normal; break;
+ }
+
+ switch( aInfo.width )
+ {
+ case FWIDTH_ULTRA_CONDENSED: pFont->m_eWidth = width::UltraCondensed; break;
+ case FWIDTH_EXTRA_CONDENSED: pFont->m_eWidth = width::ExtraCondensed; break;
+ case FWIDTH_CONDENSED: pFont->m_eWidth = width::Condensed; break;
+ case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = width::SemiCondensed; break;
+ case FWIDTH_SEMI_EXPANDED: pFont->m_eWidth = width::SemiExpanded; break;
+ case FWIDTH_EXPANDED: pFont->m_eWidth = width::Expanded; break;
+ case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = width::ExtraExpanded; break;
+ case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = width::UltraExpanded; break;
+
+ case FWIDTH_NORMAL:
+ default: pFont->m_eWidth = width::Normal; break;
+ }
+
+ pFont->m_ePitch = aInfo.pitch ? pitch::Fixed : pitch::Variable;
+ pFont->m_eItalic = aInfo.italicAngle == 0 ? italic::Upright : ( aInfo.italicAngle < 0 ? italic::Italic : italic::Oblique );
+ // #104264# there are fonts that set italic angle 0 although they are
+ // italic; use macstyle bit here
+ if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
+ pFont->m_eItalic = italic::Italic;
+
+ pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2;
+
+ pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin;
+ pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin;
+
+ if( aInfo.winAscent && aInfo.winDescent )
+ {
+ pFont->m_nAscend = aInfo.winAscent;
+ pFont->m_nDescend = aInfo.winDescent;
+ pFont->m_nLeading = pFont->m_nAscend + pFont->m_nDescend - 1000;
+ }
+ else if( aInfo.typoAscender && aInfo.typoDescender )
+ {
+ pFont->m_nLeading = aInfo.typoLineGap;
+ pFont->m_nAscend = aInfo.typoAscender;
+ pFont->m_nDescend = -aInfo.typoDescender;
+ }
+ else
+ {
+ pFont->m_nLeading = aInfo.linegap;
+ pFont->m_nAscend = aInfo.ascender;
+ pFont->m_nDescend = -aInfo.descender;
+ }
+
+ // last try: font bounding box
+ if( pFont->m_nAscend == 0 )
+ pFont->m_nAscend = aInfo.yMax;
+ if( pFont->m_nDescend == 0 )
+ pFont->m_nDescend = -aInfo.yMin;
+ if( pFont->m_nLeading == 0 )
+ pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100;
+
+ if( pFont->m_nAscend )
+ pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend;
+
+ // get bounding box
+ pFont->m_nXMin = aInfo.xMin;
+ pFont->m_nYMin = aInfo.yMin;
+ pFont->m_nXMax = aInfo.xMax;
+ pFont->m_nYMax = aInfo.yMax;
+
+ // get type flags
+ pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
+
+ // get vertical substitutions flag
+ pFont->m_bHaveVerticalSubstitutedGlyphs = DoesVerticalSubstitution( pTTFont, 1 );
+
+ CloseTTFont( pTTFont );
+ bSuccess = true;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "could not OpenTTFont \"%s\"\n", aFile.GetBuffer() );
+#endif
+
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::initFontsAlias()
+{
+ m_aXLFD_Aliases.clear();
+ rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
+ for( std::list< OString >::const_iterator dir_it = m_aFontDirectories.begin();
+ dir_it != m_aFontDirectories.end(); ++dir_it )
+ {
+ OStringBuffer aDirName(512);
+ aDirName.append( *dir_it );
+ aDirName.append( "/fonts.alias" );
+ SvFileStream aStream( OStringToOUString( aDirName.makeStringAndClear(), aEnc ), STREAM_READ );
+ if( ! aStream.IsOpen() )
+ continue;
+
+ do
+ {
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+
+ // get the alias and the pattern it gets translated to
+ ByteString aAlias = GetCommandLineToken( 0, aLine );
+ ByteString aMap = GetCommandLineToken( 1, aLine );
+
+ // remove eventual quotes
+ aAlias.EraseLeadingChars( '"' );
+ aAlias.EraseTrailingChars( '"' );
+ aMap.EraseLeadingChars( '"' );
+ aMap.EraseTrailingChars( '"' );
+
+ XLFDEntry aAliasEntry, aMapEntry;
+ parseXLFD( aAlias, aAliasEntry );
+ parseXLFD( aMap, aMapEntry );
+
+ if( aAliasEntry.nMask && aMapEntry.nMask )
+ m_aXLFD_Aliases[ aMapEntry ].push_back( aAliasEntry );
+ } while( ! aStream.IsEof() );
+ }
+}
+
+// code stolen from vcl's RegisterFontSubstitutors()
+// TODO: use that method once psprint gets merged into vcl
+static bool AreFCSubstitutionsEnabled()
+{
+ // init font substitution defaults
+ int nDisableBits = 0;
+#ifdef SOLARIS
+ // TODO: check the OS version and fc-data maintenance level
+ nDisableBits = 1; // disable "font fallback" here on default
+#endif
+ // apply the environment variable if any
+ const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
+ if( pEnvStr )
+ {
+ //
+ if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
+ nDisableBits = (*pEnvStr - '0');
+ else
+ nDisableBits = ~0U; // no specific bits set: disable all
+ }
+
+ return ((nDisableBits & 3) == 0);
+}
+
+void PrintFontManager::initialize()
+{
+ #ifdef CALLGRIND_COMPILE
+ CALLGRIND_TOGGLE_COLLECT();
+ CALLGRIND_ZERO_STATS();
+ #endif
+
+ long aDirEntBuffer[ (sizeof(struct dirent)+_PC_NAME_MAX)+1 ];
+
+ if( ! m_pFontCache )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "creating font cache ... " );
+ clock_t aStart;
+ struct tms tms;
+ aStart = times( &tms );
+#endif
+ m_pFontCache = new FontCache();
+#if OSL_DEBUG_LEVEL > 1
+ clock_t aStop = times( &tms );
+ fprintf( stderr, "done in %lf s\n", (double)(aStop - aStart)/(double)sysconf( _SC_CLK_TCK ) );
+#endif
+ }
+
+ // initialize may be called twice in the future
+ {
+ for( ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ delete (*it).second;
+ m_nNextFontID = 1;
+ m_aFonts.clear();
+ m_aFontDirectories.clear();
+ m_aPrivateFontDirectories.clear();
+ m_aOverrideFonts.clear();
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ clock_t aStart;
+ clock_t aStep1;
+ clock_t aStep2;
+ clock_t aStep3;
+ int nBuiltinFonts = 0;
+ int nCached = 0;
+
+ struct tms tms;
+
+ aStart = times( &tms );
+#endif
+
+ // first try fontconfig
+ m_bFontconfigSuccess = initFontconfig();
+
+ // part one - look for downloadable fonts
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ const ::rtl::OUString &rSalPrivatePath = psp::getFontPath();
+
+ // search for the fonts in SAL_PRIVATE_FONTPATH first; those are
+ // the fonts installed with the office
+ if( rSalPrivatePath.getLength() )
+ {
+ OString aPath = rtl::OUStringToOString( rSalPrivatePath, aEncoding );
+ const bool bAreFCSubstitutionsEnabled = AreFCSubstitutionsEnabled();
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OString aToken = aPath.getToken( 0, ';', nIndex );
+ normPath( aToken );
+ // if registering an app-specific fontdir with fontconfig fails
+ // and fontconfig-based substitutions are enabled
+ // then trying to use these app-specific fonts doesn't make sense
+ if( m_bFontconfigSuccess && !addFontconfigDir( aToken ) )
+ if( bAreFCSubstitutionsEnabled )
+ continue;
+ m_aFontDirectories.push_back( aToken );
+ m_aPrivateFontDirectories.push_back( getDirectoryAtom( aToken, true ) );
+ } while( nIndex >= 0 );
+ }
+
+ // protect against duplicate paths
+ boost::unordered_map< OString, int, OStringHash > visited_dirs;
+
+ // now that all global and local font dirs are known to fontconfig
+ // check that there are fonts actually managed by fontconfig
+ // also don't search directories that fontconfig already did
+ if( m_bFontconfigSuccess )
+ m_bFontconfigSuccess = (countFontconfigFonts( visited_dirs ) > 0);
+
+ // don't search through many directories fontconfig already told us about
+ if( ! m_bFontconfigSuccess )
+ ImplGetSVData()->mpDefInst->FillFontPathList( m_aFontDirectories );
+
+ // fill XLFD aliases from fonts.alias files
+ initFontsAlias();
+
+ // search for font files in each path
+ std::list< OString >::iterator dir_it;
+ for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it )
+ {
+ OString aPath( *dir_it );
+ // see if we were here already
+ if( visited_dirs.find( aPath ) != visited_dirs.end() )
+ continue;
+ visited_dirs[ aPath ] = 1;
+
+ // there may be ":unscaled" directories (see XFree86)
+ // it should be safe to ignore them since they should not
+ // contain any of our recognizeable fonts
+
+ // ask the font cache whether it handles this directory
+ std::list< PrintFont* > aCacheFonts;
+ if( m_pFontCache->listDirectory( aPath, aCacheFonts ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "adding cache directory: %s\n", aPath.getStr() );
+#endif
+ for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
+ {
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = *it;
+ if( (*it)->m_eType == fonttype::Type1 )
+ m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::TrueType )
+ m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::Builtin )
+ m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
+#if OSL_DEBUG_LEVEL > 1
+ if( (*it)->m_eType == fonttype::Builtin )
+ nBuiltinFonts++;
+ nCached++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "adding cached font %d: \"%s\" from %s\n", aFont,
+ OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
+ getFontFileSysPath( aFont ).getStr() );
+#endif
+#endif
+ }
+ if( ! m_pFontCache->scanAdditionalFiles( aPath ) )
+ continue;
+ }
+
+ DIR* pDIR = opendir( aPath.getStr() );
+ struct dirent* pEntry = (struct dirent*)aDirEntBuffer;
+ if( pDIR )
+ {
+ // read fonts.dir if possible
+ ::boost::unordered_map< OString, ::std::list<OString>, OStringHash > aFontsDir;
+ int nDirID = getDirectoryAtom( aPath, true );
+ // #i38367# no fonts.dir in our own directories anymore
+ std::list< int >::const_iterator priv_dir;
+ for( priv_dir = m_aPrivateFontDirectories.begin();
+ priv_dir != m_aPrivateFontDirectories.end() && *priv_dir != nDirID;
+ ++priv_dir )
+ ;
+
+ if( priv_dir == m_aPrivateFontDirectories.end() )
+ {
+ ByteString aGccDummy( aPath );
+ String aFontsDirPath( aGccDummy, aEncoding );
+ aFontsDirPath.AppendAscii( "/fonts.dir" );
+ SvFileStream aStream( aFontsDirPath, STREAM_READ );
+ if( aStream.IsOpen() )
+ {
+ ByteString aLine;
+ while( ! aStream.IsEof() )
+ {
+ aStream.ReadLine( aLine );
+ ByteString aFileName( GetCommandLineToken( 0, aLine ) );
+ ByteString aXLFD( aLine.Copy( aFileName.Len() ) );
+ if( aFileName.Len() && aXLFD.Len() )
+ aFontsDir[ aFileName ].push_back(aXLFD);
+ }
+ }
+ }
+
+ int nDirFonts = 0;
+ while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pEntry ) && pEntry )
+ {
+ OString aFileName( pEntry->d_name );
+ // ignore .afm files here
+ if( aFileName.getLength() > 3 &&
+ aFileName.lastIndexOf( ".afm" ) == aFileName.getLength()-4 )
+ continue;
+
+ struct stat aStat;
+ ByteString aFilePath( aPath );
+ aFilePath.Append( '/' );
+ aFilePath.Append( ByteString( aFileName ) );
+ if( ! stat( aFilePath.GetBuffer(), &aStat ) &&
+ S_ISREG( aStat.st_mode ) )
+ {
+ if( findFontFileID( nDirID, aFileName ) == 0 )
+ {
+ ::std::list<OString> aXLFDs;
+ ::boost::unordered_map< OString, ::std::list<OString>, OStringHash >::const_iterator it =
+ aFontsDir.find( aFileName );
+ if( it != aFontsDir.end() )
+ aXLFDs = (*it).second;
+
+ // fill in font attributes from XLFD rather
+ // than reading every file
+ ::std::list< PrintFont* > aNewFonts;
+ if( analyzeFontFile( nDirID, aFileName, aXLFDs, aNewFonts ) )
+ {
+ for( ::std::list< PrintFont* >::iterator font_it = aNewFonts.begin(); font_it != aNewFonts.end(); ++font_it )
+ {
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = *font_it;
+ m_aFontFileToFontID[ aFileName ].insert( aFont );
+ m_pFontCache->updateFontCacheEntry( *font_it, false );
+ nDirFonts++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "adding font %d: \"%s\" from %s\n", aFont,
+ OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
+ getFontFileSysPath( aFont ).getStr() );
+#endif
+ }
+ }
+ }
+ }
+ }
+ closedir( pDIR );
+ m_pFontCache->updateDirTimestamp( nDirID );
+ if( ! nDirFonts )
+ m_pFontCache->markEmptyDir( nDirID );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep1 = times( &tms );
+#endif
+
+ // part two - look for metrics for builtin printer fonts
+ std::list< OUString > aMetricDirs;
+ psp::getPrinterPathList( aMetricDirs, PRINTER_METRICDIR );
+
+ std::list< OString > aEmptyFontsDir;
+ for( std::list< OUString >::const_iterator met_dir_it = aMetricDirs.begin(); met_dir_it != aMetricDirs.end(); ++met_dir_it )
+ {
+ OString aDir = OUStringToOString( *met_dir_it, aEncoding );
+
+ // ask the font cache whether it handles this directory
+ std::list< PrintFont* > aCacheFonts;
+
+ if( m_pFontCache->listDirectory( aDir, aCacheFonts ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "adding cache directory: %s\n", aDir.getStr() );
+#endif
+ for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
+ {
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = *it;
+ if( (*it)->m_eType == fonttype::Type1 )
+ m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::TrueType )
+ m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::Builtin )
+ m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
+#if OSL_DEBUG_LEVEL > 1
+ if( (*it)->m_eType == fonttype::Builtin )
+ nBuiltinFonts++;
+ nCached++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "adding cached font %d: \"%s\" from %s\n", aFont,
+ OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
+ getFontFileSysPath( aFont ).getStr() );
+#endif
+#endif
+ }
+ continue;
+ }
+
+ DIR* pDIR = opendir( aDir.getStr() );
+ if( pDIR )
+ {
+ struct dirent* pDirEntry = (struct dirent*)aDirEntBuffer;
+ int nDirID = getDirectoryAtom( aDir, true );
+ int nDirFonts = 0;
+
+ while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pDirEntry ) && pDirEntry )
+ {
+ ByteString aFile( aDir );
+ aFile += '/';
+ aFile += pDirEntry->d_name;
+ struct stat aStat;
+ if( ! stat( aFile.GetBuffer(), &aStat )
+ && S_ISREG( aStat.st_mode )
+ )
+ {
+ OString aFileName( pDirEntry->d_name, strlen( pDirEntry->d_name ) );
+ OString aExt( aFileName.copy( aFileName.lastIndexOf( '.' )+1 ) );
+ if( aExt.equalsIgnoreAsciiCase( "afm" ) )
+ {
+ ::std::list< PrintFont* > aNewFonts;
+
+ analyzeFontFile( nDirID, aFileName, aEmptyFontsDir, aNewFonts );
+ for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
+ {
+ if( findFontBuiltinID( (*it)->m_nPSName ) == 0 )
+ {
+ m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
+ m_aFonts[ m_nNextFontID++ ] = *it;
+ m_pFontCache->updateFontCacheEntry( *it, false );
+#if OSL_DEBUG_LEVEL > 2
+ nBuiltinFonts++;
+#endif
+ }
+ else
+ delete *it;
+ }
+ }
+ }
+ }
+ closedir( pDIR );
+ if( ! nDirFonts )
+ m_pFontCache->markEmptyDir( nDirID );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep2 = times( &tms );
+#endif
+
+ // part three - fill in family styles
+ ::boost::unordered_map< fontID, PrintFont* >::iterator font_it;
+ for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it)
+ {
+ ::boost::unordered_map< int, family::type >::const_iterator it =
+ m_aFamilyTypes.find( font_it->second->m_nFamilyName );
+ if (it != m_aFamilyTypes.end())
+ continue;
+ const ::rtl::OUString& rFamily =
+ m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName);
+ family::type eType = matchFamilyName( rFamily );
+ m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType;
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep3 = times( &tms );
+ fprintf( stderr, "PrintFontManager::initialize: collected %" SAL_PRI_SIZET "u fonts (%d builtin, %d cached)\n", m_aFonts.size(), nBuiltinFonts, nCached );
+ double fTick = (double)sysconf( _SC_CLK_TCK );
+ fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/fTick );
+ fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/fTick );
+ fprintf( stderr, "Step 3 took %lf seconds\n", (double)(aStep3 - aStep2)/fTick );
+#endif
+
+ m_pFontCache->flush();
+
+ #ifdef CALLGRIND_COMPILE
+ CALLGRIND_DUMP_STATS();
+ CALLGRIND_TOGGLE_COLLECT();
+ #endif
+}
+
+// -------------------------------------------------------------------------
+inline bool
+equalPitch (psp::pitch::type from, psp::pitch::type to)
+{
+ return from == to;
+}
+
+inline bool
+equalWeight (psp::weight::type from, psp::weight::type to)
+{
+ return from > to ? (from - to) <= 3 : (to - from) <= 3;
+}
+
+inline bool
+equalItalic (psp::italic::type from, psp::italic::type to)
+{
+ if ( (from == psp::italic::Italic) || (from == psp::italic::Oblique) )
+ return (to == psp::italic::Italic) || (to == psp::italic::Oblique);
+ return to == from;
+}
+inline bool
+equalEncoding (rtl_TextEncoding from, rtl_TextEncoding to)
+{
+ if ((from == RTL_TEXTENCODING_ISO_8859_1) || (from == RTL_TEXTENCODING_MS_1252))
+ return (to == RTL_TEXTENCODING_ISO_8859_1) || (to == RTL_TEXTENCODING_MS_1252);
+ return from == to;
+}
+
+namespace {
+ struct BuiltinFontIdentifier
+ {
+ OUString aFamily;
+ italic::type eItalic;
+ weight::type eWeight;
+ pitch::type ePitch;
+ rtl_TextEncoding aEncoding;
+
+ BuiltinFontIdentifier( const OUString& rFam,
+ italic::type eIt,
+ weight::type eWg,
+ pitch::type ePt,
+ rtl_TextEncoding enc ) :
+ aFamily( rFam ),
+ eItalic( eIt ),
+ eWeight( eWg ),
+ ePitch( ePt ),
+ aEncoding( enc )
+ {}
+
+ bool operator==( const BuiltinFontIdentifier& rRight ) const
+ {
+ return equalItalic( eItalic, rRight.eItalic ) &&
+ equalWeight( eWeight, rRight.eWeight ) &&
+ equalPitch( ePitch, rRight.ePitch ) &&
+ equalEncoding( aEncoding, rRight.aEncoding ) &&
+ aFamily.equalsIgnoreAsciiCase( rRight.aFamily );
+ }
+ };
+
+ struct BuiltinFontIdentifierHash
+ {
+ size_t operator()( const BuiltinFontIdentifier& rFont ) const
+ {
+ return rFont.aFamily.hashCode() ^ rFont.eItalic ^ rFont.eWeight ^ rFont.ePitch ^ rFont.aEncoding;
+ }
+ };
+}
+
+void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs, const PPDParser* pParser, bool bUseOverrideMetrics )
+{
+ rFontIDs.clear();
+ boost::unordered_map< fontID, PrintFont* >::const_iterator it;
+
+ /*
+ * Note: there are two easy steps making this faster:
+ * first: insert the printer builtins first, then the not builtins,
+ * if they do not match.
+ * drawback: this would change the sequence of fonts; this could have
+ * subtle, unknown consequences in vcl font matching
+ * second: instead of comparing attributes to see whether a softfont
+ * is duplicate to a builtin one could simply compare the PSName (which is
+ * supposed to be unique), which at this point is just an int.
+ * drawback: this could change which fonts are listed; especially TrueType
+ * fonts often have a rather dubious PSName, so this could change the
+ * font list not so subtle.
+ * Until getFontList for a printer becomes a performance issue (which is
+ * currently not the case), best stay with the current algorithm.
+ */
+
+ // fill sets of printer supported fonts
+ if( pParser )
+ {
+ std::set<int> aBuiltinPSNames;
+ boost::unordered_set< BuiltinFontIdentifier,
+ BuiltinFontIdentifierHash
+ > aBuiltinFonts;
+
+ std::map<int, fontID > aOverridePSNames;
+ if( bUseOverrideMetrics )
+ {
+ readOverrideMetrics();
+ for( std::vector<fontID>::const_iterator over = m_aOverrideFonts.begin();
+ over != m_aOverrideFonts.end(); ++over )
+ {
+ boost::unordered_map<fontID,PrintFont*>::const_iterator font_it = m_aFonts.find( *over );
+ DBG_ASSERT( font_it != m_aFonts.end(), "override to nonexistant font" );
+ if( font_it != m_aFonts.end() )
+ aOverridePSNames[ font_it->second->m_nPSName ] = *over;
+ }
+ }
+
+ int nFonts = pParser->getFonts();
+ for( int i = 0; i < nFonts; i++ )
+ aBuiltinPSNames.insert( m_pAtoms->getAtom( ATOM_PSNAME, pParser->getFont( i ) ) );
+ for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ {
+ PrintFont* pFont = it->second;
+ if( it->second->m_eType == fonttype::Builtin &&
+ aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
+ {
+ bool bInsert = true;
+ if( bUseOverrideMetrics )
+ {
+ // in override case only use the override fonts, not their counterparts
+ std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
+ if( over != aOverridePSNames.end() && over->second != it->first )
+ bInsert = false;
+ }
+ else
+ {
+ // do not insert override fonts in non override case
+ if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
+ bInsert = false;
+ }
+ if( bInsert )
+ {
+ aBuiltinFonts.insert( BuiltinFontIdentifier(
+ m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
+ pFont->m_eItalic,
+ pFont->m_eWeight,
+ pFont->m_ePitch,
+ pFont->m_aEncoding
+ ) );
+ }
+ }
+ }
+ for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ {
+ PrintFont* pFont = it->second;
+ if( it->second->m_eType == fonttype::Builtin )
+ {
+ if( aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
+ {
+ bool bInsert = true;
+ if( bUseOverrideMetrics )
+ {
+ // in override case only use the override fonts, not their counterparts
+ std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
+ if( over != aOverridePSNames.end() && over->second != it->first )
+ bInsert = false;
+ }
+ else
+ {
+ // do not insert override fonts in non override case
+ if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
+ bInsert = false;
+ }
+ if( bInsert )
+ rFontIDs.push_back( it->first );
+ }
+ }
+ else if( aBuiltinFonts.find( BuiltinFontIdentifier(
+ m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
+ pFont->m_eItalic,
+ pFont->m_eWeight,
+ pFont->m_ePitch,
+ pFont->m_aEncoding
+ ) ) == aBuiltinFonts.end() )
+ {
+ rFontIDs.push_back( it->first );
+ }
+ }
+ }
+ else // no specific printer
+ {
+ for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ rFontIDs.push_back( it->first );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const
+{
+ ::boost::unordered_map< int, family::type >::const_iterator style_it =
+ m_aFamilyTypes.find( pFont->m_nFamilyName );
+ rInfo.m_eType = pFont->m_eType;
+ rInfo.m_aFamilyName = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName );
+ rInfo.m_aStyleName = pFont->m_aStyleName;
+ rInfo.m_eFamilyStyle = style_it != m_aFamilyTypes.end() ? style_it->second : family::Unknown;
+ rInfo.m_eItalic = pFont->m_eItalic;
+ rInfo.m_eWidth = pFont->m_eWidth;
+ rInfo.m_eWeight = pFont->m_eWeight;
+ rInfo.m_ePitch = pFont->m_ePitch;
+ rInfo.m_aEncoding = pFont->m_aEncoding;
+
+ rInfo.m_bEmbeddable = (pFont->m_eType == fonttype::Type1);
+ rInfo.m_bSubsettable = (pFont->m_eType == fonttype::TrueType); // TODO: rename to SfntType
+
+ rInfo.m_aAliases.clear();
+ for( ::std::list< int >::iterator it = pFont->m_aAliases.begin(); it != pFont->m_aAliases.end(); ++it )
+ rInfo.m_aAliases.push_back( m_pAtoms->getString( ATOM_FAMILYNAME, *it ) );
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const
+{
+ if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) ||
+ ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
+ )
+ {
+ // might be a truetype font not analyzed or type1 without metrics read
+ if( pFont->m_eType == fonttype::Type1 )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) );
+
+ rInfo.m_nAscend = pFont->m_nAscend;
+ rInfo.m_nDescend = pFont->m_nDescend;
+ rInfo.m_nLeading = pFont->m_nLeading;
+ rInfo.m_nWidth = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::getFontListWithInfo( ::std::list< PrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
+{
+ rFonts.clear();
+ ::std::list< fontID > aFontList;
+ getFontList( aFontList, pParser, bUseOverrideMetrics );
+
+ ::std::list< fontID >::iterator it;
+ for( it = aFontList.begin(); it != aFontList.end(); ++it )
+ {
+ PrintFontInfo aInfo;
+ aInfo.m_nID = *it;
+ fillPrintFontInfo( getFont( *it ), aInfo );
+ rFonts.push_back( aInfo );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::getFontListWithFastInfo( ::std::list< FastPrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
+{
+ rFonts.clear();
+ ::std::list< fontID > aFontList;
+ getFontList( aFontList, pParser, bUseOverrideMetrics );
+
+ ::std::list< fontID >::iterator it;
+ for( it = aFontList.begin(); it != aFontList.end(); ++it )
+ {
+ FastPrintFontInfo aInfo;
+ aInfo.m_nID = *it;
+ fillPrintFontInfo( getFont( *it ), aInfo );
+ rFonts.push_back( aInfo );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont )
+ {
+ rInfo.m_nID = nFontID;
+ fillPrintFontInfo( pFont, rInfo );
+ }
+ return pFont ? true : false;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont )
+ {
+ rInfo.m_nID = nFontID;
+ fillPrintFontInfo( pFont, rInfo );
+ }
+ return pFont ? true : false;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFontBoundingBox( fontID nFontID, int& xMin, int& yMin, int& xMax, int& yMax )
+{
+ bool bSuccess = false;
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont )
+ {
+ if( pFont->m_nXMin == 0 && pFont->m_nYMin == 0 && pFont->m_nXMax == 0 && pFont->m_nYMax == 0 )
+ {
+ // might be a truetype font not analyzed or type1 without metrics read
+ if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+ bSuccess = true;
+ xMin = pFont->m_nXMin;
+ yMin = pFont->m_nYMin;
+ xMax = pFont->m_nXMax;
+ yMax = pFont->m_nYMax;
+ }
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
+{
+ int nRet = -1;
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont && pFont->m_eType == fonttype::TrueType )
+ nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry;
+ return nRet;
+}
+
+// -------------------------------------------------------------------------
+
+
+family::type PrintFontManager::matchFamilyName( const ::rtl::OUString& rFamily ) const
+{
+ typedef struct {
+ const char* mpName;
+ sal_uInt16 mnLength;
+ family::type meType;
+ } family_t;
+
+#define InitializeClass( p, a ) p, sizeof(p) - 1, a
+ const family_t pFamilyMatch[] = {
+ { InitializeClass( "arial", family::Swiss ) },
+ { InitializeClass( "arioso", family::Script ) },
+ { InitializeClass( "avant garde", family::Swiss ) },
+ { InitializeClass( "avantgarde", family::Swiss ) },
+ { InitializeClass( "bembo", family::Roman ) },
+ { InitializeClass( "bookman", family::Roman ) },
+ { InitializeClass( "conga", family::Roman ) },
+ { InitializeClass( "courier", family::Modern ) },
+ { InitializeClass( "curl", family::Script ) },
+ { InitializeClass( "fixed", family::Modern ) },
+ { InitializeClass( "gill", family::Swiss ) },
+ { InitializeClass( "helmet", family::Modern ) },
+ { InitializeClass( "helvetica", family::Swiss ) },
+ { InitializeClass( "international", family::Modern ) },
+ { InitializeClass( "lucida", family::Swiss ) },
+ { InitializeClass( "new century schoolbook", family::Roman ) },
+ { InitializeClass( "palatino", family::Roman ) },
+ { InitializeClass( "roman", family::Roman ) },
+ { InitializeClass( "sans serif", family::Swiss ) },
+ { InitializeClass( "sansserif", family::Swiss ) },
+ { InitializeClass( "serf", family::Roman ) },
+ { InitializeClass( "serif", family::Roman ) },
+ { InitializeClass( "times", family::Roman ) },
+ { InitializeClass( "utopia", family::Roman ) },
+ { InitializeClass( "zapf chancery", family::Script ) },
+ { InitializeClass( "zapfchancery", family::Script ) }
+ };
+
+ rtl::OString aFamily = rtl::OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
+ sal_uInt32 nLower = 0;
+ sal_uInt32 nUpper = SAL_N_ELEMENTS(pFamilyMatch);
+
+ while( nLower < nUpper )
+ {
+ sal_uInt32 nCurrent = (nLower + nUpper) / 2;
+ const family_t* pHaystack = pFamilyMatch + nCurrent;
+ sal_Int32 nComparison =
+ rtl_str_compareIgnoreAsciiCase_WithLength
+ (
+ aFamily.getStr(), aFamily.getLength(),
+ pHaystack->mpName, pHaystack->mnLength
+ );
+
+ if( nComparison < 0 )
+ nUpper = nCurrent;
+ else
+ if( nComparison > 0 )
+ nLower = nCurrent + 1;
+ else
+ return pHaystack->meType;
+ }
+
+ return family::Unknown;
+}
+
+// -------------------------------------------------------------------------
+
+family::type PrintFontManager::getFontFamilyType( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( !pFont )
+ return family::Unknown;
+
+ ::boost::unordered_map< int, family::type >::const_iterator it =
+ m_aFamilyTypes.find( pFont->m_nFamilyName );
+ return (it != m_aFamilyTypes.end()) ? it->second : family::Unknown;
+}
+
+
+// -------------------------------------------------------------------------
+
+const ::rtl::OUString& PrintFontManager::getFontFamily( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ return m_pAtoms->getString( ATOM_FAMILYNAME, pFont ? pFont->m_nFamilyName : INVALID_ATOM );
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::getAfmFile( PrintFont* pFont ) const
+{
+ OString aMetricPath;
+ if( pFont )
+ {
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1:
+ {
+ Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
+ aMetricPath = getDirectory( pPSFont->m_nDirectory );
+ aMetricPath += "/";
+ aMetricPath += pPSFont->m_aMetricFile;
+ }
+ break;
+ case fonttype::Builtin:
+ {
+ BuiltinFont* pBuiltinFont = static_cast< BuiltinFont* >(pFont);
+ aMetricPath = getDirectory( pBuiltinFont->m_nDirectory );
+ aMetricPath += "/";
+ aMetricPath += pBuiltinFont->m_aMetricFile;
+ }
+ break;
+ default: break;
+ }
+ }
+ return aMetricPath;
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::getFontFile( PrintFont* pFont ) const
+{
+ OString aPath;
+
+ if( pFont && pFont->m_eType == fonttype::Type1 )
+ {
+ Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
+ ::boost::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory );
+ aPath = it->second;
+ aPath += "/";
+ aPath += pPSFont->m_aFontFile;
+ }
+ else if( pFont && pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont);
+ ::boost::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory );
+ aPath = it->second;
+ aPath += "/";
+ aPath += pTTFont->m_aFontFile;
+ }
+ return aPath;
+}
+
+// -------------------------------------------------------------------------
+
+const ::rtl::OUString& PrintFontManager::getPSName( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont && pFont->m_nPSName == 0 )
+ {
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM );
+}
+
+// -------------------------------------------------------------------------
+
+const CharacterMetric& PrintFontManager::getGlobalFontMetric( fontID nFontID, bool bHorizontal ) const
+{
+ static CharacterMetric aMetric;
+ PrintFont* pFont = getFont( nFontID );
+ return pFont ? ( bHorizontal ? pFont->m_aGlobalMetricX : pFont->m_aGlobalMetricY ) : aMetric;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontAscend( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
+ }
+ return pFont->m_nAscend;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontDescend( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
+ }
+ return pFont->m_nDescend;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontLeading( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+ return pFont->m_nLeading;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::hasVerticalSubstitutions( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+ return pFont->m_bHaveVerticalSubstitutedGlyphs;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::hasVerticalSubstitutions( fontID nFontID,
+ const sal_Unicode* pCharacters, int nCharacters, bool* pHasSubst ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ if( ! pFont->m_bHaveVerticalSubstitutedGlyphs )
+ memset( pHasSubst, 0, sizeof(bool)*nCharacters );
+ else
+ {
+ for( int i = 0; i < nCharacters; i++ )
+ {
+ sal_Unicode code = pCharacters[i];
+ if( ! pFont->m_pMetrics ||
+ ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
+ pFont->queryMetricPage( code >> 8, m_pAtoms );
+ ::boost::unordered_map< sal_Unicode, bool >::const_iterator it = pFont->m_pMetrics->m_bVerticalSubstitutions.find( code );
+ pHasSubst[i] = it != pFont->m_pMetrics->m_bVerticalSubstitutions.end();
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+OUString PrintFontManager::getFontXLFD( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ OUString aRet;
+ if( pFont )
+ {
+ ByteString aXLFD( getXLFD( pFont ) );
+ rtl_TextEncoding aEncoding = aXLFD.GetToken( 6, '-' ).Search( "utf8" ) != STRING_NOTFOUND ? RTL_TEXTENCODING_UTF8 : RTL_TEXTENCODING_ISO_8859_1;
+ aRet = OStringToOUString( aXLFD, aEncoding );
+ }
+ return aRet;
+}
+
+// -------------------------------------------------------------------------
+
+const ::std::list< KernPair >& PrintFontManager::getKernPairs( fontID nFontID, bool bVertical ) const
+{
+ static ::std::list< KernPair > aEmpty;
+
+ PrintFont* pFont = getFont( nFontID );
+ if( ! pFont )
+ return aEmpty;
+
+ if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
+ pFont->queryMetricPage( 0, m_pAtoms );
+ if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
+ return aEmpty;
+ return bVertical ? pFont->m_pMetrics->m_aYKernPairs : pFont->m_pMetrics->m_aXKernPairs;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::isFontDownloadingAllowed( fontID nFont ) const
+{
+ static const char* pEnable = getenv( "PSPRINT_ENABLE_TTF_COPYRIGHTAWARENESS" );
+ bool bRet = true;
+
+ if( pEnable && *pEnable )
+ {
+ PrintFont* pFont = getFont( nFont );
+ if( pFont && pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFontFile* pTTFontFile = static_cast<TrueTypeFontFile*>(pFont);
+ if( pTTFontFile->m_nTypeFlags & TYPEFLAG_INVALID )
+ {
+ TrueTypeFont* pTTFont = NULL;
+ ByteString aFile = getFontFile( pFont );
+ if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ // get type flags
+ TTGlobalFontInfo aInfo;
+ GetTTGlobalFontInfo( pTTFont, & aInfo );
+ pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
+ CloseTTFont( pTTFont );
+ }
+ }
+
+ unsigned int nCopyrightFlags = pTTFontFile->m_nTypeFlags & TYPEFLAG_COPYRIGHT_MASK;
+
+ // font embedding is allowed if either
+ // no restriction at all (bit 1 clear)
+ // printing allowed (bit 1 set, bit 2 set )
+ bRet = ! ( nCopyrightFlags & 0x02 ) || ( nCopyrightFlags & 0x04 );
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( ! pFont )
+ return false;
+
+ if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
+ )
+ {
+ // might be a font not yet analyzed
+ if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ for( int i = 0; i < nLen; i++ )
+ {
+ if( ! pFont->m_pMetrics ||
+ ! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) )
+ pFont->queryMetricPage( pString[i] >> 8, m_pAtoms );
+ pArray[i].width = pArray[i].height = -1;
+ if( pFont->m_pMetrics )
+ {
+ int effectiveCode = pString[i];
+ effectiveCode |= bVertical ? 1 << 16 : 0;
+ ::boost::unordered_map< int, CharacterMetric >::const_iterator it =
+ pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
+ // if no vertical metrics are available assume rotated horizontal metrics
+ if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
+ it = pFont->m_pMetrics->m_aMetrics.find( pString[i] );
+ // the character metrics are in it->second
+ if( it != pFont->m_pMetrics->m_aMetrics.end() )
+ pArray[ i ] = it->second;
+ }
+ }
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( ! pFont )
+ return false;
+
+ if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
+ )
+ {
+ // might be a font not yet analyzed
+ if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ sal_Unicode code = minCharacter;
+ do
+ {
+ if( ! pFont->m_pMetrics ||
+ ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
+ pFont->queryMetricPage( code >> 8, m_pAtoms );
+ pArray[ code - minCharacter ].width = -1;
+ pArray[ code - minCharacter ].height = -1;
+ if( pFont->m_pMetrics )
+ {
+ int effectiveCode = code;
+ effectiveCode |= bVertical ? 1 << 16 : 0;
+ ::boost::unordered_map< int, CharacterMetric >::const_iterator it =
+ pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
+ // if no vertical metrics are available assume rotated horizontal metrics
+ if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
+ it = pFont->m_pMetrics->m_aMetrics.find( code );
+ // the character metrics are in it->second
+ if( it != pFont->m_pMetrics->m_aMetrics.end() )
+ pArray[ code - minCharacter ] = it->second;
+ }
+ } while( code++ != maxCharacter );
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+static bool createWriteablePath( const ByteString& rPath )
+{
+ bool bSuccess = false;
+
+ if( access( rPath.GetBuffer(), W_OK ) )
+ {
+ int nPos = rPath.SearchBackward( '/' );
+ if( nPos != STRING_NOTFOUND )
+ while( nPos > 0 && rPath.GetChar( nPos ) == '/' )
+ nPos--;
+
+ if( nPos != STRING_NOTFOUND && nPos != 0 && createWriteablePath( rPath.Copy( 0, nPos+1 ) ) )
+ {
+ bSuccess = mkdir( rPath.GetBuffer(), 0777 ) ? false : true;
+ }
+ }
+ else
+ bSuccess = true;
+
+ return bSuccess;
+}
+
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::importFonts( const ::std::list< OString >& rFiles, bool bLinkOnly, ImportFontCallback* pCallback )
+{
+ int nSuccess = 0;
+
+ // find a directory with write access
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ bool bCanWrite = false;
+ int nDirID = 0;
+ INetURLObject aDir;
+ for( ::std::list< int >::const_iterator dir_it = m_aPrivateFontDirectories.begin();
+ ! bCanWrite && dir_it != m_aPrivateFontDirectories.end(); ++dir_it )
+ {
+ // check if we can create files in that directory
+ ByteString aDirPath = getDirectory( *dir_it );
+ if( createWriteablePath( aDirPath ) )
+ {
+ aDir = INetURLObject( OStringToOUString( aDirPath, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ nDirID = *dir_it;
+ bCanWrite = true;
+ }
+ }
+ if( bCanWrite )
+ {
+ for( ::std::list< OString >::const_iterator font_it = rFiles.begin();
+ font_it != rFiles.end(); ++font_it )
+ {
+ INetURLObject aFrom( OStringToOUString( *font_it, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ INetURLObject aTo( aDir );
+ aTo.Append( aFrom.GetName() );
+
+ if( pCallback )
+ pCallback->progress( aTo.PathToFileName() );
+
+ if( pCallback && pCallback->isCanceled() )
+ break;
+
+ if( ! access( ByteString( String(aTo.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ if( ! ( pCallback ? pCallback->queryOverwriteFile( aTo.PathToFileName() ) : false ) )
+ continue;
+ }
+ // look for afm if necessary
+ OUString aAfmCopied;
+ FileBase::RC nError;
+ if( aFrom.getExtension().equalsIgnoreAsciiCaseAscii( "pfa" ) ||
+ aFrom.getExtension().equalsIgnoreAsciiCaseAscii( "pfb" ) )
+ {
+ INetURLObject aFromAfm( aFrom );
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ aFromAfm.removeSegment();
+ aFromAfm.Append( String( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ aFromAfm.Append( aTo.GetName() );
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ // give up
+ if( pCallback )
+ pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::NoAfmMetric );
+ continue;
+ }
+ }
+ }
+ }
+ INetURLObject aToAfm( aTo );
+ aToAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ OUString aFromPath, aToPath;
+ if( bLinkOnly )
+ {
+ ByteString aLinkFromPath( String(aFromAfm.PathToFileName()),
+ aEncoding );
+ ByteString aLinkToPath( String(aToAfm.PathToFileName()),
+ aEncoding );
+ nError = (FileBase::RC)symlink( aLinkFromPath.GetBuffer(), aLinkToPath.GetBuffer() );
+ }
+ else
+ nError = File::copy( aFromAfm.GetMainURL(INetURLObject::DECODE_TO_IURI), aToAfm.GetMainURL(INetURLObject::DECODE_TO_IURI) );
+ if( nError )
+ {
+ if( pCallback )
+ pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::AfmCopyFailed );
+ continue;
+ }
+ aAfmCopied = aToPath;
+ }
+ if( bLinkOnly )
+ {
+ ByteString aFromPath( String(aFrom.PathToFileName()),
+ aEncoding );
+ ByteString aToPath( String(aTo.PathToFileName()), aEncoding );
+ nError = (FileBase::RC)symlink( aFromPath.GetBuffer(),
+ aToPath.GetBuffer() );
+ }
+ else
+ nError = File::copy( aFrom.GetMainURL(INetURLObject::DECODE_TO_IURI), aTo.GetMainURL(INetURLObject::DECODE_TO_IURI) );
+ // copy font file
+ if( nError )
+ {
+ if( aAfmCopied.getLength() )
+ File::remove( aAfmCopied );
+ if( pCallback )
+ pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::FontCopyFailed );
+ continue;
+ }
+
+ ::std::list< PrintFont* > aNewFonts;
+ ::std::list< PrintFont* >::iterator it;
+ if( analyzeFontFile( nDirID, OUStringToOString( aTo.GetName(), aEncoding ), ::std::list<OString>(), aNewFonts ) )
+ {
+ // remove all fonts for the same file
+ // discarding their font ids
+ ::boost::unordered_map< fontID, PrintFont* >::iterator current, next;
+ current = m_aFonts.begin();
+ OString aFileName( OUStringToOString( aTo.GetName(), aEncoding ) );
+ while( current != m_aFonts.end() )
+ {
+ bool bRemove = false;
+ switch( current->second->m_eType )
+ {
+ case fonttype::Type1:
+ if( static_cast<Type1FontFile*>(current->second)->m_aFontFile == aFileName )
+ bRemove = true;
+ break;
+ case fonttype::TrueType:
+ if( static_cast<TrueTypeFontFile*>(current->second)->m_aFontFile == aFileName )
+ bRemove = true;
+ break;
+ default: break;
+ }
+ if( bRemove )
+ {
+ next = current;
+ ++next;
+ m_aFontFileToFontID[ aFileName ].erase( current->first );
+ delete current->second;
+ m_aFonts.erase( current );
+ current = next;
+ }
+ else
+ ++current;
+ }
+
+ DBG_ASSERT( !findFontFileID( nDirID, aFileName ), "not all fonts removed for file" );
+
+ nSuccess++;
+ for( it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
+ {
+ m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
+ m_aFonts[ m_nNextFontID++ ] = *it;
+ m_pFontCache->updateFontCacheEntry( *it, false );
+ }
+ }
+ }
+
+ m_pFontCache->updateDirTimestamp( nDirID );
+ m_pFontCache->flush();
+ }
+ else if( pCallback )
+ pCallback->importFontsFailed( ImportFontCallback::NoWritableDirectory );
+
+ return nSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::checkImportPossible() const
+{
+ bool bSuccess = false;
+
+ // find a directory with write access
+ ByteString aDir;
+ for( std::list< int >::const_iterator dir_it = m_aPrivateFontDirectories.begin();
+ dir_it != m_aPrivateFontDirectories.end(); ++dir_it )
+ {
+ aDir = getDirectory( *dir_it );
+ if( createWriteablePath( aDir ) )
+ {
+ bSuccess = true;
+ break;
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ if( bSuccess )
+ fprintf( stderr, "found writable %s\n", aDir.GetBuffer() );
+#endif
+
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::checkChangeFontPropertiesPossible( fontID /*nFontID*/ ) const
+{
+ // since font properties are changed in the font cache file only nowadays
+ // they can always be changed
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::changeFontProperties( fontID nFontID, const ::rtl::OUString& rXLFD )
+{
+ ByteString aXLFD( OUStringToOString( rXLFD, RTL_TEXTENCODING_UTF8 ) );
+ ByteString aAddStyle = aXLFD.GetToken( '-', 6 );
+ if( aAddStyle.Search( "utf8" ) == STRING_NOTFOUND )
+ {
+ aAddStyle.Append( aAddStyle.Len() ? ";utf8" : "utf8" );
+ aXLFD.SetToken( 6, ';', aAddStyle );
+ }
+ PrintFont* pFont = getFont( nFontID );
+ std::list< OString > aDummyList;
+ aDummyList.push_back( aXLFD );
+ getFontAttributesFromXLFD( pFont, aDummyList );
+ pFont->m_bUserOverride = true;
+ m_pFontCache->updateFontCacheEntry( pFont, true );
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::
+getImportableFontProperties(
+ const OString& rFile,
+ ::std::list< FastPrintFontInfo >& rFontProps
+ )
+{
+ rFontProps.clear();
+ int nIndex = rFile.lastIndexOf( '/' );
+ OString aDir, aFile( rFile.copy( nIndex+1 ) );
+ if( nIndex != -1 )
+ aDir = rFile.copy( 0, nIndex );
+ int nDirID = getDirectoryAtom( aDir, true );
+ ::std::list< PrintFont* > aFonts;
+ bool bRet = analyzeFontFile( nDirID, aFile, ::std::list<OString>(), aFonts );
+ while( aFonts.begin() != aFonts.end() )
+ {
+ PrintFont* pFont = aFonts.front();
+ aFonts.pop_front();
+ FastPrintFontInfo aInfo;
+ fillPrintFontInfo( pFont, aInfo );
+ rFontProps.push_back( aInfo );
+ delete pFont;
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFileDuplicates( fontID nFont, ::std::list< fontID >& rFonts ) const
+{
+ bool bRet = false;
+
+ rFonts.clear();
+
+ PrintFont* pSearchFont = getFont( nFont );
+ if( ! pSearchFont ||
+ pSearchFont->m_eType != fonttype::TrueType ||
+ static_cast<TrueTypeFontFile*>(pSearchFont)->m_nCollectionEntry == -1
+ )
+ return false;
+
+ OString aFile( getFontFileSysPath( nFont ) );
+ if( ! aFile.getLength() )
+ return false;
+
+ for( ::boost::unordered_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ {
+ if( nFont != it->first )
+ {
+ OString aCompFile( getFontFile( it->second ) );
+ if( aCompFile == aFile )
+ {
+ rFonts.push_back( it->first );
+ bRet = true;
+ }
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::removeFonts( const ::std::list< fontID >& rFonts )
+{
+ bool bRet = true;
+ ::std::list< fontID > aDuplicates;
+ for( ::std::list< fontID >::const_iterator it = rFonts.begin(); it != rFonts.end(); ++it )
+ {
+ ::boost::unordered_map< fontID, PrintFont* >::const_iterator haveFont = m_aFonts.find( *it );
+ if( haveFont == m_aFonts.end() )
+ continue;
+
+ PrintFont* pFont = haveFont->second;
+ bool bRemoveDuplicates = getFileDuplicates( *it, aDuplicates );
+ ByteString aFile( getFontFile( pFont ) );
+ if( aFile.Len() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try unlink( \"%s\" ) ... ", aFile.GetBuffer() );
+#endif
+ if( unlink( aFile.GetBuffer() ) )
+ {
+ bRet = false;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "failed\n" );
+#endif
+ continue;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "succeeded\n" );
+#endif
+ OString aAfm( getAfmFile( pFont ) );
+ if( aAfm.getLength() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "unlink( \"%s\" )\n", aAfm.getStr() );
+#endif
+ unlink( aAfm.getStr() );
+ }
+ m_aFonts.erase( *it );
+ delete pFont;
+ if( bRemoveDuplicates )
+ {
+ for( ::std::list< fontID >::iterator dup = aDuplicates.begin(); dup != aDuplicates.end(); ++dup )
+ {
+ m_aFontFileToFontID[ aFile ].erase( *dup );
+ PrintFont* pDup = m_aFonts[ *dup ];
+ m_aFonts.erase( *dup );
+ delete pDup;
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::isPrivateFontFile( fontID nFont ) const
+{
+ bool bRet = false;
+ int nDirID = -1;
+ PrintFont* pFont = getFont( nFont );
+ if( pFont )
+ {
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1: nDirID = static_cast< Type1FontFile* >(pFont)->m_nDirectory;break;
+ case fonttype::TrueType: nDirID = static_cast< TrueTypeFontFile* >(pFont)->m_nDirectory;break;
+ default: break;
+ }
+ }
+ if( nDirID != -1 )
+ {
+ for( ::std::list< int >::const_iterator it = m_aPrivateFontDirectories.begin(); it != m_aPrivateFontDirectories.end(); ++it )
+ {
+ if( nDirID == *it )
+ {
+ bRet = true;
+ break;
+ }
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getAlternativeFamilyNames( fontID nFont, ::std::list< OUString >& rNames ) const
+{
+ rNames.clear();
+
+ PrintFont* pFont = getFont( nFont );
+ if( pFont && pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ ByteString aFile( getFontFile( pFont ) );
+ TrueTypeFont* pTTFont;
+ if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ NameRecord* pNameRecords = NULL;
+ int nNameRecords = GetTTNameRecords( pTTFont, &pNameRecords );
+ for( int i = 0; i < nNameRecords; i++ )
+ {
+ if( pNameRecords[i].nameID != 1 ) // family name
+ continue;
+
+ OUString aFamily( convertTrueTypeName( pNameRecords+i ) );
+ if( aFamily.getLength()
+ &&
+ m_pAtoms->getAtom( ATOM_FAMILYNAME, aFamily, sal_True ) != pFont->m_nFamilyName
+ )
+ {
+ rNames.push_back( aFamily );
+ }
+ }
+
+ if( nNameRecords )
+ DisposeNameRecords( pNameRecords, nNameRecords );
+ CloseTTFont( pTTFont );
+ }
+ }
+ return rNames.begin() != rNames.end();
+}
+
+// -------------------------------------------------------------------------
+
+// TODO: move most of this stuff into the central font-subsetting code
+bool PrintFontManager::createFontSubset(
+ FontSubsetInfo& rInfo,
+ fontID nFont,
+ const OUString& rOutFile,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pNewEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ bool bVertical
+ )
+{
+ PrintFont* pFont = getFont( nFont );
+ if( !pFont )
+ return false;
+
+ switch( pFont->m_eType )
+ {
+ case psp::fonttype::TrueType: rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; break;
+ case psp::fonttype::Type1: rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1; break;
+ default:
+ return false;
+ }
+ // TODO: remove when Type1 subsetting gets implemented
+ if( pFont->m_eType != fonttype::TrueType )
+ return false;
+
+ // reshuffle array of requested glyphs to make sure glyph0==notdef
+ sal_uInt8 pEnc[256];
+ sal_uInt16 pGID[256];
+ sal_uInt8 pOldIndex[256];
+ memset( pEnc, 0, sizeof( pEnc ) );
+ memset( pGID, 0, sizeof( pGID ) );
+ memset( pOldIndex, 0, sizeof( pOldIndex ) );
+ if( nGlyphs > 256 )
+ return false;
+ int nChar = 1;
+ for( int i = 0; i < nGlyphs; i++ )
+ {
+ if( pNewEncoding[i] == 0 )
+ {
+ pOldIndex[ 0 ] = i;
+ }
+ else
+ {
+ DBG_ASSERT( !(pGlyphIDs[i] & 0x007f0000), "overlong glyph id" );
+ DBG_ASSERT( (int)pNewEncoding[i] < nGlyphs, "encoding wrong" );
+ DBG_ASSERT( pEnc[pNewEncoding[i]] == 0 && pGID[pNewEncoding[i]] == 0, "duplicate encoded glyph" );
+ pEnc[ pNewEncoding[i] ] = pNewEncoding[i];
+ pGID[ pNewEncoding[i] ] = (sal_uInt16)pGlyphIDs[ i ];
+ pOldIndex[ pNewEncoding[i] ] = i;
+ nChar++;
+ }
+ }
+ nGlyphs = nChar; // either input value or increased by one
+
+ // prepare system name for read access for subset source file
+ // TODO: since this file is usually already mmapped there is no need to open it again
+ const ByteString aFromFile = getFontFile( pFont );
+
+ TrueTypeFont* pTTFont = NULL; // TODO: rename to SfntFont
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ if( OpenTTFontFile( aFromFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
+ return false;
+
+ // prepare system name for write access for subset file target
+ OUString aSysPath;
+ if( osl_File_E_None != osl_getSystemPathFromFileURL( rOutFile.pData, &aSysPath.pData ) )
+ return false;
+ const rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ const ByteString aToFile( OUStringToOString( aSysPath, aEncoding ) );
+
+ // do CFF subsetting if possible
+ int nCffLength = 0;
+ const sal_uInt8* pCffBytes = NULL;
+ if( GetSfntTable( pTTFont, O_CFF, &pCffBytes, &nCffLength ) )
+ {
+ rInfo.LoadFont( FontSubsetInfo::CFF_FONT, pCffBytes, nCffLength );
+#if 1 // TODO: remove 16bit->long conversion when related methods handle non-16bit glyphids
+ long aRequestedGlyphs[256];
+ for( int i = 0; i < nGlyphs; ++i )
+ aRequestedGlyphs[i] = pGID[i];
+#endif
+ // create subset file at requested path
+ FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
+ // create font subset
+ const char* pGlyphSetName = NULL; // TODO: better name?
+ const bool bOK = rInfo.CreateFontSubset(
+ FontSubsetInfo::TYPE1_PFB,
+ pOutFile, pGlyphSetName,
+ aRequestedGlyphs, pEnc, nGlyphs, pWidths );
+ fclose( pOutFile );
+ // cleanup before early return
+ CloseTTFont( pTTFont );
+ return bOK;
+ }
+
+ // do TTF->Type42 or Type3 subsetting
+ // fill in font info
+ psp::PrintFontInfo aFontInfo;
+ if( ! getFontInfo( nFont, aFontInfo ) )
+ return false;
+
+ rInfo.m_nAscent = aFontInfo.m_nAscend;
+ rInfo.m_nDescent = aFontInfo.m_nDescend;
+ rInfo.m_aPSName = getPSName( nFont );
+
+ int xMin, yMin, xMax, yMax;
+ getFontBoundingBox( nFont, xMin, yMin, xMax, yMax );
+ rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
+ rInfo.m_nCapHeight = yMax; // Well ...
+
+ // fill in glyph advance widths
+ TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
+ pGID,
+ nGlyphs,
+ bVertical ? 1 : 0 );
+ if( pMetrics )
+ {
+ for( int i = 0; i < nGlyphs; i++ )
+ pWidths[pOldIndex[i]] = pMetrics[i].adv;
+ free( pMetrics );
+ }
+ else
+ {
+ CloseTTFont( pTTFont );
+ return false;
+ }
+
+ bool bSuccess = ( SF_OK == CreateTTFromTTGlyphs( pTTFont,
+ aToFile.GetBuffer(),
+ pGID,
+ pEnc,
+ nGlyphs,
+ 0,
+ NULL,
+ 0 ) );
+ CloseTTFont( pTTFont );
+
+ return bSuccess;
+}
+
+void PrintFontManager::getGlyphWidths( fontID nFont,
+ bool bVertical,
+ std::vector< sal_Int32 >& rWidths,
+ std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc )
+{
+ PrintFont* pFont = getFont( nFont );
+ if( !pFont ||
+ (pFont->m_eType != fonttype::TrueType && pFont->m_eType != fonttype::Type1) )
+ return;
+ if( pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFont* pTTFont = NULL;
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ ByteString aFromFile = getFontFile( pFont );
+ if( OpenTTFontFile( aFromFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
+ return;
+ int nGlyphs = GetTTGlyphCount( pTTFont );
+ if( nGlyphs > 0 )
+ {
+ rWidths.resize(nGlyphs);
+ std::vector<sal_uInt16> aGlyphIds(nGlyphs);
+ for( int i = 0; i < nGlyphs; i++ )
+ aGlyphIds[i] = sal_uInt16(i);
+ TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
+ &aGlyphIds[0],
+ nGlyphs,
+ bVertical ? 1 : 0 );
+ if( pMetrics )
+ {
+ for( int i = 0; i< nGlyphs; i++ )
+ rWidths[i] = pMetrics[i].adv;
+ free( pMetrics );
+ rUnicodeEnc.clear();
+ }
+
+ // fill the unicode map
+ // TODO: isn't this map already available elsewhere in the fontmanager?
+ const sal_uInt8* pCmapData = NULL;
+ int nCmapSize = 0;
+ if( GetSfntTable( pTTFont, O_cmap, &pCmapData, &nCmapSize ) )
+ {
+ CmapResult aCmapResult;
+ if( ParseCMAP( pCmapData, nCmapSize, aCmapResult ) )
+ {
+ const ImplFontCharMap aCharMap( aCmapResult );
+ for( sal_uInt32 cOld = 0;;)
+ {
+ // get next unicode covered by font
+ const sal_uInt32 c = aCharMap.GetNextChar( cOld );
+ if( c == cOld )
+ break;
+ cOld = c;
+#if 1 // TODO: remove when sal_Unicode covers all of unicode
+ if( c > (sal_Unicode)~0 )
+ break;
+#endif
+ // get the matching glyph index
+ const sal_uInt32 nGlyphId = aCharMap.GetGlyphIndex( c );
+ // update the requested map
+ rUnicodeEnc[ (sal_Unicode)c ] = nGlyphId;
+ }
+ }
+ }
+ }
+ CloseTTFont( pTTFont );
+ }
+ else if( pFont->m_eType == fonttype::Type1 )
+ {
+ if( ! pFont->m_aEncodingVector.size() )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
+ if( pFont->m_pMetrics )
+ {
+ rUnicodeEnc.clear();
+ rWidths.clear();
+ rWidths.reserve( pFont->m_pMetrics->m_aMetrics.size() );
+ for( boost::unordered_map< int, CharacterMetric >::const_iterator it =
+ pFont->m_pMetrics->m_aMetrics.begin();
+ it != pFont->m_pMetrics->m_aMetrics.end(); ++it )
+ {
+ if( (it->first & 0x00010000) == 0 || bVertical )
+ {
+ rUnicodeEnc[ sal_Unicode(it->first & 0x0000ffff) ] = sal_uInt32(rWidths.size());
+ rWidths.push_back( it->second.width );
+ }
+ }
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, rtl::OString >** pNonEncoded ) const
+{
+ PrintFont* pFont = getFont( nFont );
+ if( !pFont ||
+ (pFont->m_eType != fonttype::Type1 && pFont->m_eType != fonttype::Builtin)
+ )
+ return NULL;
+
+ if( ! pFont->m_aEncodingVector.size() )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
+
+ if( pNonEncoded )
+ *pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL;
+
+ return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL;
+}
+
+// -------------------------------------------------------------------------
+
+std::list< OString > PrintFontManager::getAdobeNameFromUnicode( sal_Unicode aChar ) const
+{
+ std::pair< boost::unordered_multimap< sal_Unicode, rtl::OString >::const_iterator,
+ boost::unordered_multimap< sal_Unicode, rtl::OString >::const_iterator > range
+ = m_aUnicodeToAdobename.equal_range( aChar );
+
+ std::list< OString > aRet;
+ for( ; range.first != range.second; ++range.first )
+ aRet.push_back( range.first->second );
+
+ if( aRet.begin() == aRet.end() && aChar != 0 )
+ {
+ sal_Char aBuf[8];
+ sal_Int32 nChars = snprintf( (char*)aBuf, sizeof( aBuf ), "uni%.4hX", aChar );
+ aRet.push_back( OString( aBuf, nChars ) );
+ }
+
+ return aRet;
+}
+
+// -------------------------------------------------------------------------
+std::list< sal_Unicode > PrintFontManager::getUnicodeFromAdobeName( const rtl::OString& rName ) const
+{
+ std::pair< boost::unordered_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator,
+ boost::unordered_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator > range
+ = m_aAdobenameToUnicode.equal_range( rName );
+
+ std::list< sal_Unicode > aRet;
+ for( ; range.first != range.second; ++range.first )
+ aRet.push_back( range.first->second );
+
+ if( aRet.begin() == aRet.end() )
+ {
+ if( rName.getLength() == 7 && rName.indexOf( "uni" ) == 0 )
+ {
+ sal_Unicode aCode = (sal_Unicode)rName.copy( 3 ).toInt32( 16 );
+ aRet.push_back( aCode );
+ }
+ }
+
+ return aRet;
+}
+
+// -------------------------------------------------------------------------
+namespace
+{
+ OUString getString( const Any& rAny )
+ {
+ OUString aStr;
+ rAny >>= aStr;
+ return aStr;
+ }
+ bool getBool( const Any& rAny )
+ {
+ sal_Bool bBool = sal_False;
+ rAny >>= bBool;
+ return static_cast<bool>(bBool);
+ }
+ sal_Int32 getInt( const Any& rAny )
+ {
+ sal_Int32 n = 0;
+ rAny >>= n;
+ return n;
+ }
+}
+bool PrintFontManager::readOverrideMetrics()
+{
+ if( ! m_aOverrideFonts.empty() )
+ return false;
+
+ css::uno::Reference< XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory() );
+ if( !xFact.is() )
+ return false;
+ css::uno::Reference< XMaterialHolder > xMat(
+ xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.psprint.CompatMetricOverride" ) ) ),
+ UNO_QUERY );
+ if( !xMat.is() )
+ return false;
+
+ Any aAny( xMat->getMaterial() );
+ Sequence< Any > aOverrideFonts;
+ if( ! (aAny >>= aOverrideFonts ) )
+ return false;
+ sal_Int32 nFonts = aOverrideFonts.getLength();
+ for( sal_Int32 i = 0; i < nFonts; i++ )
+ {
+ Sequence< NamedValue > aMetrics;
+ if( ! (aOverrideFonts.getConstArray()[i] >>= aMetrics) )
+ continue;
+ BuiltinFont* pFont = new BuiltinFont();
+ pFont->m_nDirectory = 0;
+ pFont->m_bUserOverride = false;
+ pFont->m_pMetrics = new PrintFontMetrics;
+ memset( pFont->m_pMetrics->m_aPages, 0xff, sizeof( pFont->m_pMetrics->m_aPages ) );
+ pFont->m_pMetrics->m_bKernPairsQueried = true;
+ sal_Int32 nProps = aMetrics.getLength();
+ const NamedValue* pProps = aMetrics.getConstArray();
+ for( sal_Int32 n = 0; n < nProps; n++ )
+ {
+ if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "FamilyName" ) ) )
+ pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME,
+ getString(pProps[n].Value),
+ sal_True );
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "PSName" ) ) )
+ pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME,
+ getString(pProps[n].Value),
+ sal_True );
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "StyleName" ) ) )
+ pFont->m_aStyleName = getString(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Italic" ) ) )
+ pFont->m_eItalic = static_cast<italic::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Width" ) ) )
+ pFont->m_eWidth = static_cast<width::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Weight" ) ) )
+ pFont->m_eWeight = static_cast<weight::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Pitch" ) ) )
+ pFont->m_ePitch = static_cast<pitch::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Encoding" ) ) )
+ pFont->m_aEncoding = static_cast<rtl_TextEncoding>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "FontEncodingOnly" ) ) )
+ pFont->m_bFontEncodingOnly = getBool(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "GlobalMetricXWidth" ) ) )
+ pFont->m_aGlobalMetricX.width = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "GlobalMetricXHeight" ) ) )
+ pFont->m_aGlobalMetricX.height = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "GlobalMetricYWidth" ) ) )
+ pFont->m_aGlobalMetricY.width = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "GlobalMetricYHeight" ) ) )
+ pFont->m_aGlobalMetricY.height = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Ascend" ) ) )
+ pFont->m_nAscend = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Descend" ) ) )
+ pFont->m_nDescend = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Leading" ) ) )
+ pFont->m_nLeading = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "XMin" ) ) )
+ pFont->m_nXMin = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "YMin" ) ) )
+ pFont->m_nYMin = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "XMax" ) ) )
+ pFont->m_nXMax = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "YMax" ) ) )
+ pFont->m_nYMax = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "VerticalSubstitutes" ) ) )
+ pFont->m_bHaveVerticalSubstitutedGlyphs = getBool(pProps[n].Value);
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "EncodingVector" ) ) )
+ {
+ Sequence< NamedValue > aEncoding;
+ pProps[n].Value >>= aEncoding;
+ sal_Int32 nEnc = aEncoding.getLength();
+ const NamedValue* pEnc = aEncoding.getConstArray();
+ for( sal_Int32 m = 0; m < nEnc; m++ )
+ {
+ sal_Unicode cCode = *pEnc[m].Name.getStr();
+ sal_Int32 nGlyph = getInt(pEnc[m].Value);
+ pFont->m_aEncodingVector[ cCode ] = nGlyph;
+ }
+ }
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "NonEncoded" ) ) )
+ {
+ Sequence< NamedValue > aEncoding;
+ pProps[n].Value >>= aEncoding;
+ sal_Int32 nEnc = aEncoding.getLength();
+ const NamedValue* pEnc = aEncoding.getConstArray();
+ for( sal_Int32 m = 0; m < nEnc; m++ )
+ {
+ sal_Unicode cCode = *pEnc[m].Name.getStr();
+ OUString aGlyphName( getString(pEnc[m].Value) );
+ pFont->m_aNonEncoded[ cCode ] = OUStringToOString(aGlyphName,RTL_TEXTENCODING_ASCII_US);
+ }
+ }
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CharacterMetrics" ) ) )
+ {
+ // fill pFont->m_pMetrics->m_aMetrics
+ // expect triples of int: int -> CharacterMetric.{ width, height }
+ Sequence< sal_Int32 > aSeq;
+ pProps[n].Value >>= aSeq;
+ sal_Int32 nInts = aSeq.getLength();
+ const sal_Int32* pInts = aSeq.getConstArray();
+ for( sal_Int32 m = 0; m < nInts; m+=3 )
+ {
+ pFont->m_pMetrics->m_aMetrics[ pInts[m] ].width = static_cast<short int>(pInts[m+1]);
+ pFont->m_pMetrics->m_aMetrics[ pInts[m] ].height = static_cast<short int>(pInts[m+2]);
+ }
+ }
+ else if( pProps[n].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "XKernPairs" ) ) )
+ {
+ // fill pFont->m_pMetrics->m_aXKernPairs
+ // expection name: <unicode1><unicode2> value: ((height << 16)| width)
+ Sequence< NamedValue > aKern;
+ pProps[n].Value >>= aKern;
+ KernPair aPair;
+ const NamedValue* pVals = aKern.getConstArray();
+ int nPairs = aKern.getLength();
+ for( int m = 0; m < nPairs; m++ )
+ {
+ if( pVals[m].Name.getLength() == 2 )
+ {
+ aPair.first = pVals[m].Name.getStr()[0];
+ aPair.second = pVals[m].Name.getStr()[1];
+ sal_Int32 nKern = getInt( pVals[m].Value );
+ aPair.kern_x = static_cast<short int>(nKern & 0xffff);
+ aPair.kern_y = static_cast<short int>((sal_uInt32(nKern) >> 16) & 0xffff);
+ pFont->m_pMetrics->m_aXKernPairs.push_back( aPair );
+ }
+ }
+ }
+ }
+ // sanity check
+ if( pFont->m_nPSName &&
+ pFont->m_nFamilyName &&
+ ! pFont->m_pMetrics->m_aMetrics.empty() )
+ {
+ m_aOverrideFonts.push_back( m_nNextFontID );
+ m_aFonts[ m_nNextFontID++ ] = pFont;
+ }
+ else
+ {
+ DBG_ASSERT( 0, "override font failed" );
+ delete pFont;
+ }
+ }
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/fontmanager/helper.cxx b/vcl/unx/generic/fontmanager/helper.cxx
new file mode 100644
index 000000000000..4b0d327a9a03
--- /dev/null
+++ b/vcl/unx/generic/fontmanager/helper.cxx
@@ -0,0 +1,411 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <cstring>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "vcl/helper.hxx"
+#include "vcl/ppdparser.hxx"
+#include "tools/string.hxx"
+#include "tools/urlobj.hxx"
+#include "osl/file.hxx"
+#include "osl/process.h"
+#include "rtl/bootstrap.hxx"
+
+using ::rtl::Bootstrap;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::rtl::OString;
+using ::rtl::OStringToOUString;
+using ::rtl::OUStringToOString;
+
+namespace psp {
+
+OUString getOfficePath( enum whichOfficePath ePath )
+{
+ static OUString aNetPath;
+ static OUString aUserPath;
+ static OUString aConfigPath;
+ static OUString aEmpty;
+ static bool bOnce = false;
+
+ if( ! bOnce )
+ {
+ bOnce = true;
+ OUString aIni;
+ Bootstrap::get( OUString( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aIni );
+ aIni += OUString( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
+ Bootstrap aBootstrap( aIni );
+ aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "CustomDataUrl" ) ), aConfigPath );
+ aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseInstallation" ) ), aNetPath );
+ aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath );
+ OUString aUPath = aUserPath;
+
+ if( ! aConfigPath.compareToAscii( "file://", 7 ) )
+ {
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aConfigPath.pData, &aSysPath.pData ) == osl_File_E_None )
+ aConfigPath = aSysPath;
+ }
+ if( ! aNetPath.compareToAscii( "file://", 7 ) )
+ {
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aNetPath.pData, &aSysPath.pData ) == osl_File_E_None )
+ aNetPath = aSysPath;
+ }
+ if( ! aUserPath.compareToAscii( "file://", 7 ) )
+ {
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aUserPath.pData, &aSysPath.pData ) == osl_File_E_None )
+ aUserPath = aSysPath;
+ }
+ // ensure user path exists
+ aUPath += OUString( RTL_CONSTASCII_USTRINGPARAM( "/user/psprint" ) );
+ #if OSL_DEBUG_LEVEL > 1
+ oslFileError eErr =
+ #endif
+ osl_createDirectoryPath( aUPath.pData, NULL, NULL );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try to create \"%s\" = %d\n", OUStringToOString( aUPath, RTL_TEXTENCODING_UTF8 ).getStr(), eErr );
+ #endif
+ }
+
+ switch( ePath )
+ {
+ case ConfigPath: return aConfigPath;
+ case NetPath: return aNetPath;
+ case UserPath: return aUserPath;
+ }
+ return aEmpty;
+}
+
+static OString getEnvironmentPath( const char* pKey )
+{
+ OString aPath;
+
+ const char* pValue = getenv( pKey );
+ if( pValue && *pValue )
+ {
+ aPath = OString( pValue );
+ }
+ return aPath;
+}
+
+} // namespace psp
+
+void psp::getPrinterPathList( std::list< OUString >& rPathList, const char* pSubDir )
+{
+ rPathList.clear();
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+
+ OUStringBuffer aPathBuffer( 256 );
+
+ // append net path
+ aPathBuffer.append( getOfficePath( psp::NetPath ) );
+ if( aPathBuffer.getLength() )
+ {
+ aPathBuffer.appendAscii( "/share/psprint" );
+ if( pSubDir )
+ {
+ aPathBuffer.append( sal_Unicode('/') );
+ aPathBuffer.appendAscii( pSubDir );
+ }
+ rPathList.push_back( aPathBuffer.makeStringAndClear() );
+ }
+ // append user path
+ aPathBuffer.append( getOfficePath( psp::UserPath ) );
+ if( aPathBuffer.getLength() )
+ {
+ aPathBuffer.appendAscii( "/user/psprint" );
+ if( pSubDir )
+ {
+ aPathBuffer.append( sal_Unicode('/') );
+ aPathBuffer.appendAscii( pSubDir );
+ }
+ rPathList.push_back( aPathBuffer.makeStringAndClear() );
+ }
+
+ OString aPath( getEnvironmentPath("SAL_PSPRINT") );
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OString aDir( aPath.getToken( 0, ':', nIndex ) );
+ if( ! aDir.getLength() )
+ continue;
+
+ if( pSubDir )
+ {
+ aDir += "/";
+ aDir += pSubDir;
+ }
+ struct stat aStat;
+ if( stat( aDir.getStr(), &aStat ) || ! S_ISDIR( aStat.st_mode ) )
+ continue;
+
+ rPathList.push_back( OStringToOUString( aDir, aEncoding ) );
+ } while( nIndex != -1 );
+
+ #ifdef SYSTEM_PPD_DIR
+ if( pSubDir && rtl_str_compare( pSubDir, PRINTER_PPDDIR ) == 0 )
+ {
+ rPathList.push_back( rtl::OStringToOUString( rtl::OString( SYSTEM_PPD_DIR ), RTL_TEXTENCODING_UTF8 ) );
+ }
+ #endif
+
+ if( rPathList.empty() )
+ {
+ // last resort: next to program file (mainly for setup)
+ OUString aExe;
+ if( osl_getExecutableFile( &aExe.pData ) == osl_Process_E_None )
+ {
+ INetURLObject aDir( aExe );
+ aDir.removeSegment();
+ aExe = aDir.GetMainURL( INetURLObject::NO_DECODE );
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aExe.pData, &aSysPath.pData ) == osl_File_E_None )
+ {
+ rPathList.push_back( aSysPath );
+ }
+ }
+ }
+}
+
+OUString psp::getFontPath()
+{
+ static OUString aPath;
+
+ if( ! aPath.getLength() )
+ {
+ OUStringBuffer aPathBuffer( 512 );
+
+ OUString aConfigPath( getOfficePath( psp::ConfigPath ) );
+ OUString aNetPath( getOfficePath( psp::NetPath ) );
+ OUString aUserPath( getOfficePath( psp::UserPath ) );
+ if( aConfigPath.getLength() )
+ {
+ // #i53530# Path from CustomDataUrl will completely
+ // replace net and user paths if the path exists
+ aPathBuffer.append(aConfigPath);
+ aPathBuffer.appendAscii("/share/fonts");
+ // check existance of config path
+ struct stat aStat;
+ if( 0 != stat( OUStringToOString( aPathBuffer.makeStringAndClear(), osl_getThreadTextEncoding() ).getStr(), &aStat )
+ || ! S_ISDIR( aStat.st_mode ) )
+ aConfigPath = OUString();
+ else
+ {
+ aPathBuffer.append(aConfigPath);
+ aPathBuffer.appendAscii("/share/fonts");
+ }
+ }
+ if( aConfigPath.getLength() == 0 )
+ {
+ if( aNetPath.getLength() )
+ {
+ aPathBuffer.append( aNetPath );
+ aPathBuffer.appendAscii( "/share/fonts/truetype;");
+ aPathBuffer.append( aNetPath );
+ aPathBuffer.appendAscii( "/share/fonts/type1;" );
+ }
+ if( aUserPath.getLength() )
+ {
+ aPathBuffer.append( aUserPath );
+ aPathBuffer.appendAscii( "/user/fonts" );
+ }
+ }
+ OString aEnvPath( getEnvironmentPath( "SAL_FONTPATH_PRIVATE" ) );
+ if( aEnvPath.getLength() )
+ {
+ aPathBuffer.append( sal_Unicode(';') );
+ aPathBuffer.append( OStringToOUString( aEnvPath, osl_getThreadTextEncoding() ) );
+ }
+
+ aPath = aPathBuffer.makeStringAndClear();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "initializing font path to \"%s\"\n", OUStringToOString( aPath, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ }
+ return aPath;
+}
+
+bool psp::convertPfbToPfa( ::osl::File& rInFile, ::osl::File& rOutFile )
+{
+ static unsigned char hexDigits[] =
+ {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+ bool bSuccess = true;
+ bool bEof = false;
+ unsigned char buffer[256];
+ sal_uInt64 nRead;
+ sal_uInt64 nOrgPos = 0;
+ rInFile.getPos( nOrgPos );
+
+ while( bSuccess && ! bEof )
+ {
+ // read leading bytes
+ bEof = ! rInFile.read( buffer, 6, nRead ) && nRead == 6 ? false : true;
+ unsigned int nType = buffer[ 1 ];
+ unsigned int nBytesToRead = buffer[2] | buffer[3] << 8 | buffer[4] << 16 | buffer[5] << 24;
+ if( buffer[0] != 0x80 ) // test for pfb m_agic number
+ {
+ // this migt be a pfa font already
+ if( ! rInFile.read( buffer+6, 9, nRead ) && nRead == 9 &&
+ ( ! std::strncmp( (char*)buffer, "%!FontType1-", 12 ) ||
+ ! std::strncmp( (char*)buffer, "%!PS-AdobeFont-", 15 ) ) )
+ {
+ sal_uInt64 nWrite = 0;
+ if( rOutFile.write( buffer, 15, nWrite ) || nWrite != 15 )
+ bSuccess = false;
+ while( bSuccess &&
+ ! rInFile.read( buffer, sizeof( buffer ), nRead ) &&
+ nRead != 0 )
+ {
+ if( rOutFile.write( buffer, nRead, nWrite ) ||
+ nWrite != nRead )
+ bSuccess = false;
+ }
+ bEof = true;
+ }
+ else
+ bSuccess = false;
+ }
+ else if( nType == 1 || nType == 2 )
+ {
+ unsigned char* pBuffer = new unsigned char[ nBytesToRead+1 ];
+
+ if( ! rInFile.read( pBuffer, nBytesToRead, nRead ) && nRead == nBytesToRead )
+ {
+ if( nType == 1 )
+ {
+ // ascii data, convert dos lineends( \r\n ) and
+ // m_ac lineends( \r ) to \n
+ unsigned char * pWriteBuffer = new unsigned char[ nBytesToRead ];
+ unsigned int nBytesToWrite = 0;
+ for( unsigned int i = 0; i < nBytesToRead; i++ )
+ {
+ if( pBuffer[i] != '\r' )
+ pWriteBuffer[ nBytesToWrite++ ] = pBuffer[i];
+ else if( pBuffer[ i+1 ] == '\n' )
+ {
+ i++;
+ pWriteBuffer[ nBytesToWrite++ ] = '\n';
+ }
+ else
+ pWriteBuffer[ nBytesToWrite++ ] = '\n';
+ }
+ if( rOutFile.write( pWriteBuffer, nBytesToWrite, nRead ) || nRead != nBytesToWrite )
+ bSuccess = false;
+
+ delete [] pWriteBuffer;
+ }
+ else
+ {
+ // binary data
+ unsigned int nBuffer = 0;
+ for( unsigned int i = 0; i < nBytesToRead && bSuccess; i++ )
+ {
+ buffer[ nBuffer++ ] = hexDigits[ pBuffer[ i ] >> 4 ];
+ buffer[ nBuffer++ ] = hexDigits[ pBuffer[ i ] & 15 ];
+ if( nBuffer >= 80 )
+ {
+ buffer[ nBuffer++ ] = '\n';
+ if( rOutFile.write( buffer, nBuffer, nRead ) || nRead != nBuffer )
+ bSuccess = false;
+ nBuffer = 0;
+ }
+ }
+ if( nBuffer > 0 && bSuccess )
+ {
+ buffer[ nBuffer++ ] = '\n';
+ if( rOutFile.write( buffer, nBuffer, nRead ) || nRead != nBuffer )
+ bSuccess = false;
+ }
+ }
+ }
+ else
+ bSuccess = false;
+
+ delete [] pBuffer;
+ }
+ else if( nType == 3 )
+ bEof = true;
+ else
+ bSuccess = false;
+ }
+
+ return bSuccess;
+}
+
+void psp::normPath( OString& rPath )
+{
+ char buf[PATH_MAX];
+
+ ByteString aPath( rPath );
+
+ // double slashes and slash at end are probably
+ // removed by realpath anyway, but since this runs
+ // on many different platforms let's play it safe
+ while( aPath.SearchAndReplace( "//", "/" ) != STRING_NOTFOUND )
+ ;
+ if( aPath.Len() > 0 && aPath.GetChar( aPath.Len()-1 ) == '/' )
+ aPath.Erase( aPath.Len()-1 );
+
+ if( ( aPath.Search( "./" ) != STRING_NOTFOUND ||
+ aPath.Search( "~" ) != STRING_NOTFOUND )
+ && realpath( aPath.GetBuffer(), buf ) )
+ {
+ rPath = buf;
+ }
+ else
+ {
+ rPath = aPath;
+ }
+}
+
+void psp::splitPath( OString& rPath, OString& rDir, OString& rBase )
+{
+ normPath( rPath );
+ sal_Int32 nIndex = rPath.lastIndexOf( '/' );
+ if( nIndex > 0 )
+ rDir = rPath.copy( 0, nIndex );
+ else if( nIndex == 0 ) // root dir
+ rDir = rPath.copy( 0, 1 );
+ if( rPath.getLength() > nIndex+1 )
+ rBase = rPath.copy( nIndex+1 );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/fontmanager/parseAFM.cxx b/vcl/unx/generic/fontmanager/parseAFM.cxx
new file mode 100644
index 000000000000..242537c8e699
--- /dev/null
+++ b/vcl/unx/generic/fontmanager/parseAFM.cxx
@@ -0,0 +1,1492 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
+ *
+ * This file may be freely copied and redistributed as long as:
+ * 1) This entire notice continues to be included in the file,
+ * 2) If the file has been modified in any way, a notice of such
+ * modification is conspicuously indicated.
+ *
+ * PostScript, Display PostScript, and Adobe are registered trademarks of
+ * Adobe Systems Incorporated.
+ *
+ * ************************************************************************
+ * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
+ * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
+ * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
+ * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
+ * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
+ * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * ************************************************************************
+ */
+
+/*
+ * Changes made for OpenOffice.org
+ *
+ * 10/24/2000 pl - changed code to compile with c++-compilers
+ * - added namespace to avoid symbol clashes
+ * - replaced BOOL by bool
+ * - added function to free space allocated by parseFile
+ * 10/26/2000 pl - added additional keys
+ * - added ability to parse slightly broken files
+ * - added charwidth member to GlobalFontInfo
+ * 04/26/2001 pl - added OpenOffice header
+ * 10/19/2005 pl - performance increase:
+ * - fread file in one pass
+ * - replace file io by buffer access
+ * 10/20/2005 pl - performance increase:
+ * - use one table lookup in token() routine
+ * instead of many conditions
+ * - return token length in toke() routine
+ * - use hash lookup instead of binary search
+ * in recognize() routine
+ */
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+/* parseAFM.c
+ *
+ * This file is used in conjuction with the parseAFM.h header file.
+ * This file contains several procedures that are used to parse AFM
+ * files. It is intended to work with an application program that needs
+ * font metric information. The program can be used as is by making a
+ * procedure call to "parseFile" (passing in the expected parameters)
+ * and having it fill in a data structure with the data from the
+ * AFM file, or an application developer may wish to customize this
+ * code.
+ *
+ * There is also a file, parseAFMclient.c, that is a sample application
+ * showing how to call the "parseFile" procedure and how to use the data
+ * after "parseFile" has returned.
+ *
+ * Please read the comments in parseAFM.h and parseAFMclient.c.
+ *
+ * History:
+ * original: DSM Thu Oct 20 17:39:59 PDT 1988
+ * modified: DSM Mon Jul 3 14:17:50 PDT 1989
+ * - added 'storageProblem' return code
+ * - fixed bug of not allocating extra byte for string duplication
+ * - fixed typos
+ * modified: DSM Tue Apr 3 11:18:34 PDT 1990
+ * - added free(ident) at end of parseFile routine
+ * modified: DSM Tue Jun 19 10:16:29 PDT 1990
+ * - changed (width == 250) to (width = 250) in initializeArray
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <math.h>
+
+#include "parseAFM.hxx"
+#include "vcl/strhelper.hxx"
+
+#include "rtl/alloc.h"
+
+#define lineterm EOL /* line terminating character */
+#define normalEOF 1 /* return code from parsing routines used only */
+/* in this module */
+#define Space "space" /* used in string comparison to look for the width */
+/* of the space character to init the widths array */
+#define False "false" /* used in string comparison to check the value of */
+/* boolean keys (e.g. IsFixedPitch) */
+
+#define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0)
+
+namespace psp {
+
+class FileInputStream
+{
+ char* m_pMemory;
+ unsigned int m_nPos;
+ unsigned int m_nLen;
+ public:
+ FileInputStream( const char* pFilename );
+ ~FileInputStream();
+
+ int getChar() { return (m_nPos < m_nLen) ? int(m_pMemory[m_nPos++]) : -1; }
+ void ungetChar()
+ {
+ if( m_nPos > 0 )
+ m_nPos--;
+ }
+ unsigned int tell() const { return m_nPos; }
+ void seek( unsigned int nPos )
+ // NOTE: do not check input data since only results of tell()
+ // get seek()ed in this file
+ { m_nPos = nPos; }
+};
+
+FileInputStream::FileInputStream( const char* pFilename ) :
+ m_pMemory( NULL ),
+ m_nPos( 0 ),
+ m_nLen( 0 )
+{
+ struct stat aStat;
+ if( ! stat( pFilename, &aStat ) &&
+ S_ISREG( aStat.st_mode ) &&
+ aStat.st_size > 0
+ )
+ {
+ FILE* fp = fopen( pFilename, "r" );
+ if( fp )
+ {
+ m_pMemory = (char*)rtl_allocateMemory( aStat.st_size );
+ m_nLen = (unsigned int)fread( m_pMemory, 1, aStat.st_size, fp );
+ fclose( fp );
+ }
+ }
+}
+
+FileInputStream::~FileInputStream()
+{
+ rtl_freeMemory( m_pMemory );
+}
+
+/*************************** GLOBALS ***********************/
+/* "shorts" for fast case statement
+ * The values of each of these enumerated items correspond to an entry in the
+ * table of strings defined below. Therefore, if you add a new string as
+ * new keyword into the keyStrings table, you must also add a corresponding
+ * parseKey AND it MUST be in the same position!
+ *
+ * IMPORTANT: since the sorting algorithm is a binary search, the strings of
+ * keywords must be placed in lexicographical order, below. [Therefore, the
+ * enumerated items are not necessarily in lexicographical order, depending
+ * on the name chosen. BUT, they must be placed in the same position as the
+ * corresponding key string.] The NOPE shall remain in the last position,
+ * since it does not correspond to any key string, and it is used in the
+ * "recognize" procedure to calculate how many possible keys there are.
+ */
+
+// some metrics have Ascent, Descent instead Ascender, Descender or Em
+// which is not allowed per afm spcification, but let us handle
+// this gently
+enum parseKey {
+ ASCENDER, ASCENT, CHARBBOX, CODE, COMPCHAR, CODEHEX, CAPHEIGHT, CHARWIDTH, CHARACTERSET, CHARACTERS, COMMENT,
+ DESCENDER, DESCENT, EM, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES, ENDDIRECTION,
+ ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
+ FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISBASEFONT, ISFIXEDPITCH,
+ ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, MAPPINGSCHEME, METRICSSETS, CHARNAME,
+ NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES, STARTDIRECTION,
+ STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
+ STARTTRACKKERN, STDHW, STDVW, TRACKKERN, UNDERLINEPOSITION,
+ UNDERLINETHICKNESS, VVECTOR, VERSION, XYWIDTH, X0WIDTH, XWIDTH, WEIGHT, XHEIGHT,
+ NOPE
+};
+
+/*************************** PARSING ROUTINES **************/
+
+/*************************** token *************************/
+
+/* A "AFM file Conventions" tokenizer. That means that it will
+ * return the next token delimited by white space. See also
+ * the `linetoken' routine, which does a similar thing but
+ * reads all tokens until the next end-of-line.
+ */
+
+// token white space is ' ', '\n', '\r', ',', '\t', ';'
+static const bool is_white_Array[ 256 ] =
+{ false, false, false, false, false, false, false, false, // 0-7
+ false, true, true, false, false, true, false, false, // 8-15
+ false, false, false, false, false, false, false, false, // 16-23
+ false, false, false, false, false, false, false, false, // 24-31
+ true, false, false, false, false, false, false, false, // 32-39
+ false, false, false, false, true, false, false, false, // 40-47
+ false, false, false, false, false, false, false, false, // 48-55
+ false, false, false, true, false, false, false, false, // 56-63
+
+ false, false, false, false, false, false, false, false, // 64 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 127
+
+ false, false, false, false, false, false, false, false, // 128 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 191
+
+ false, false, false, false, false, false, false, false, // 192 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 255
+};
+// token delimiters are ' ', '\n', '\r', '\t', ':', ';'
+static const bool is_delimiter_Array[ 256 ] =
+{ false, false, false, false, false, false, false, false, // 0-7
+ false, true, true, false, false, true, false, false, // 8-15
+ false, false, false, false, false, false, false, false, // 16-23
+ false, false, false, false, false, false, false, false, // 24-31
+ true, false, false, false, false, false, false, false, // 32-39
+ false, false, false, false, false, false, false, false, // 40-47
+ false, false, false, false, false, false, false, false, // 48-55
+ false, false, true, true, false, false, false, false, // 56-63
+
+ false, false, false, false, false, false, false, false, // 64 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 127
+
+ false, false, false, false, false, false, false, false, // 128 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 191
+
+ false, false, false, false, false, false, false, false, // 192 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 255
+};
+static char *token( FileInputStream* stream, int& rLen )
+{
+ static char ident[MAX_NAME]; /* storage buffer for keywords */
+
+ int ch, idx;
+
+ /* skip over white space */
+ // relies on EOF = -1
+ while( is_white_Array[ (ch = stream->getChar()) & 255 ] )
+ ;
+
+ idx = 0;
+ while( ch != -1 && ! is_delimiter_Array[ ch & 255 ] && idx < MAX_NAME-1 )
+ {
+ ident[idx++] = ch;
+ ch = stream->getChar();
+ }
+
+ if (ch == -1 && idx < 1) return ((char *)NULL);
+ if (idx >= 1 && ch != ':' && ch != -1) stream->ungetChar();
+ if (idx < 1 ) ident[idx++] = ch; /* single-character token */
+ ident[idx] = 0;
+ rLen = idx;
+
+ return(ident); /* returns pointer to the token */
+
+} /* token */
+
+
+/*************************** linetoken *************************/
+
+/* "linetoken" will get read all tokens until the EOL character from
+ * the given stream. This is used to get any arguments that can be
+ * more than one word (like Comment lines and FullName).
+ */
+
+static char *linetoken( FileInputStream* stream )
+{
+ static char ident[MAX_NAME]; /* storage buffer for keywords */
+ int ch, idx;
+
+ while ((ch = stream->getChar()) == ' ' || ch == '\t' ) ;
+
+ idx = 0;
+ while (ch != -1 && ch != lineterm && ch != '\r' && idx < MAX_NAME-1 )
+ {
+ ident[idx++] = ch;
+ ch = stream->getChar();
+ } /* while */
+
+ stream->ungetChar();
+ ident[idx] = 0;
+
+ return(ident); /* returns pointer to the token */
+
+} /* linetoken */
+
+
+/*************************** recognize *************************/
+
+/* This function tries to match a string to a known list of
+ * valid AFM entries (check the keyStrings array above).
+ * "ident" contains everything from white space through the
+ * next space, tab, or ":" character.
+ *
+ * The algorithm is a standard Knuth binary search.
+ */
+#include "afm_hash.cpp"
+
+static inline enum parseKey recognize( register char* ident, int len)
+{
+ const hash_entry* pEntry = AfmKeywordHash::in_word_set( ident, len );
+ return pEntry ? pEntry->eKey : NOPE;
+
+} /* recognize */
+
+
+/************************* parseGlobals *****************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "StartCharMetrics" keyword, which essentially marks the
+ * end of the Global Font Information and the beginning of the character
+ * metrics information.
+ *
+ * If the caller of "parseFile" specified that it wanted the Global
+ * Font Information (as defined by the "AFM file Specification"
+ * document), then that information will be stored in the returned
+ * data structure.
+ *
+ * Any Global Font Information entries that are not found in a
+ * given file, will have the usual default initialization value
+ * for its type (i.e. entries of type int will be 0, etc).
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseGlobals( FileInputStream* fp, register GlobalFontInfo* gfi )
+{
+ bool cont = true, save = (gfi != NULL);
+ int error = ok;
+ register char *keyword;
+ int direction = -1;
+ int tokenlen;
+
+ while (cont)
+ {
+ keyword = token(fp, tokenlen);
+
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Global Font info section */
+ /* without saving any of the data */
+ switch (recognize(keyword, tokenlen))
+ {
+ case STARTCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire global font info section, */
+ /* saving the data */
+ switch(recognize(keyword, tokenlen))
+ {
+ case STARTFONTMETRICS:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->afmVersion = strdup( keyword );
+ break;
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case FONTNAME:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontName = strdup( keyword );
+ break;
+ case ENCODINGSCHEME:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->encodingScheme = strdup( keyword );
+ break;
+ case FULLNAME:
+ if ((keyword = linetoken(fp)) != NULL)
+ gfi->fullName = strdup( keyword );
+ break;
+ case FAMILYNAME:
+ if ((keyword = linetoken(fp)) != NULL)
+ gfi->familyName = strdup( keyword );
+ break;
+ case WEIGHT:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->weight = strdup( keyword );
+ break;
+ case ITALICANGLE:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->italicAngle = StringToDouble( keyword );
+ break;
+ case ISFIXEDPITCH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ {
+ if (MATCH(keyword, False))
+ gfi->isFixedPitch = 0;
+ else
+ gfi->isFixedPitch = 1;
+ }
+ break;
+ case UNDERLINEPOSITION:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->underlinePosition = atoi(keyword);
+ break;
+ case UNDERLINETHICKNESS:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->underlineThickness = atoi(keyword);
+ break;
+ case VERSION:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->version = strdup( keyword );
+ break;
+ case NOTICE:
+ if ((keyword = linetoken(fp)) != NULL)
+ gfi->notice = strdup( keyword );
+ break;
+ case FONTBBOX:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontBBox.llx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontBBox.lly = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontBBox.urx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontBBox.ury = atoi(keyword);
+ break;
+ case CAPHEIGHT:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->capHeight = atoi(keyword);
+ break;
+ case XHEIGHT:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->xHeight = atoi(keyword);
+ break;
+ case DESCENT:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->descender = -atoi(keyword);
+ break;
+ case DESCENDER:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->descender = atoi(keyword);
+ break;
+ case ASCENT:
+ case ASCENDER:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->ascender = atoi(keyword);
+ break;
+ case STARTCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case EM:
+ // skip one token
+ keyword = token(fp,tokenlen);
+ break;
+ case STARTDIRECTION:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ direction = atoi(keyword);
+ break; /* ignore this for now */
+ case ENDDIRECTION:
+ break; /* ignore this for now */
+ case MAPPINGSCHEME:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case CHARACTERS:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case ISBASEFONT:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case CHARACTERSET:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case STDHW:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case STDVW:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case CHARWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ {
+ if (direction == 0)
+ gfi->charwidth = atoi(keyword);
+ }
+ keyword = token(fp,tokenlen);
+ /* ignore y-width for now */
+ break;
+ case METRICSSETS:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ return(error);
+
+} /* parseGlobals */
+
+
+/************************* parseCharWidths **************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndCharMetrics" keyword. It will save the character
+ * width info (as opposed to all of the character metric information)
+ * if requested by the caller of parseFile. Otherwise, it will just
+ * parse through the section without saving any information.
+ *
+ * If data is to be saved, parseCharWidths is passed in a pointer
+ * to an array of widths that has already been initialized by the
+ * standard value for unmapped character codes. This function parses
+ * the Character Metrics section only storing the width information
+ * for the encoded characters into the array using the character code
+ * as the index into that array.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCharWidths( FileInputStream* fp, register int* cwi)
+{
+ bool cont = true, save = (cwi != NULL);
+ int pos = 0, error = ok, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Char Metrics section without */
+ /* saving any of the data*/
+ switch (recognize(keyword,tokenlen))
+ {
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire char metrics section, saving */
+ /* only the char x-width info */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ pos = atoi(keyword);
+ break;
+ case XYWIDTH:
+ /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen); /* eat values */
+ error = parseError;
+ break;
+ case CODEHEX:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ sscanf(keyword, "<%x>", &pos);
+ break;
+ case X0WIDTH:
+ (void) token(fp,tokenlen);
+ break;
+ case XWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ if (pos >= 0) /* ignore unmapped chars */
+ cwi[pos] = atoi(keyword);
+ break;
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case CHARNAME: /* eat values (so doesn't cause parseError) */
+ keyword = token(fp,tokenlen);
+ break;
+ case CHARBBOX:
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ break;
+ case LIGATURE:
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ break;
+ case VVECTOR:
+ keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen);
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ return(error);
+
+} /* parseCharWidths */
+
+
+/*
+ * number of char metrics is almost allways inaccurate, so be gentle and try to
+ * adapt our internal storage by adjusting the allocated list
+ */
+
+static int
+reallocFontMetrics( void **pp_fontmetrics, int *p_oldcount, int n_newcount, unsigned int n_size )
+{
+ char *p_tmpmetrics = NULL;
+
+ if ((pp_fontmetrics == NULL) || (*pp_fontmetrics == NULL))
+ return storageProblem;
+
+ if (*p_oldcount == n_newcount)
+ return ok;
+
+ p_tmpmetrics = (char*)realloc(*pp_fontmetrics, n_newcount * n_size);
+ if (p_tmpmetrics == NULL)
+ return storageProblem;
+
+ if ( n_newcount > *p_oldcount )
+ {
+ char *p_inimetrics = p_tmpmetrics + n_size * *p_oldcount;
+ int n_inimetrics = n_size * (n_newcount - *p_oldcount);
+ memset( p_inimetrics, 0, n_inimetrics );
+ }
+
+ *pp_fontmetrics = p_tmpmetrics;
+ *p_oldcount = n_newcount;
+
+ return ok;
+}
+
+static unsigned int
+enlargeCount( unsigned int n_oldcount )
+{
+ unsigned int n_newcount = n_oldcount + n_oldcount / 5;
+ if (n_oldcount == n_newcount )
+ n_newcount = n_oldcount + 5;
+
+ return n_newcount;
+}
+
+/************************* parseCharMetrics ************************/
+
+/* This function is called by parseFile if the caller of parseFile
+ * requested that all character metric information be saved
+ * (as opposed to only the character width information).
+ *
+ * parseCharMetrics is passed in a pointer to an array of records
+ * to hold information on a per character basis. This function
+ * parses the Character Metrics section storing all character
+ * metric information for the ALL characters (mapped and unmapped)
+ * into the array.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCharMetrics( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, firstTime = true;
+ int error = ok, count = 0, tokenlen;
+ register CharMetricInfo *temp = fi->cmi;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ if (!(count < fi->numOfChars))
+ {
+ reallocFontMetrics( (void**)&(fi->cmi),
+ &(fi->numOfChars), enlargeCount(fi->numOfChars),
+ sizeof(CharMetricInfo) );
+ temp = &(fi->cmi[ count - 1 ]);
+ }
+ if (count < fi->numOfChars)
+ {
+ if (firstTime) firstTime = false;
+ else temp++;
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->code = atoi(keyword);
+ if (fi->gfi && fi->gfi->charwidth)
+ temp->wx = fi->gfi->charwidth;
+ count++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case CODEHEX:
+ if (!(count < fi->numOfChars ))
+ {
+ reallocFontMetrics( (void**)&(fi->cmi),
+ &(fi->numOfChars), enlargeCount(fi->numOfChars),
+ sizeof(CharMetricInfo) );
+ temp = &(fi->cmi[ count - 1 ]);
+ }
+ if (count < fi->numOfChars) {
+ if (firstTime)
+ firstTime = false;
+ else
+ temp++;
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ sscanf(keyword,"<%x>", &temp->code);
+ if (fi->gfi && fi->gfi->charwidth)
+ temp->wx = fi->gfi->charwidth;
+ count++;
+ }
+ else {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case XYWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->wx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->wy = atoi(keyword);
+ break;
+ case X0WIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->wx = atoi(keyword);
+ break;
+ case XWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->wx = atoi(keyword);
+ break;
+ case CHARNAME:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->name = (char *)strdup(keyword);
+ break;
+ case CHARBBOX:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->charBBox.llx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->charBBox.lly = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->charBBox.urx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->charBBox.ury = atoi(keyword);
+ break;
+ case LIGATURE: {
+ Ligature **tail = &(temp->ligs);
+ Ligature *node = *tail;
+
+ if (*tail != NULL)
+ {
+ while (node->next != NULL)
+ node = node->next;
+ tail = &(node->next);
+ }
+
+ *tail = (Ligature *) calloc(1, sizeof(Ligature));
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ (*tail)->succ = (char *)strdup(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ (*tail)->lig = (char *)strdup(keyword);
+ break; }
+ case ENDCHARMETRICS:
+ cont = false;;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case VVECTOR:
+ keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen);
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if ((error == ok) && (count != fi->numOfChars))
+ error = reallocFontMetrics( (void**)&(fi->cmi), &(fi->numOfChars),
+ count, sizeof(CharMetricInfo) );
+
+ if ((error == ok) && (count != fi->numOfChars))
+ error = parseError;
+
+ return(error);
+
+} /* parseCharMetrics */
+
+
+
+/************************* parseTrackKernData ***********************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
+ * track kerning data if requested by the caller of parseFile.
+ *
+ * parseTrackKernData is passed in a pointer to the FontInfo record.
+ * If data is to be saved, the FontInfo record will already contain
+ * a valid pointer to storage for the track kerning data.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseTrackKernData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, save = (fi->tkd != NULL);
+ int pos = 0, error = ok, tcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Track Kerning Data */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDTRACKKERN:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Track Kerning Data section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case TRACKKERN:
+ if (!(tcount < fi->numOfTracks))
+ {
+ reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks),
+ enlargeCount(fi->numOfTracks), sizeof(TrackKernData) );
+ }
+
+ if (tcount < fi->numOfTracks)
+ {
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos].degree = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos].minPtSize = StringToDouble(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos].minKernAmt = StringToDouble(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos].maxPtSize = StringToDouble(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos++].maxKernAmt = StringToDouble(keyword);
+ tcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case ENDTRACKKERN:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && tcount != fi->numOfTracks)
+ error = reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks),
+ tcount, sizeof(TrackKernData) );
+
+ if (error == ok && tcount != fi->numOfTracks)
+ error = parseError;
+
+ return(error);
+
+} /* parseTrackKernData */
+
+
+/************************* parsePairKernData ************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndKernPairs" or "EndKernData" keywords. It will save
+ * the pair kerning data if requested by the caller of parseFile.
+ *
+ * parsePairKernData is passed in a pointer to the FontInfo record.
+ * If data is to be saved, the FontInfo record will already contain
+ * a valid pointer to storage for the pair kerning data.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parsePairKernData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, save = (fi->pkd != NULL);
+ int pos = 0, error = ok, pcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Pair Kerning Data */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDKERNPAIRS:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Pair Kerning Data section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case KERNPAIR:
+ if (!(pcount < fi->numOfPairs))
+ {
+ reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ enlargeCount(fi->numOfPairs), sizeof(PairKernData) );
+ }
+ if (pcount < fi->numOfPairs)
+ {
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].name1 = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].name2 = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].xamt = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos++].yamt = atoi(keyword);
+ pcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case KERNPAIRXAMT:
+ if (!(pcount < fi->numOfPairs))
+ {
+ reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ enlargeCount(fi->numOfPairs), sizeof(PairKernData) );
+ }
+ if (pcount < fi->numOfPairs)
+ {
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].name1 = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].name2 = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos++].xamt = atoi(keyword);
+ pcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case ENDKERNPAIRS:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if ((error == ok) && (pcount != fi->numOfPairs))
+ error = reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ pcount, sizeof(PairKernData) );
+
+ if (error == ok && pcount != fi->numOfPairs)
+ error = parseError;
+
+ return(error);
+
+} /* parsePairKernData */
+
+
+/************************* parseCompCharData **************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndComposites" keyword. It will save the composite
+ * character data if requested by the caller of parseFile.
+ *
+ * parseCompCharData is passed in a pointer to the FontInfo record, and
+ * a boolean representing if the data should be saved.
+ *
+ * This function will create the appropriate amount of storage for
+ * the composite character data and store a pointer to the storage
+ * in the FontInfo record.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCompCharData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, firstTime = true, save = (fi->ccd != NULL);
+ int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (ccount > fi->numOfComps)
+ {
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ enlargeCount(fi->numOfComps), sizeof(CompCharData) );
+ }
+ if (ccount > fi->numOfComps)
+ {
+ error = parseError;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Composite Character info */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDCOMPOSITES:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case COMMENT:
+ case COMPCHAR:
+ keyword = linetoken(fp);
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Composite Character info section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case COMPCHAR:
+ if (!(ccount < fi->numOfComps))
+ {
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ enlargeCount(fi->numOfComps), sizeof(CompCharData) );
+ }
+ if (ccount < fi->numOfComps)
+ {
+ keyword = token(fp,tokenlen);
+ if (pcount != fi->ccd[pos].numOfPieces)
+ error = parseError;
+ pcount = 0;
+ if (firstTime) firstTime = false;
+ else pos++;
+ fi->ccd[pos].ccName = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->ccd[pos].numOfPieces = atoi(keyword);
+ fi->ccd[pos].pieces = (Pcc *)
+ calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc));
+ j = 0;
+ ccount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case COMPCHARPIECE:
+ if (pcount < fi->ccd[pos].numOfPieces)
+ {
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->ccd[pos].pieces[j].pccName = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->ccd[pos].pieces[j].deltax = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->ccd[pos].pieces[j++].deltay = atoi(keyword);
+ pcount++;
+ }
+ else
+ error = parseError;
+ break;
+ case ENDCOMPOSITES:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && ccount != fi->numOfComps)
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ ccount, sizeof(CompCharData) );
+
+ if (error == ok && ccount != fi->numOfComps)
+ error = parseError;
+
+ return(error);
+
+} /* parseCompCharData */
+
+
+
+
+/*************************** 'PUBLIC' FUNCTION ********************/
+
+
+/*************************** parseFile *****************************/
+
+/* parseFile is the only 'public' procedure available. It is called
+ * from an application wishing to get information from an AFM file.
+ * The caller of this function is responsible for locating and opening
+ * an AFM file and handling all errors associated with that task.
+ *
+ * parseFile expects 3 parameters: a filename pointer, a pointer
+ * to a (FontInfo *) variable (for which storage will be allocated and
+ * the data requested filled in), and a mask specifying which
+ * data from the AFM file should be saved in the FontInfo structure.
+ *
+ * The file will be parsed and the requested data will be stored in
+ * a record of type FontInfo (refer to ParseAFM.h).
+ *
+ * parseFile returns an error code as defined in parseAFM.h.
+ *
+ * The position of the read/write pointer associated with the file
+ * pointer upon return of this function is undefined.
+ */
+
+int parseFile( const char* pFilename, FontInfo** fi, FLAGS flags)
+{
+ FileInputStream aFile( pFilename );
+
+ int code = ok; /* return code from each of the parsing routines */
+ int error = ok; /* used as the return code from this function */
+ int tokenlen;
+
+ register char *keyword; /* used to store a token */
+
+
+ (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo));
+ if ((*fi) == NULL) {error = storageProblem; return(error);}
+
+ if (flags & P_G)
+ {
+ (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo));
+ if ((*fi)->gfi == NULL) {error = storageProblem; return(error);}
+ }
+
+ /* The AFM file begins with Global Font Information. This section */
+ /* will be parsed whether or not information should be saved. */
+ code = parseGlobals(&aFile, (*fi)->gfi);
+
+ if (code < 0) error = code;
+
+ /* The Global Font Information is followed by the Character Metrics */
+ /* section. Which procedure is used to parse this section depends on */
+ /* how much information should be saved. If all of the metrics info */
+ /* is wanted, parseCharMetrics is called. If only the character widths */
+ /* is wanted, parseCharWidths is called. parseCharWidths will also */
+ /* be called in the case that no character data is to be saved, just */
+ /* to parse through the section. */
+
+ if ((code != normalEOF) && (code != earlyEOF))
+ {
+ if ((keyword = token(&aFile,tokenlen)) != NULL)
+ (*fi)->numOfChars = atoi(keyword);
+ if (flags & (P_M ^ P_W))
+ {
+ (*fi)->cmi = (CharMetricInfo *)
+ calloc((*fi)->numOfChars, sizeof(CharMetricInfo));
+ if ((*fi)->cmi == NULL) {error = storageProblem; return(error);}
+ code = parseCharMetrics(&aFile, *fi);
+ }
+ else
+ {
+ if (flags & P_W)
+ {
+ (*fi)->cwi = (int *) calloc(256, sizeof(int));
+ if ((*fi)->cwi == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ }
+ /* parse section regardless */
+ code = parseCharWidths(&aFile, (*fi)->cwi);
+ } /* else */
+ } /* if */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ /* The remaining sections of the AFM are optional. This code will */
+ /* look at the next keyword in the file to determine what section */
+ /* is next, and then allocate the appropriate amount of storage */
+ /* for the data (if the data is to be saved) and call the */
+ /* appropriate parsing routine to parse the section. */
+
+ while ((code != normalEOF) && (code != earlyEOF))
+ {
+ keyword = token(&aFile,tokenlen);
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ code = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case STARTKERNDATA:
+ break;
+ case ENDKERNDATA:
+ break;
+ case STARTTRACKKERN:
+ keyword = token(&aFile,tokenlen);
+ if ((flags & P_T) && keyword)
+ {
+ (*fi)->numOfTracks = atoi(keyword);
+ (*fi)->tkd = (TrackKernData *)
+ calloc((*fi)->numOfTracks, sizeof(TrackKernData));
+ if ((*fi)->tkd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parseTrackKernData(&aFile, *fi);
+ break;
+ case STARTKERNPAIRS:
+ keyword = token(&aFile,tokenlen);
+ if ((flags & P_P) && keyword)
+ {
+ (*fi)->numOfPairs = atoi(keyword);
+ (*fi)->pkd = (PairKernData *)
+ calloc((*fi)->numOfPairs, sizeof(PairKernData));
+ if ((*fi)->pkd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parsePairKernData(&aFile, *fi);
+ break;
+ case STARTCOMPOSITES:
+ keyword = token(&aFile,tokenlen);
+ if ((flags & P_C) && keyword)
+ {
+ (*fi)->numOfComps = atoi(keyword);
+ (*fi)->ccd = (CompCharData *)
+ calloc((*fi)->numOfComps, sizeof(CompCharData));
+ if ((*fi)->ccd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parseCompCharData(&aFile, *fi);
+ break;
+ case ENDFONTMETRICS:
+ code = normalEOF;
+ break;
+ case COMMENT:
+ linetoken(&aFile);
+ break;
+ case NOPE:
+ default:
+ code = parseError;
+ break;
+ } /* switch */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ } /* while */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ return(error);
+
+} /* parseFile */
+
+void
+freeFontInfo (FontInfo *fi)
+{
+ int i;
+
+ if (fi->gfi)
+ {
+ free (fi->gfi->afmVersion);
+ free (fi->gfi->fontName);
+ free (fi->gfi->fullName);
+ free (fi->gfi->familyName);
+ free (fi->gfi->weight);
+ free (fi->gfi->version);
+ free (fi->gfi->notice);
+ free (fi->gfi->encodingScheme);
+ free (fi->gfi);
+ }
+
+ free (fi->cwi);
+
+ if (fi->cmi)
+ {
+ for (i = 0; i < fi->numOfChars; i++)
+ {
+ Ligature *ligs;
+ free (fi->cmi[i].name);
+ ligs = fi->cmi[i].ligs;
+ while (ligs)
+ {
+ Ligature *tmp;
+ tmp = ligs;
+ ligs = ligs->next;
+ free (tmp->succ);
+ free (tmp->lig);
+ free (tmp);
+ }
+ }
+ free (fi->cmi);
+ }
+
+ free (fi->tkd);
+
+ if (fi->pkd)
+ {
+ for ( i = 0; i < fi->numOfPairs; i++)
+ {
+ free (fi->pkd[i].name1);
+ free (fi->pkd[i].name2);
+ }
+ free (fi->pkd);
+ }
+
+ if (fi->ccd)
+ {
+ for (i = 0; i < fi->numOfComps; i++)
+ {
+ free (fi->ccd[i].ccName);
+ int j;
+ for (j = 0; j < fi->ccd[i].numOfPieces; j++)
+ free (fi->ccd[i].pieces[j].pccName);
+
+ free (fi->ccd[i].pieces);
+ }
+ free (fi->ccd);
+ }
+
+ free (fi);
+}
+
+} // namspace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/fontmanager/parseAFM.hxx b/vcl/unx/generic/fontmanager/parseAFM.hxx
new file mode 100644
index 000000000000..0c390bd8cf8d
--- /dev/null
+++ b/vcl/unx/generic/fontmanager/parseAFM.hxx
@@ -0,0 +1,337 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * (C) 1988, 1989 by Adobe Systems Incorporated. All rights reserved.
+ *
+ * This file may be freely copied and redistributed as long as:
+ * 1) This entire notice continues to be included in the file,
+ * 2) If the file has been modified in any way, a notice of such
+ * modification is conspicuously indicated.
+ *
+ * PostScript, Display PostScript, and Adobe are registered trademarks of
+ * Adobe Systems Incorporated.
+ *
+ * ************************************************************************
+ * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
+ * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
+ * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
+ * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
+ * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
+ * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * ************************************************************************
+ */
+
+/*
+ * Changes made for OpenOffice.org
+ *
+ * 10/24/2000 pl - changed code to compile with c++-compilers
+ * - added namespace to avoid symbol clashes
+ * - replaced BOOL by bool
+ * - added function to free space allocated by parseFile
+ * 10/26/2000 pl - added additional keys
+ * - added ability to parse slightly broken files
+ * - added charwidth member to GlobalFontInfo
+ * 04/26/2001 pl - added OpenOffice header
+ * 10/19/2005 pl - changed parseFile to accept a file name instead of a stream
+ */
+
+/* ParseAFM.h
+ *
+ * This header file is used in conjuction with the parseAFM.c file.
+ * Together these files provide the functionality to parse Adobe Font
+ * Metrics files and store the information in predefined data structures.
+ * It is intended to work with an application program that needs font metric
+ * information. The program can be used as is by making a procedure call to
+ * parse an AFM file and have the data stored, or an application developer
+ * may wish to customize the code.
+ *
+ * This header file defines the data structures used as well as the key
+ * strings that are currently recognized by this version of the AFM parser.
+ * This program is based on the document "Adobe Font Metrics Files,
+ * Specification Version 2.0".
+ *
+ * AFM files are separated into distinct sections of different data. Because
+ * of this, the parseAFM program can parse a specified file to only save
+ * certain sections of information based on the application's needs. A record
+ * containing the requested information will be returned to the application.
+ *
+ * AFM files are divided into five sections of data:
+ * 1) The Global Font Information
+ * 2) The Character Metrics Information
+ * 3) The Track Kerning Data
+ * 4) The Pair-Wise Kerning Data
+ * 5) The Composite Character Data
+ *
+ * Basically, the application can request any of these sections independent
+ * of what other sections are requested. In addition, in recognizing that
+ * many applications will want ONLY the x-width of characters and not all
+ * of the other character metrics information, there is a way to receive
+ * only the width information so as not to pay the storage cost for the
+ * unwanted data. An application should never request both the
+ * "quick and dirty" char metrics (widths only) and the Character Metrics
+ * Information since the Character Metrics Information will contain all
+ * of the character widths as well.
+ *
+ * There is a procedure in parseAFM.c, called parseFile, that can be
+ * called from any application wishing to get information from the AFM File.
+ * This procedure expects 3 parameters: a vaild file descriptor, a pointer
+ * to a (FontInfo *) variable (for which space will be allocated and then
+ * will be filled in with the data requested), and a mask specifying
+ * which data from the AFM File should be saved in the FontInfo structure.
+ *
+ * The flags that can be used to set the appropriate mask are defined below.
+ * In addition, several commonly used masks have already been defined.
+ *
+ * History:
+ * original: DSM Thu Oct 20 17:39:59 PDT 1988
+ * modified: DSM Mon Jul 3 14:17:50 PDT 1989
+ * - added 'storageProblem' return code
+ * - fixed typos
+ */
+
+#include <stdio.h>
+
+namespace psp {
+
+/* your basic constants */
+#define EOL '\n' /* end-of-line indicator */
+#define MAX_NAME 4096 /* max length for identifiers */
+#define FLAGS int
+
+
+
+/* Flags that can be AND'ed together to specify exactly what
+ * information from the AFM file should be saved.
+ */
+#define P_G 0x01 /* 0000 0001 */ /* Global Font Info */
+#define P_W 0x02 /* 0000 0010 */ /* Character Widths ONLY */
+#define P_M 0x06 /* 0000 0110 */ /* All Char Metric Info */
+#define P_P 0x08 /* 0000 1000 */ /* Pair Kerning Info */
+#define P_T 0x10 /* 0001 0000 */ /* Track Kerning Info */
+#define P_C 0x20 /* 0010 0000 */ /* Composite Char Info */
+
+
+/* Commonly used flags
+ */
+#define P_GW (P_G | P_W)
+#define P_GM (P_G | P_M)
+#define P_GMP (P_G | P_M | P_P)
+#define P_GMK (P_G | P_M | P_P | P_T)
+#define P_ALL (P_G | P_M | P_P | P_T | P_C)
+
+
+
+/* Possible return codes from the parseFile procedure.
+ *
+ * ok means there were no problems parsing the file.
+ *
+ * parseError means that there was some kind of parsing error, but the
+ * parser went on. This could include problems like the count for any given
+ * section does not add up to how many entries there actually were, or
+ * there was a key that was not recognized. The return record may contain
+ * vaild data or it may not.
+ *
+ * earlyEOF means that an End of File was encountered before expected. This
+ * may mean that the AFM file had been truncated, or improperly formed.
+ *
+ * storageProblem means that there were problems allocating storage for
+ * the data structures that would have contained the AFM data.
+ */
+
+enum afmError { ok = 0, parseError = -1, earlyEOF = -2, storageProblem = -3 };
+
+
+/************************* TYPES *********************************/
+/* Below are all of the data structure definitions. These structures
+ * try to map as closely as possible to grouping and naming of data
+ * in the AFM Files.
+ */
+
+
+/* Bounding box definition. Used for the Font BBox as well as the
+ * Character BBox.
+ */
+typedef struct
+{
+ int llx; /* lower left x-position */
+ int lly; /* lower left y-position */
+ int urx; /* upper right x-position */
+ int ury; /* upper right y-position */
+} BBox;
+
+
+/* Global Font information.
+ * The key that each field is associated with is in comments. For an
+ * explanation about each key and its value please refer to the AFM
+ * documentation (full title & version given above).
+ */
+typedef struct
+{
+ char *afmVersion; /* key: StartFontMetrics */
+ char *fontName; /* key: FontName */
+ char *fullName; /* key: FullName */
+ char *familyName; /* key: FamilyName */
+ char *weight; /* key: Weight */
+ float italicAngle; /* key: ItalicAngle */
+ bool isFixedPitch; /* key: IsFixedPitch */
+ BBox fontBBox; /* key: FontBBox */
+ int underlinePosition; /* key: UnderlinePosition */
+ int underlineThickness; /* key: UnderlineThickness */
+ char *version; /* key: Version */
+ char *notice; /* key: Notice */
+ char *encodingScheme; /* key: EncodingScheme */
+ int capHeight; /* key: CapHeight */
+ int xHeight; /* key: XHeight */
+ int ascender; /* key: Ascender */
+ int descender; /* key: Descender */
+ int charwidth; /* key: CharWidth */
+} GlobalFontInfo;
+
+
+/* Ligature definition is a linked list since any character can have
+ * any number of ligatures.
+ */
+typedef struct _t_ligature
+{
+ char *succ, *lig;
+ struct _t_ligature *next;
+} Ligature;
+
+
+/* Character Metric Information. This structure is used only if ALL
+ * character metric information is requested. If only the character
+ * widths is requested, then only an array of the character x-widths
+ * is returned.
+ *
+ * The key that each field is associated with is in comments. For an
+ * explanation about each key and its value please refer to the
+ * Character Metrics section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ int code, /* key: C */
+ wx, /* key: WX */
+ w0x, /* key: W0X */
+ wy; /* together wx and wy are associated with key: W */
+ char *name; /* key: N */
+ BBox charBBox; /* key: B */
+ Ligature *ligs; /* key: L (linked list; not a fixed number of Ls */
+} CharMetricInfo;
+
+
+/* Track kerning data structure.
+ * The fields of this record are the five values associated with every
+ * TrackKern entry.
+ *
+ * For an explanation about each value please refer to the
+ * Track Kerning section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ int degree;
+ float minPtSize,
+ minKernAmt,
+ maxPtSize,
+ maxKernAmt;
+} TrackKernData;
+
+
+/* Pair Kerning data structure.
+ * The fields of this record are the four values associated with every
+ * KP entry. For KPX entries, the yamt will be zero.
+ *
+ * For an explanation about each value please refer to the
+ * Pair Kerning section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *name1;
+ char *name2;
+ int xamt,
+ yamt;
+} PairKernData;
+
+
+/* PCC is a piece of a composite character. This is a sub structure of a
+ * compCharData described below.
+ * These fields will be filled in with the values from the key PCC.
+ *
+ * For an explanation about each key and its value please refer to the
+ * Composite Character section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *pccName;
+ int deltax,
+ deltay;
+} Pcc;
+
+
+/* Composite Character Information data structure.
+ * The fields ccName and numOfPieces are filled with the values associated
+ * with the key CC. The field pieces points to an array (size = numOfPieces)
+ * of information about each of the parts of the composite character. That
+ * array is filled in with the values from the key PCC.
+ *
+ * For an explanation about each key and its value please refer to the
+ * Composite Character section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *ccName;
+ int numOfPieces;
+ Pcc *pieces;
+} CompCharData;
+
+
+/* FontInfo
+ * Record type containing pointers to all of the other data
+ * structures containing information about a font.
+ * A a record of this type is filled with data by the
+ * parseFile function.
+ */
+typedef struct
+{
+ GlobalFontInfo *gfi; /* ptr to a GlobalFontInfo record */
+ int *cwi; /* ptr to 256 element array of just char widths */
+ int numOfChars; /* number of entries in char metrics array */
+ CharMetricInfo *cmi; /* ptr to char metrics array */
+ int numOfTracks; /* number to entries in track kerning array */
+ TrackKernData *tkd; /* ptr to track kerning array */
+ int numOfPairs; /* number to entries in pair kerning array */
+ PairKernData *pkd; /* ptr to pair kerning array */
+ int numOfComps; /* number to entries in comp char array */
+ CompCharData *ccd; /* ptr to comp char array */
+} FontInfo;
+
+
+
+/************************* PROCEDURES ****************************/
+
+/* Call this procedure to do the grunt work of parsing an AFM file.
+ *
+ * "fp" should be a valid file pointer to an AFM file.
+ *
+ * "fi" is a pointer to a pointer to a FontInfo record sturcture
+ * (defined above). Storage for the FontInfo structure will be
+ * allocated in parseFile and the structure will be filled in
+ * with the requested data from the AFM File.
+ *
+ * "flags" is a mask with bits set representing what data should
+ * be saved. Defined above are valid flags that can be used to set
+ * the mask, as well as a few commonly used masks.
+ *
+ * The possible return codes from parseFile are defined above.
+ */
+
+int parseFile( const char* pFilename, FontInfo **fi, FLAGS flags );
+void freeFontInfo(FontInfo *fi);
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/cdeint.cxx b/vcl/unx/generic/gdi/cdeint.cxx
new file mode 100644
index 000000000000..a6a37a178c48
--- /dev/null
+++ b/vcl/unx/generic/gdi/cdeint.cxx
@@ -0,0 +1,247 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <tools/stream.hxx>
+#include <tools/debug.hxx>
+
+#include <vcl/settings.hxx>
+
+#include <unx/salunx.h>
+#include <unx/saldisp.hxx>
+#include <unx/cdeint.hxx>
+
+CDEIntegrator::CDEIntegrator()
+{
+ meType = DtCDE;
+}
+
+CDEIntegrator::~CDEIntegrator()
+{
+}
+
+static int getHexDigit( const char c )
+{
+ if( c >= '0' && c <= '9' )
+ return (int)(c-'0');
+ else if( c >= 'a' && c <= 'f' )
+ return (int)(c-'a'+10);
+ else if( c >= 'A' && c <= 'F' )
+ return (int)(c-'A'+10);
+ return -1;
+}
+
+
+void CDEIntegrator::GetSystemLook( AllSettings& rSettings )
+{
+ static Color aColors[ 8 ];
+ static sal_Bool bRead = sal_False;
+ static sal_Bool bValid = sal_False;
+
+ if( ! bRead )
+ {
+ // get used palette from xrdb
+ char **ppStringList = 0;
+ int nStringCount;
+ XTextProperty aTextProperty;
+ aTextProperty.value = 0;
+
+ static Atom nResMgrAtom = XInternAtom( mpDisplay, "RESOURCE_MANAGER", False );
+
+ if( XGetTextProperty( mpDisplay,
+ RootWindow( mpDisplay, 0 ),
+ &aTextProperty,
+ nResMgrAtom )
+ && aTextProperty.value
+ && XTextPropertyToStringList( &aTextProperty, &ppStringList, &nStringCount )
+ )
+ {
+ // format of ColorPalette resource:
+ // *n*ColorPalette: palettefile
+
+ ByteString aLines;
+ int i;
+ for( i=0; i < nStringCount; i++ )
+ aLines += ppStringList[i];
+ for( i = aLines.GetTokenCount( '\n' )-1; i >= 0; i-- )
+ {
+ ByteString aLine = aLines.GetToken( i, '\n' );
+ int nIndex = aLine.Search( "ColorPalette" );
+ if( nIndex != STRING_NOTFOUND )
+ {
+ int nPos = nIndex;
+
+ nIndex+=12;
+ const char* pStr = aLine.GetBuffer() +nIndex;
+ while( *pStr && isspace( *pStr ) && *pStr != ':' )
+ {
+ pStr++;
+ nIndex++;
+ }
+ if( *pStr != ':' )
+ continue;
+ pStr++, nIndex++;
+ for( ; *pStr && isspace( *pStr ); pStr++, nIndex++ )
+ ;
+ if( ! *pStr )
+ continue;
+ int nIndex2 = nIndex;
+ for( ; *pStr && ! isspace( *pStr ); pStr++, nIndex2++ )
+ ;
+ ByteString aPaletteFile( aLine.Copy( nIndex, nIndex2 - nIndex ) );
+ // extract number before ColorPalette;
+ for( ; nPos >= 0 && aLine.GetChar( nPos ) != '*'; nPos-- )
+ ;
+ nPos--;
+ for( ; nPos >= 0 && aLine.GetChar( nPos ) != '*'; nPos-- )
+ ;
+ int nNumber = aLine.Copy( ++nPos ).ToInt32();
+
+ OSL_TRACE( "found palette %d in resource \"%s\"", nNumber, aLine.GetBuffer() );
+
+ // found no documentation what this number actually means;
+ // might be the screen number. 0 seems to be the right one
+ // in most cases.
+ if( nNumber )
+ continue;
+
+ OSL_TRACE( "Palette file is \"%s\".\n", aPaletteFile.GetBuffer() );
+
+ String aPath( aHomeDir );
+ aPath.AppendAscii( "/.dt/palettes/" );
+ aPath += String( aPaletteFile, gsl_getSystemTextEncoding() );
+
+ SvFileStream aStream( aPath, STREAM_READ );
+ if( ! aStream.IsOpen() )
+ {
+ aPath = String::CreateFromAscii( "/usr/dt/palettes/" );
+ aPath += String( aPaletteFile, gsl_getSystemTextEncoding() );
+ aStream.Open( aPath, STREAM_READ );
+ if( ! aStream.IsOpen() )
+ continue;
+ }
+
+ ByteString aBuffer;
+ for( nIndex = 0; nIndex < 8; nIndex++ )
+ {
+ aStream.ReadLine( aBuffer );
+ // format is "#RRRRGGGGBBBB"
+
+ OSL_TRACE( "\t\"%s\".\n", aBuffer.GetBuffer() );
+
+ if( aBuffer.Len() )
+ {
+ const char* pArr = (const char*)aBuffer.GetBuffer()+1;
+ aColors[nIndex] = Color(
+ getHexDigit( pArr[1] )
+ | ( getHexDigit( pArr[0] ) << 4 ),
+ getHexDigit( pArr[5] )
+ | ( getHexDigit( pArr[4] ) << 4 ),
+ getHexDigit( pArr[9] )
+ | ( getHexDigit( pArr[8] ) << 4 )
+ );
+
+ OSL_TRACE( "\t\t%lx\n", aColors[nIndex].GetColor() );
+ }
+ }
+
+ bValid = sal_True;
+ break;
+ }
+ }
+ }
+
+ if( ppStringList )
+ XFreeStringList( ppStringList );
+ if( aTextProperty.value )
+ XFree( aTextProperty.value );
+ }
+
+
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+ // #i48001# set a default blink rate
+ aStyleSettings.SetCursorBlinkTime( 500 );
+ if (bValid)
+ {
+ aStyleSettings.SetActiveColor( aColors[0] );
+ aStyleSettings.SetActiveColor2( aColors[0] );
+ aStyleSettings.SetActiveBorderColor( aColors[0] );
+
+ aStyleSettings.SetDeactiveColor( aColors[0] );
+ aStyleSettings.SetDeactiveColor2( aColors[0] );
+ aStyleSettings.SetDeactiveBorderColor( aColors[0] );
+
+ Color aActive =
+ aColors[ 0 ].GetBlue() < 128 ||
+ aColors[ 0 ].GetGreen() < 128 ||
+ aColors[ 0 ].GetRed() < 128
+ ? Color( COL_WHITE ) : Color( COL_BLACK );
+ Color aDeactive =
+ aColors[ 1 ].GetBlue() < 128 ||
+ aColors[ 1 ].GetGreen() < 128 ||
+ aColors[ 1 ].GetRed() < 128
+ ? Color( COL_WHITE ) : Color( COL_BLACK );
+ aStyleSettings.SetActiveTextColor( aActive );
+ aStyleSettings.SetDeactiveTextColor( aDeactive );
+
+ aStyleSettings.SetDialogTextColor( aDeactive );
+ aStyleSettings.SetMenuTextColor( aDeactive );
+ aStyleSettings.SetMenuBarTextColor( aDeactive );
+ aStyleSettings.SetButtonTextColor( aDeactive );
+ aStyleSettings.SetRadioCheckTextColor( aDeactive );
+ aStyleSettings.SetGroupTextColor( aDeactive );
+ aStyleSettings.SetLabelTextColor( aDeactive );
+ aStyleSettings.SetInfoTextColor( aDeactive );
+
+ aStyleSettings.Set3DColors( aColors[1] );
+ aStyleSettings.SetFaceColor( aColors[1] );
+ aStyleSettings.SetDialogColor( aColors[1] );
+ aStyleSettings.SetMenuColor( aColors[1] );
+ aStyleSettings.SetMenuBarColor( aColors[1] );
+ if ( aStyleSettings.GetFaceColor() == COL_LIGHTGRAY )
+ aStyleSettings.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
+ else
+ {
+ // calculate Checked color
+ Color aColor2 = aStyleSettings.GetLightColor();
+ sal_uInt8 nRed = (sal_uInt8)(((sal_uInt16)aColors[1].GetRed() + (sal_uInt16)aColor2.GetRed())/2);
+ sal_uInt8 nGreen = (sal_uInt8)(((sal_uInt16)aColors[1].GetGreen() + (sal_uInt16)aColor2.GetGreen())/2);
+ sal_uInt8 nBlue = (sal_uInt8)(((sal_uInt16)aColors[1].GetBlue() + (sal_uInt16)aColor2.GetBlue())/2);
+ aStyleSettings.SetCheckedColor( Color( nRed, nGreen, nBlue ) );
+ }
+ }
+ rSettings.SetStyleSettings( aStyleSettings );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/dtint.cxx b/vcl/unx/generic/gdi/dtint.cxx
new file mode 100644
index 000000000000..df1826df90f5
--- /dev/null
+++ b/vcl/unx/generic/gdi/dtint.cxx
@@ -0,0 +1,143 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+
+#include "osl/file.h"
+#include "osl/process.h"
+#include "osl/security.h"
+
+#include "vcl/svapp.hxx"
+
+#include "unx/salunx.h"
+#include <X11/Xatom.h>
+#ifdef USE_CDE
+#include "unx/cdeint.hxx"
+#endif
+#include "unx/dtint.hxx"
+#include "unx/saldisp.hxx"
+#include "unx/saldata.hxx"
+#include "unx/wmadaptor.hxx"
+
+#include "dtsetenum.hxx"
+
+#include <set>
+#include <stdio.h>
+
+// NETBSD has no RTLD_GLOBAL
+#ifndef RTLD_GLOBAL
+#define DLOPEN_MODE (RTLD_LAZY)
+#else
+#define DLOPEN_MODE (RTLD_GLOBAL | RTLD_LAZY)
+#endif
+
+
+using namespace vcl_sal;
+
+using ::rtl::OUString;
+
+String DtIntegrator::aHomeDir;
+
+DtIntegrator::DtIntegrator() :
+ meType( DtGeneric ),
+ mnSystemLookCommandProcess( -1 )
+{
+ mpSalDisplay = GetX11SalData()->GetDisplay();
+ mpDisplay = mpSalDisplay->GetDisplay();
+ OUString aDir;
+ oslSecurity aCur = osl_getCurrentSecurity();
+ if( aCur )
+ {
+ osl_getHomeDir( aCur, &aDir.pData );
+ osl_freeSecurityHandle( aCur );
+ OUString aSysDir;
+ osl_getSystemPathFromFileURL( aDir.pData, &aSysDir.pData );
+ aHomeDir = aSysDir;
+ }
+}
+
+DtIntegrator::~DtIntegrator()
+{
+}
+
+DtIntegrator* DtIntegrator::CreateDtIntegrator()
+{
+ /*
+ * #i22061# override desktop detection
+ * if environment variable OOO_FORCE_DESKTOP is set
+ * to one of "cde" "kde" "gnome" then autodetection
+ * is overridden.
+ */
+ static const char* pOverride = getenv( "OOO_FORCE_DESKTOP" );
+ if( pOverride && *pOverride )
+ {
+ OString aOver( pOverride );
+
+#if USE_CDE
+ if( aOver.equalsIgnoreAsciiCase( "cde" ) )
+ return new CDEIntegrator();
+#endif
+ if( aOver.equalsIgnoreAsciiCase( "none" ) )
+ return new DtIntegrator();
+ }
+
+#ifdef USE_CDE
+ void* pLibrary = NULL;
+
+ // check dt type
+ // CDE
+ SalDisplay* pSalDisplay = GetX11SalData()->GetDisplay();
+ Display* pDisplay = pSalDisplay->GetDisplay();
+ Atom nDtAtom = XInternAtom( pDisplay, "_DT_WM_READY", True );
+ if( nDtAtom && ( pLibrary = dlopen( "/usr/dt/lib/libDtSvc.so", DLOPEN_MODE ) ) )
+ {
+ dlclose( pLibrary );
+ return new CDEIntegrator();
+ }
+#endif
+
+ // default: generic implementation
+ return new DtIntegrator();
+}
+
+void DtIntegrator::GetSystemLook( AllSettings& rSettings )
+{
+ // #i48001# set a default blink rate
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+ aStyleSettings.SetCursorBlinkTime( 500 );
+ rSettings.SetStyleSettings( aStyleSettings );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/dtsetenum.hxx b/vcl/unx/generic/gdi/dtsetenum.hxx
new file mode 100644
index 000000000000..7973758d9f0d
--- /dev/null
+++ b/vcl/unx/generic/gdi/dtsetenum.hxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_DTSETENUM_HXX
+#define _VCL_DTSETENUM_HXX
+
+enum DtSetEnum
+{
+ /* settings for mouse */
+ MouseOptions = 1,
+ DoubleClickTime,
+ DoubleClickWidth,
+ DoubleClickHeight,
+ StartDragWidth,
+ StartDragHeight,
+ DragMoveCode,
+ DragCopyCode,
+ DragLinkCode,
+ ContextMenuCode,
+ ContextMenuClicks,
+ ContextMenuDown,
+ ScrollRepeat,
+ ButtonStartRepeat,
+ ButtonRepeat,
+ ActionDelay,
+ MenuDelay,
+ Follow,
+ MiddleButtonAction,
+ /* settings for keyboard */
+ KeyboardOptions=64,
+ /* style settings */
+ StyleOptions = 128,
+ BorderSize,
+ TitleHeight,
+ FloatTitleHeight,
+ TearOffTitleHeight,
+ MenuBarHeight,
+ ScrollBarSize,
+ SpinSize,
+ SplitSize,
+ IconHorzSpace,
+ IconVertSpace,
+ CursorSize,
+ CursorBlinkTime,
+ ScreenZoom,
+ ScreenFontZoom,
+ LogoDisplayTime,
+ DragFullOptions,
+ AnimationOptions,
+ SelectionOptions,
+ DisplayOptions,
+ AntialiasingMinPixelHeight,
+ /* style colors */
+ AllTextColors, /* convenience, sets all control text colors */
+ AllBackColors, /* convenience, sets all control background colors */
+ ThreeDColor,
+ FaceColor,
+ CheckedColor,
+ LightColor,
+ LightBorderColor,
+ ShadowColor,
+ DarkShadowColor,
+ ButtonTextColor,
+ RadioCheckTextColor,
+ GroupTextColor,
+ LabelTextColor,
+ InfoTextColor,
+ WindowColor,
+ WindowTextColor,
+ DialogColor,
+ DialogTextColor,
+ WorkspaceColor,
+ FieldColor,
+ FieldTextColor,
+ ActiveColor,
+ ActiveColor2,
+ ActiveTextColor,
+ ActiveBorderColor,
+ DeactiveColor,
+ DeactiveColor2,
+ DeactiveTextColor,
+ DeactiveBorderColor,
+ HighlightColor,
+ HighlightTextColor,
+ DisableColor,
+ HelpColor,
+ HelpTextColor,
+ MenuColor,
+ MenuBarColor,
+ MenuTextColor,
+ MenuHighlightColor,
+ MenuHighlightTextColor,
+ LinkColor,
+ VisitedLinkColor,
+ HighlightLinkColor,
+ HighContrastMode,
+ /* style fonts */
+ UIFont, /* convenience, sets all fonts but TitleFont and FloatTitleFont */
+ AppFont,
+ HelpFont,
+ TitleFont,
+ FloatTitleFont,
+ MenuFont,
+ ToolFont,
+ GroupFont,
+ LabelFont,
+ InfoFont,
+ RadioCheckFont,
+ PushButtonFont,
+ FieldFont,
+ IconFont,
+ /* style numeric styles */
+ RadioButtonStyle,
+ CheckBoxStyle,
+ PushButtonStyle,
+ TabControlStyle,
+ /* toolbar style */
+ ToolbarIconSize
+
+};
+
+#endif // _VCL_DTSETENUM_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/gcach_xpeer.cxx b/vcl/unx/generic/gdi/gcach_xpeer.cxx
new file mode 100644
index 000000000000..9da147dbec9c
--- /dev/null
+++ b/vcl/unx/generic/gdi/gcach_xpeer.cxx
@@ -0,0 +1,685 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 "rtl/ustring.hxx"
+#include "osl/module.h"
+#include "osl/thread.h"
+
+#include "unx/saldisp.hxx"
+#include "unx/saldata.hxx"
+#include "unx/salgdi.h"
+
+#include "gcach_xpeer.hxx"
+#include "xrender_peer.hxx"
+
+// ===========================================================================
+
+// all glyph specific data needed by the XGlyphPeer is quite trivial
+// with one exception: if multiple screens are involved and non-antialiased
+// glyph rendering is active, then we need screen specific pixmaps
+struct MultiScreenGlyph
+{
+ const RawBitmap* mpRawBitmap;
+ Glyph maXRGlyphId;
+ Pixmap maPixmaps[1]; // [mnMaxScreens]
+};
+
+// ===========================================================================
+
+X11GlyphPeer::X11GlyphPeer()
+: mpDisplay( GetX11SalData()->GetDisplay()->GetDisplay() )
+, mnMaxScreens(0)
+, mnDefaultScreen(0)
+, mnExtByteCount(0)
+, mnForcedAA(0)
+, mnUsingXRender(0)
+{
+ maRawBitmap.mnAllocated = 0;
+ maRawBitmap.mpBits = NULL;
+ if( !mpDisplay )
+ return;
+
+ SalDisplay& rSalDisplay = *GetX11SalData()->GetDisplay();
+ mpDisplay = rSalDisplay.GetDisplay();
+ mnMaxScreens = rSalDisplay.GetScreenCount();
+ if( mnMaxScreens > MAX_GCACH_SCREENS )
+ mnMaxScreens = MAX_GCACH_SCREENS;
+ // if specific glyph data has to be kept for many screens
+ // then prepare the allocation of MultiScreenGlyph objects
+ if( mnMaxScreens > 1 )
+ mnExtByteCount = sizeof(MultiScreenGlyph) + sizeof(Pixmap) * (mnMaxScreens - 1);
+ mnDefaultScreen = rSalDisplay.GetDefaultScreenNumber();
+
+ InitAntialiasing();
+}
+
+// ---------------------------------------------------------------------------
+
+X11GlyphPeer::~X11GlyphPeer()
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ Display* const pX11Disp = pSalDisp->GetDisplay();
+ XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
+ for( int i = 0; i < mnMaxScreens; i++ )
+ {
+ SalDisplay::RenderEntryMap& rMap = pSalDisp->GetRenderEntries( i );
+ for( SalDisplay::RenderEntryMap::iterator it = rMap.begin(); it != rMap.end(); ++it )
+ {
+ if( it->second.m_aPixmap )
+ ::XFreePixmap( pX11Disp, it->second.m_aPixmap );
+ if( it->second.m_aPicture )
+ rRenderPeer.FreePicture( it->second.m_aPicture );
+ }
+ rMap.clear();
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::InitAntialiasing()
+{
+ int nEnvAntiAlias = 0;
+ const char* pEnvAntiAlias = getenv( "SAL_ANTIALIAS_DISABLE" );
+ if( pEnvAntiAlias )
+ {
+ nEnvAntiAlias = atoi( pEnvAntiAlias );
+ if( nEnvAntiAlias == 0 )
+ return;
+ }
+
+ mnUsingXRender = 0;
+ mnForcedAA = 0;
+
+ // enable XRENDER accelerated aliasing on screens that support it
+ // unless it explicitly disabled by an environment variable
+ if( (nEnvAntiAlias & 2) == 0 )
+ mnUsingXRender = XRenderPeer::GetInstance().InitRenderText();
+
+ // else enable client side antialiasing for these screens
+ // unless it is explicitly disabled by an environment variable
+ if( (nEnvAntiAlias & 1) != 0 )
+ return;
+
+ // enable client side antialiasing for screen visuals that are suitable
+ // mnForcedAA is a bitmask of screens enabled for client side antialiasing
+ mnForcedAA = (~(~0U << mnMaxScreens)) ^ mnUsingXRender;
+ SalDisplay& rSalDisplay = *GetX11SalData()->GetDisplay();
+ for( int nScreen = 0; nScreen < mnMaxScreens; ++nScreen)
+ {
+ Visual* pVisual = rSalDisplay.GetVisual( nScreen ).GetVisual();
+ XVisualInfo aXVisualInfo;
+ aXVisualInfo.visualid = pVisual->visualid;
+ int nVisuals = 0;
+ XVisualInfo* pXVisualInfo = XGetVisualInfo( mpDisplay, VisualIDMask, &aXVisualInfo, &nVisuals );
+ for( int i = nVisuals; --i >= 0; )
+ {
+ if( ((pXVisualInfo[i].c_class==PseudoColor) || (pXVisualInfo[i].depth<24))
+ && ((pXVisualInfo[i].c_class>GrayScale) || (pXVisualInfo[i].depth!=8) ) )
+ mnForcedAA &= ~(1U << nScreen);
+ }
+ if( pXVisualInfo != NULL )
+ XFree( pXVisualInfo );
+ }
+}
+
+// ===========================================================================
+
+enum { INFO_EMPTY=0, INFO_PIXMAP, INFO_XRENDER, INFO_RAWBMP, INFO_MULTISCREEN };
+static const Glyph NO_GLYPHID = 0;
+static RawBitmap* const NO_RAWBMP = NULL;
+static const Pixmap NO_PIXMAP = ~0;
+
+// ---------------------------------------------------------------------------
+
+MultiScreenGlyph* X11GlyphPeer::PrepareForMultiscreen( ExtGlyphData& rEGD ) const
+{
+ // prepare to store screen specific pixmaps
+ MultiScreenGlyph* pMSGlyph = (MultiScreenGlyph*)new char[ mnExtByteCount ];
+
+ // init the glyph formats
+ pMSGlyph->mpRawBitmap = NO_RAWBMP;
+ pMSGlyph->maXRGlyphId = NO_GLYPHID;
+ for( int i = 0; i < mnMaxScreens; ++i )
+ pMSGlyph->maPixmaps[i] = NO_PIXMAP;
+ // reuse already available glyph formats
+ if( rEGD.meInfo == INFO_XRENDER )
+ pMSGlyph->maXRGlyphId = reinterpret_cast<Glyph>(rEGD.mpData);
+ else if( rEGD.meInfo == INFO_RAWBMP )
+ pMSGlyph->mpRawBitmap = reinterpret_cast<RawBitmap*>(rEGD.mpData);
+ else if( rEGD.meInfo == INFO_PIXMAP )
+ {
+ Pixmap aPixmap = reinterpret_cast<Pixmap>(rEGD.mpData);
+ if( aPixmap != None )
+ // pixmap for the default screen is available
+ pMSGlyph->maPixmaps[ mnDefaultScreen ] = aPixmap;
+ else // empty pixmap for all screens is available
+ for( int i = 0; i < mnMaxScreens; ++i )
+ pMSGlyph->maPixmaps[ i ] = None;
+ }
+ // enable use of multiscreen glyph
+ rEGD.mpData = (void*)pMSGlyph;
+ rEGD.meInfo = INFO_MULTISCREEN;
+
+ return pMSGlyph;
+ }
+
+// ---------------------------------------------------------------------------
+
+Glyph X11GlyphPeer::GetRenderGlyph( const GlyphData& rGD ) const
+{
+ Glyph aGlyphId = NO_GLYPHID;
+ const ExtGlyphData& rEGD = rGD.ExtDataRef();
+ if( rEGD.meInfo == INFO_XRENDER )
+ aGlyphId = reinterpret_cast<Glyph>(rEGD.mpData);
+ else if( rEGD.meInfo == INFO_MULTISCREEN )
+ aGlyphId = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maXRGlyphId;
+ return aGlyphId;
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::SetRenderGlyph( GlyphData& rGD, Glyph aGlyphId ) const
+{
+ ExtGlyphData& rEGD = rGD.ExtDataRef();
+ switch( rEGD.meInfo )
+ {
+ case INFO_EMPTY:
+ rEGD.meInfo = INFO_XRENDER;
+ // fall through
+ case INFO_XRENDER:
+ rEGD.mpData = reinterpret_cast<void*>(aGlyphId);
+ break;
+ case INFO_PIXMAP:
+ case INFO_RAWBMP:
+ PrepareForMultiscreen( rEGD );
+ // fall through
+ case INFO_MULTISCREEN:
+ reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maXRGlyphId = aGlyphId;
+ break;
+ default:
+ break; // cannot happen...
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+const RawBitmap* X11GlyphPeer::GetRawBitmap( const GlyphData& rGD ) const
+{
+ const RawBitmap* pRawBitmap = NO_RAWBMP;
+ const ExtGlyphData& rEGD = rGD.ExtDataRef();
+ if( rEGD.meInfo == INFO_RAWBMP )
+ pRawBitmap = reinterpret_cast<RawBitmap*>(rEGD.mpData);
+ else if( rEGD.meInfo == INFO_MULTISCREEN )
+ pRawBitmap = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->mpRawBitmap;
+ return pRawBitmap;
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::SetRawBitmap( GlyphData& rGD, const RawBitmap* pRawBitmap ) const
+{
+ ExtGlyphData& rEGD = rGD.ExtDataRef();
+ switch( rEGD.meInfo )
+ {
+ case INFO_EMPTY:
+ rEGD.meInfo = INFO_RAWBMP;
+ // fall through
+ case INFO_RAWBMP:
+ rEGD.mpData = (void*)pRawBitmap;
+ break;
+ case INFO_PIXMAP:
+ case INFO_XRENDER:
+ PrepareForMultiscreen( rEGD );
+ // fall through
+ case INFO_MULTISCREEN:
+ reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->mpRawBitmap = pRawBitmap;
+ break;
+ default:
+ // cannot happen...
+ break;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+Pixmap X11GlyphPeer::GetPixmap( const GlyphData& rGD, int nScreen ) const
+{
+ Pixmap aPixmap = NO_PIXMAP;
+ const ExtGlyphData& rEGD = rGD.ExtDataRef();
+ if( (rEGD.meInfo == INFO_PIXMAP) && (nScreen == mnDefaultScreen) )
+ aPixmap = (Pixmap)rEGD.mpData;
+ else if( rEGD.meInfo == INFO_MULTISCREEN )
+ aPixmap = (Pixmap)(reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maPixmaps[nScreen]);
+ return aPixmap;
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::SetPixmap( GlyphData& rGD, Pixmap aPixmap, int nScreen ) const
+{
+ if( aPixmap == NO_PIXMAP )
+ aPixmap = None;
+
+ ExtGlyphData& rEGD = rGD.ExtDataRef();
+ if( (rEGD.meInfo == INFO_EMPTY) && (nScreen == mnDefaultScreen) )
+ {
+ rEGD.meInfo = INFO_PIXMAP;
+ rEGD.mpData = (void*)aPixmap;
+ }
+ else
+ {
+ MultiScreenGlyph* pMSGlyph;
+ if( rEGD.meInfo == INFO_MULTISCREEN )
+ pMSGlyph = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData);
+ else
+ pMSGlyph = PrepareForMultiscreen( rEGD );
+
+ pMSGlyph->maPixmaps[ nScreen ] = aPixmap;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::RemovingFont( ServerFont& rServerFont )
+{
+ void* pFontExt = rServerFont.GetExtPointer();
+ switch( rServerFont.GetExtInfo() )
+ {
+ case INFO_PIXMAP:
+ case INFO_RAWBMP:
+ // nothing to do
+ break;
+ case INFO_MULTISCREEN:
+ // cannot happen...
+ break;
+
+ case INFO_XRENDER:
+ XRenderPeer::GetInstance().FreeGlyphSet( (GlyphSet)pFontExt );
+ break;
+ }
+
+ rServerFont.SetExtended( INFO_EMPTY, NULL );
+}
+
+// ---------------------------------------------------------------------------
+
+// notification to clean up GlyphPeer resources for this glyph
+void X11GlyphPeer::RemovingGlyph( ServerFont& /*rServerFont*/, GlyphData& rGlyphData, int /*nGlyphIndex*/ )
+{
+ // nothing to do if the GlyphPeer hasn't allocated resources for the glyph
+ if( rGlyphData.ExtDataRef().meInfo == INFO_EMPTY )
+ return;
+
+ const GlyphMetric& rGM = rGlyphData.GetMetric();
+ const int nWidth = rGM.GetSize().Width();
+ const int nHeight = rGM.GetSize().Height();
+
+ void* pGlyphExt = rGlyphData.ExtDataRef().mpData;
+ switch( rGlyphData.ExtDataRef().meInfo )
+ {
+ case INFO_PIXMAP:
+ {
+ Pixmap aPixmap = (Pixmap)pGlyphExt;
+ if( aPixmap != None )
+ {
+ XFreePixmap( mpDisplay, aPixmap );
+ mnBytesUsed -= nHeight * ((nWidth + 7) >> 3);
+ }
+ }
+ break;
+
+ case INFO_MULTISCREEN:
+ {
+ MultiScreenGlyph* pMSGlyph = reinterpret_cast<MultiScreenGlyph*>(pGlyphExt);
+ for( int i = 0; i < mnMaxScreens; ++i)
+ {
+ if( pMSGlyph->maPixmaps[i] == NO_PIXMAP )
+ continue;
+ if( pMSGlyph->maPixmaps[i] == None )
+ continue;
+ XFreePixmap( mpDisplay, pMSGlyph->maPixmaps[i] );
+ mnBytesUsed -= nHeight * ((nWidth + 7) >> 3);
+ }
+ delete pMSGlyph->mpRawBitmap;
+ // Glyph nGlyphId = (Glyph)rGlyphData.GetExtPointer();
+ // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nGlyphId );
+ delete[] pMSGlyph; // it was allocated with new char[]
+ }
+ break;
+
+ case INFO_RAWBMP:
+ {
+ RawBitmap* pRawBitmap = (RawBitmap*)pGlyphExt;
+ if( pRawBitmap != NULL )
+ {
+ mnBytesUsed -= pRawBitmap->mnScanlineSize * pRawBitmap->mnHeight;
+ mnBytesUsed -= sizeof(RawBitmap);
+ delete pRawBitmap;
+ }
+ }
+ break;
+
+ case INFO_XRENDER:
+ {
+ // Glyph nGlyphId = (Glyph)rGlyphData.GetExtPointer();
+ // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nGlyphId );
+ mnBytesUsed -= nHeight * ((nWidth + 3) & ~3);
+ }
+ break;
+ }
+
+ if( mnBytesUsed < 0 ) // TODO: eliminate nBytesUsed calc mismatch
+ mnBytesUsed = 0;
+
+ rGlyphData.ExtDataRef() = ExtGlyphData();
+}
+
+// ---------------------------------------------------------------------------
+
+bool X11GlyphPeer::ForcedAntialiasing( const ServerFont& rServerFont, int nScreen ) const
+{
+ bool bForceOk = rServerFont.GetAntialiasAdvice();
+ // maximum size for antialiasing is 250 pixels
+ bForceOk &= (rServerFont.GetFontSelData().mnHeight < 250);
+ return (bForceOk && ((mnForcedAA >> nScreen) & 1));
+}
+
+// ---------------------------------------------------------------------------
+
+GlyphSet X11GlyphPeer::GetGlyphSet( ServerFont& rServerFont, int nScreen )
+{
+ if( (nScreen >= 0) && ((mnUsingXRender >> nScreen) & 1) == 0 )
+ return 0;
+
+ GlyphSet aGlyphSet;
+
+ switch( rServerFont.GetExtInfo() )
+ {
+ case INFO_XRENDER:
+ aGlyphSet = (GlyphSet)rServerFont.GetExtPointer();
+ break;
+
+ case INFO_EMPTY:
+ {
+ // antialiasing for reasonable font heights only
+ // => prevents crashes caused by X11 requests >= 256k
+ // => prefer readablity of hinted glyphs at small sizes
+ // => prefer "grey clouds" to "black clouds" at very small sizes
+ int nHeight = rServerFont.GetFontSelData().mnHeight;
+ if( nHeight<250 && rServerFont.GetAntialiasAdvice() )
+ {
+ aGlyphSet = XRenderPeer::GetInstance().CreateGlyphSet();
+ rServerFont.SetExtended( INFO_XRENDER, (void*)aGlyphSet );
+ }
+ else
+ aGlyphSet = 0;
+ }
+ break;
+
+ default:
+ aGlyphSet = 0;
+ break;
+ }
+
+ return aGlyphSet;
+}
+
+// ---------------------------------------------------------------------------
+
+Pixmap X11GlyphPeer::GetPixmap( ServerFont& rServerFont, int nGlyphIndex, int nReqScreen )
+{
+ if( rServerFont.IsGlyphInvisible( nGlyphIndex ) )
+ return None;
+
+ GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
+ Pixmap aPixmap = GetPixmap( rGlyphData, nReqScreen );
+ if( aPixmap == NO_PIXMAP )
+ {
+ aPixmap = None;
+ if( rServerFont.GetGlyphBitmap1( nGlyphIndex, maRawBitmap ) )
+ {
+ // #94666# circumvent bug in some X11 systems, e.g. XF410.LynxEM.v163
+ sal_uLong nPixmapWidth = 8 * maRawBitmap.mnScanlineSize - 1;
+ nPixmapWidth = Max( nPixmapWidth, maRawBitmap.mnWidth );
+
+ rGlyphData.SetSize( Size( nPixmapWidth, maRawBitmap.mnHeight ) );
+ rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset );
+
+ const sal_uLong nBytes = maRawBitmap.mnHeight * maRawBitmap.mnScanlineSize;
+ if( nBytes > 0 )
+ {
+ // conversion table LSB<->MSB (for XCreatePixmapFromData)
+ static const unsigned char lsb2msb[256] =
+ {
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+ };
+
+ unsigned char* pTemp = maRawBitmap.mpBits;
+ for( int i = nBytes; --i >= 0; ++pTemp )
+ *pTemp = lsb2msb[ *pTemp ];
+
+ // often a glyph pixmap is only needed on the default screen
+ // => optimize for this common case
+ int nMinScreen = 0;
+ int nEndScreen = mnMaxScreens;
+ if( nReqScreen == mnDefaultScreen ) {
+ nMinScreen = mnDefaultScreen;
+ nEndScreen = mnDefaultScreen + 1;
+ }
+ // prepare glyph pixmaps for the different screens
+ for( int i = nMinScreen; i < nEndScreen; ++i )
+ {
+ // don't bother if the pixmap is already there
+ if( GetPixmap( rGlyphData, i ) != NO_PIXMAP )
+ continue;
+ // create the glyph pixmap
+ Pixmap aScreenPixmap = XCreatePixmapFromBitmapData( mpDisplay,
+ RootWindow( mpDisplay, i ), (char*)maRawBitmap.mpBits,
+ nPixmapWidth, maRawBitmap.mnHeight, 1, 0, 1 );
+ // and cache it as glyph specific data
+ SetPixmap( rGlyphData, aScreenPixmap, i );
+ mnBytesUsed += nBytes;
+ if( i == nReqScreen )
+ aPixmap = aScreenPixmap;
+ }
+ }
+ }
+ else
+ {
+ // fall back to .notdef glyph
+ if( nGlyphIndex != 0 ) // recurse only once
+ aPixmap = GetPixmap( rServerFont, 0, nReqScreen );
+
+ if( aPixmap == NO_PIXMAP )
+ aPixmap = None;
+ }
+ }
+
+ return aPixmap;
+}
+
+// ---------------------------------------------------------------------------
+
+const RawBitmap* X11GlyphPeer::GetRawBitmap( ServerFont& rServerFont,
+ int nGlyphIndex )
+{
+ if( rServerFont.IsGlyphInvisible( nGlyphIndex ) )
+ return NO_RAWBMP;
+
+ GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
+
+ const RawBitmap* pRawBitmap = GetRawBitmap( rGlyphData );
+ if( pRawBitmap == NO_RAWBMP )
+ {
+ RawBitmap* pNewBitmap = new RawBitmap;
+ if( rServerFont.GetGlyphBitmap8( nGlyphIndex, *pNewBitmap ) )
+ {
+ pRawBitmap = pNewBitmap;
+ mnBytesUsed += pNewBitmap->mnScanlineSize * pNewBitmap->mnHeight;
+ mnBytesUsed += sizeof(pNewBitmap);
+ }
+ else
+ {
+ delete pNewBitmap;
+ // fall back to .notdef glyph
+ if( nGlyphIndex != 0 ) // recurse only once
+ pRawBitmap = GetRawBitmap( rServerFont, 0 );
+ }
+
+ SetRawBitmap( rGlyphData, pRawBitmap );
+ }
+
+ return pRawBitmap;
+}
+
+// ---------------------------------------------------------------------------
+
+Glyph X11GlyphPeer::GetGlyphId( ServerFont& rServerFont, int nGlyphIndex )
+{
+ if( rServerFont.IsGlyphInvisible( nGlyphIndex ) )
+ return NO_GLYPHID;
+
+ GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
+
+ Glyph aGlyphId = GetRenderGlyph( rGlyphData );
+ if( aGlyphId == NO_GLYPHID )
+ {
+ // prepare GlyphInfo and Bitmap
+ if( rServerFont.GetGlyphBitmap8( nGlyphIndex, maRawBitmap ) )
+ {
+ XGlyphInfo aGlyphInfo;
+ aGlyphInfo.width = maRawBitmap.mnWidth;
+ aGlyphInfo.height = maRawBitmap.mnHeight;
+ aGlyphInfo.x = -maRawBitmap.mnXOffset;
+ aGlyphInfo.y = -maRawBitmap.mnYOffset;
+
+ rGlyphData.SetSize( Size( maRawBitmap.mnWidth, maRawBitmap.mnHeight ) );
+ rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset );
+
+ const GlyphMetric& rGM = rGlyphData.GetMetric();
+ aGlyphInfo.xOff = +rGM.GetDelta().X();
+ aGlyphInfo.yOff = +rGM.GetDelta().Y();
+
+ // upload glyph bitmap to server
+ GlyphSet aGlyphSet = GetGlyphSet( rServerFont, -1 );
+
+ aGlyphId = nGlyphIndex & 0x00FFFFFF;
+ const sal_uLong nBytes = maRawBitmap.mnScanlineSize * maRawBitmap.mnHeight;
+ XRenderPeer::GetInstance().AddGlyph( aGlyphSet, aGlyphId,
+ aGlyphInfo, (char*)maRawBitmap.mpBits, nBytes );
+ mnBytesUsed += nBytes;
+ }
+ else
+ {
+ // fall back to .notdef glyph
+ if( nGlyphIndex != 0 ) // recurse only once
+ aGlyphId = GetGlyphId( rServerFont, 0 );
+ }
+
+ SetRenderGlyph( rGlyphData, aGlyphId );
+ }
+
+ return aGlyphId;
+}
+
+// ===========================================================================
+
+X11GlyphCache::X11GlyphCache( X11GlyphPeer& rPeer )
+: GlyphCache( rPeer )
+{
+}
+
+// ---------------------------------------------------------------------------
+
+static X11GlyphPeer* pX11GlyphPeer = NULL;
+static X11GlyphCache* pX11GlyphCache = NULL;
+
+X11GlyphCache& X11GlyphCache::GetInstance()
+{
+ if( !pX11GlyphCache )
+ {
+ pX11GlyphPeer = new X11GlyphPeer();
+ pX11GlyphCache = new X11GlyphCache( *pX11GlyphPeer );
+ }
+ return *pX11GlyphCache;
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphCache::KillInstance()
+{
+ delete pX11GlyphCache;
+ delete pX11GlyphPeer;
+ pX11GlyphCache = NULL;
+ pX11GlyphPeer = NULL;
+}
+
+// ===========================================================================
+
+void X11SalGraphics::releaseGlyphPeer()
+{
+ X11GlyphCache::KillInstance();
+}
+
+// ===========================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/gcach_xpeer.hxx b/vcl/unx/generic/gdi/gcach_xpeer.hxx
new file mode 100644
index 000000000000..412c47f82de2
--- /dev/null
+++ b/vcl/unx/generic/gdi/gcach_xpeer.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_GCACH_XPEER_HXX
+#define _SV_GCACH_XPEER_HXX
+
+#include <tools/prex.h>
+#include <X11/extensions/Xrender.h>
+#include <tools/postx.h>
+
+#include <glyphcache.hxx>
+
+class SalDisplay;
+struct MultiScreenGlyph;
+
+class X11GlyphPeer
+: public GlyphCachePeer
+{
+public:
+ X11GlyphPeer();
+ virtual ~X11GlyphPeer();
+
+ Pixmap GetPixmap( ServerFont&, int nGlyphIndex, int nScreen );
+ const RawBitmap* GetRawBitmap( ServerFont&, int nGlyphIndex );
+ bool ForcedAntialiasing( const ServerFont&, int nScreen ) const;
+
+ GlyphSet GetGlyphSet( ServerFont&, int nScreen );
+ Glyph GetGlyphId( ServerFont&, int nGlyphIndex );
+
+protected:
+ void InitAntialiasing();
+
+ virtual void RemovingFont( ServerFont& );
+ virtual void RemovingGlyph( ServerFont&, GlyphData&, int nGlyphIndex );
+
+ MultiScreenGlyph* PrepareForMultiscreen( ExtGlyphData& ) const;
+ void SetRenderGlyph( GlyphData&, Glyph ) const;
+ void SetRawBitmap( GlyphData&, const RawBitmap* ) const;
+ void SetPixmap( GlyphData&, Pixmap, int nScreen ) const;
+ Glyph GetRenderGlyph( const GlyphData& ) const;
+ const RawBitmap* GetRawBitmap( const GlyphData& ) const;
+ Pixmap GetPixmap( const GlyphData&, int nScreen ) const;
+
+private:
+ Display* mpDisplay;
+
+ // thirty-two screens should be enough for everyone...
+ static const int MAX_GCACH_SCREENS = 32;
+ int mnMaxScreens;
+ int mnDefaultScreen;
+ int mnExtByteCount;
+ RawBitmap maRawBitmap;
+ sal_uInt32 mnForcedAA;
+ sal_uInt32 mnUsingXRender;
+};
+
+class X11GlyphCache : public GlyphCache
+{
+public:
+ X11GlyphPeer& GetPeer() { return reinterpret_cast<X11GlyphPeer&>( mrPeer ); }
+static X11GlyphCache& GetInstance();
+static void KillInstance();
+
+private:
+ X11GlyphCache( X11GlyphPeer& );
+};
+
+#endif // _SV_GCACH_XPEER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/pspgraphics.cxx b/vcl/unx/generic/gdi/pspgraphics.cxx
new file mode 100644
index 000000000000..65c4c0ab41da
--- /dev/null
+++ b/vcl/unx/generic/gdi/pspgraphics.cxx
@@ -0,0 +1,1504 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "unx/pspgraphics.h"
+
+#include "vcl/jobdata.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/bmpacc.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/sysdata.hxx"
+
+#include "printergfx.hxx"
+#include "salbmp.hxx"
+#include "glyphcache.hxx"
+#include "impfont.hxx"
+#include "outfont.hxx"
+#include "fontsubset.hxx"
+#include "salprn.hxx"
+#include "region.h"
+
+#ifdef ENABLE_GRAPHITE
+#include <graphite_layout.hxx>
+#include <graphite_serverfont.hxx>
+#endif
+
+using namespace psp;
+
+using ::rtl::OUString;
+using ::rtl::OString;
+
+// ----- Implementation of PrinterBmp by means of SalBitmap/BitmapBuffer ---------------
+
+class SalPrinterBmp : public psp::PrinterBmp
+{
+ private:
+ BitmapBuffer* mpBmpBuffer;
+
+ FncGetPixel mpFncGetPixel;
+ Scanline mpScanAccess;
+ sal_PtrDiff mnScanOffset;
+
+ sal_uInt32 ColorOf (BitmapColor& rColor) const;
+ sal_uInt8 GrayOf (BitmapColor& rColor) const;
+
+ SalPrinterBmp ();
+
+ public:
+
+ SalPrinterBmp (BitmapBuffer* pBitmap);
+ virtual ~SalPrinterBmp ();
+ virtual sal_uInt32 GetPaletteColor (sal_uInt32 nIdx) const;
+ virtual sal_uInt32 GetPaletteEntryCount () const;
+ virtual sal_uInt32 GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const;
+ virtual sal_uInt8 GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const;
+ virtual sal_uInt8 GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const;
+ virtual sal_uInt32 GetWidth () const;
+ virtual sal_uInt32 GetHeight() const;
+ virtual sal_uInt32 GetDepth () const;
+};
+
+SalPrinterBmp::SalPrinterBmp (BitmapBuffer* pBuffer) :
+ mpBmpBuffer (pBuffer)
+{
+ DBG_ASSERT (mpBmpBuffer, "SalPrinterBmp::SalPrinterBmp () can't acquire Bitmap");
+
+ // calibrate scanline buffer
+ if( BMP_SCANLINE_ADJUSTMENT( mpBmpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ {
+ mpScanAccess = mpBmpBuffer->mpBits;
+ mnScanOffset = mpBmpBuffer->mnScanlineSize;
+ }
+ else
+ {
+ mpScanAccess = mpBmpBuffer->mpBits
+ + (mpBmpBuffer->mnHeight - 1) * mpBmpBuffer->mnScanlineSize;
+ mnScanOffset = - mpBmpBuffer->mnScanlineSize;
+ }
+
+ // request read access to the pixels
+ switch( BMP_SCANLINE_FORMAT( mpBmpBuffer->mnFormat ) )
+ {
+ case BMP_FORMAT_1BIT_MSB_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_1BIT_MSB_PAL; break;
+ case BMP_FORMAT_1BIT_LSB_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_1BIT_LSB_PAL; break;
+ case BMP_FORMAT_4BIT_MSN_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_4BIT_MSN_PAL; break;
+ case BMP_FORMAT_4BIT_LSN_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_4BIT_LSN_PAL; break;
+ case BMP_FORMAT_8BIT_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_8BIT_PAL; break;
+ case BMP_FORMAT_8BIT_TC_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_8BIT_TC_MASK; break;
+ case BMP_FORMAT_16BIT_TC_MSB_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_16BIT_TC_MSB_MASK; break;
+ case BMP_FORMAT_16BIT_TC_LSB_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_16BIT_TC_LSB_MASK; break;
+ case BMP_FORMAT_24BIT_TC_BGR:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_24BIT_TC_BGR; break;
+ case BMP_FORMAT_24BIT_TC_RGB:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_24BIT_TC_RGB; break;
+ case BMP_FORMAT_24BIT_TC_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_24BIT_TC_MASK; break;
+ case BMP_FORMAT_32BIT_TC_ABGR:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_ABGR; break;
+ case BMP_FORMAT_32BIT_TC_ARGB:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_ARGB; break;
+ case BMP_FORMAT_32BIT_TC_BGRA:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_BGRA; break;
+ case BMP_FORMAT_32BIT_TC_RGBA:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_RGBA; break;
+ case BMP_FORMAT_32BIT_TC_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_MASK; break;
+
+ default:
+ OSL_FAIL("Error: SalPrinterBmp::SalPrinterBmp() unknown bitmap format");
+ break;
+ }
+}
+
+SalPrinterBmp::~SalPrinterBmp ()
+{
+}
+
+sal_uInt32
+SalPrinterBmp::GetWidth () const
+{
+ return mpBmpBuffer->mnWidth;
+}
+
+sal_uInt32
+SalPrinterBmp::GetHeight () const
+{
+ return mpBmpBuffer->mnHeight;
+}
+
+sal_uInt32
+SalPrinterBmp::GetDepth () const
+{
+ sal_uInt32 nDepth;
+
+ switch (mpBmpBuffer->mnBitCount)
+ {
+ case 1:
+ nDepth = 1;
+ break;
+
+ case 4:
+ case 8:
+ nDepth = 8;
+ break;
+
+ case 16:
+ case 24:
+ case 32:
+ nDepth = 24;
+ break;
+
+ default:
+ nDepth = 1;
+ OSL_FAIL("Error: unsupported bitmap depth in SalPrinterBmp::GetDepth()");
+ break;
+ }
+
+ return nDepth;
+}
+
+sal_uInt32
+SalPrinterBmp::ColorOf (BitmapColor& rColor) const
+{
+ if (rColor.IsIndex())
+ return ColorOf (mpBmpBuffer->maPalette[rColor.GetIndex()]);
+ else
+ return ((rColor.GetBlue()) & 0x000000ff)
+ | ((rColor.GetGreen() << 8) & 0x0000ff00)
+ | ((rColor.GetRed() << 16) & 0x00ff0000);
+}
+
+sal_uInt8
+SalPrinterBmp::GrayOf (BitmapColor& rColor) const
+{
+ if (rColor.IsIndex())
+ return GrayOf (mpBmpBuffer->maPalette[rColor.GetIndex()]);
+ else
+ return ( rColor.GetBlue() * 28UL
+ + rColor.GetGreen() * 151UL
+ + rColor.GetRed() * 77UL ) >> 8;
+}
+
+sal_uInt32
+SalPrinterBmp::GetPaletteEntryCount () const
+{
+ return mpBmpBuffer->maPalette.GetEntryCount ();
+}
+
+sal_uInt32
+SalPrinterBmp::GetPaletteColor (sal_uInt32 nIdx) const
+{
+ return ColorOf (mpBmpBuffer->maPalette[nIdx]);
+}
+
+sal_uInt32
+SalPrinterBmp::GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const
+{
+ Scanline pScan = mpScanAccess + nRow * mnScanOffset;
+ BitmapColor aColor = mpFncGetPixel (pScan, nColumn, mpBmpBuffer->maColorMask);
+
+ return ColorOf (aColor);
+}
+
+sal_uInt8
+SalPrinterBmp::GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const
+{
+ Scanline pScan = mpScanAccess + nRow * mnScanOffset;
+ BitmapColor aColor = mpFncGetPixel (pScan, nColumn, mpBmpBuffer->maColorMask);
+
+ return GrayOf (aColor);
+}
+
+sal_uInt8
+SalPrinterBmp::GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const
+{
+ Scanline pScan = mpScanAccess + nRow * mnScanOffset;
+ BitmapColor aColor = mpFncGetPixel (pScan, nColumn, mpBmpBuffer->maColorMask);
+
+ if (aColor.IsIndex())
+ return aColor.GetIndex();
+ else
+ return 0;
+}
+
+/*******************************************************
+ * PspGraphics *
+ *******************************************************/
+
+PspGraphics::~PspGraphics()
+{
+ ReleaseFonts();
+}
+
+void PspGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY )
+{
+ if (m_pJobData != NULL)
+ {
+ int x = m_pJobData->m_aContext.getRenderResolution();
+
+ rDPIX = x;
+ rDPIY = x;
+ }
+}
+
+sal_uInt16 PspGraphics::GetBitCount() const
+{
+ return m_pPrinterGfx->GetBitCount();
+}
+
+long PspGraphics::GetGraphicsWidth() const
+{
+ return 0;
+}
+
+void PspGraphics::ResetClipRegion()
+{
+ m_pPrinterGfx->ResetClipRegion();
+}
+
+bool PspGraphics::setClipRegion( const Region& i_rClip )
+{
+ // TODO: support polygonal clipregions here
+ m_pPrinterGfx->BeginSetClipRegion( i_rClip.GetRectCount() );
+
+ ImplRegionInfo aInfo;
+ long nX, nY, nW, nH;
+ bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH );
+ while( bRegionRect )
+ {
+ if ( nW && nH )
+ {
+ m_pPrinterGfx->UnionClipRegion( nX, nY, nW, nH );
+ }
+ bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
+ }
+ m_pPrinterGfx->EndSetClipRegion();
+ return true;
+}
+
+void PspGraphics::SetLineColor()
+{
+ m_pPrinterGfx->SetLineColor ();
+}
+
+void PspGraphics::SetLineColor( SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->SetLineColor (aColor);
+}
+
+void PspGraphics::SetFillColor()
+{
+ m_pPrinterGfx->SetFillColor ();
+}
+
+void PspGraphics::SetFillColor( SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->SetFillColor (aColor);
+}
+
+void PspGraphics::SetROPLineColor( SalROPColor )
+{
+ DBG_ASSERT( 0, "Error: PrinterGfx::SetROPLineColor() not implemented" );
+}
+
+void PspGraphics::SetROPFillColor( SalROPColor )
+{
+ DBG_ASSERT( 0, "Error: PrinterGfx::SetROPFillColor() not implemented" );
+}
+
+void PspGraphics::SetXORMode( bool bSet, bool )
+{
+ (void)bSet;
+ DBG_ASSERT( !bSet, "Error: PrinterGfx::SetXORMode() not implemented" );
+}
+
+void PspGraphics::drawPixel( long nX, long nY )
+{
+ m_pPrinterGfx->DrawPixel (Point(nX, nY));
+}
+
+void PspGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->DrawPixel (Point(nX, nY), aColor);
+}
+
+void PspGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ m_pPrinterGfx->DrawLine (Point(nX1, nY1), Point(nX2, nY2));
+}
+
+void PspGraphics::drawRect( long nX, long nY, long nDX, long nDY )
+{
+ m_pPrinterGfx->DrawRect (Rectangle(Point(nX, nY), Size(nDX, nDY)));
+}
+
+void PspGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint *pPtAry )
+{
+ m_pPrinterGfx->DrawPolyLine (nPoints, (Point*)pPtAry);
+}
+
+void PspGraphics::drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry )
+{
+ // Point must be equal to SalPoint! see vcl/inc/salgtype.hxx
+ m_pPrinterGfx->DrawPolygon (nPoints, (Point*)pPtAry);
+}
+
+void PspGraphics::drawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32 *pPoints,
+ PCONSTSALPOINT *pPtAry )
+{
+ m_pPrinterGfx->DrawPolyPolygon (nPoly, pPoints, (const Point**)pPtAry);
+}
+
+bool PspGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double /*fTransparency*/ )
+{
+ // TODO: implement and advertise OutDevSupport_B2DDraw support
+ return false;
+}
+
+bool PspGraphics::drawPolyLine( const basegfx::B2DPolygon&, double /*fTranspareny*/, const basegfx::B2DVector& /*rLineWidths*/, basegfx::B2DLineJoin /*eJoin*/)
+{
+ // TODO: a PS printer can draw B2DPolyLines almost directly
+ return false;
+}
+
+sal_Bool PspGraphics::drawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry )
+{
+ m_pPrinterGfx->DrawPolyLineBezier (nPoints, (Point*)pPtAry, pFlgAry);
+ return sal_True;
+}
+
+sal_Bool PspGraphics::drawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry )
+{
+ m_pPrinterGfx->DrawPolygonBezier (nPoints, (Point*)pPtAry, pFlgAry);
+ return sal_True;
+}
+
+sal_Bool PspGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ const SalPoint* const* pPtAry,
+ const sal_uInt8* const* pFlgAry )
+{
+ // Point must be equal to SalPoint! see vcl/inc/salgtype.hxx
+ m_pPrinterGfx->DrawPolyPolygonBezier (nPoly, pPoints, (Point**)pPtAry, (sal_uInt8**)pFlgAry);
+ return sal_True;
+}
+
+void PspGraphics::invert( sal_uLong,
+ const SalPoint*,
+ SalInvert )
+{
+ DBG_ASSERT( 0, "Error: PrinterGfx::Invert() not implemented" );
+}
+sal_Bool PspGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize )
+{
+ return m_pPrinterGfx->DrawEPS( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ), pPtr, nSize );
+}
+
+void PspGraphics::copyBits( const SalTwoRect*,
+ SalGraphics* )
+{
+ OSL_FAIL( "Error: PrinterGfx::CopyBits() not implemented" );
+}
+
+void PspGraphics::copyArea ( long,long,long,long,long,long,sal_uInt16 )
+{
+ OSL_FAIL( "Error: PrinterGfx::CopyArea() not implemented" );
+}
+
+void PspGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap )
+{
+ Rectangle aSrc (Point(pPosAry->mnSrcX, pPosAry->mnSrcY),
+ Size(pPosAry->mnSrcWidth, pPosAry->mnSrcHeight));
+ Rectangle aDst (Point(pPosAry->mnDestX, pPosAry->mnDestY),
+ Size(pPosAry->mnDestWidth, pPosAry->mnDestHeight));
+
+ BitmapBuffer* pBuffer= const_cast<SalBitmap&>(rSalBitmap).AcquireBuffer(sal_True);
+
+ SalPrinterBmp aBmp (pBuffer);
+ m_pPrinterGfx->DrawBitmap (aDst, aSrc, aBmp);
+
+ const_cast<SalBitmap&>(rSalBitmap).ReleaseBuffer (pBuffer, sal_True);
+}
+
+void PspGraphics::drawBitmap( const SalTwoRect*,
+ const SalBitmap&,
+ const SalBitmap& )
+{
+ OSL_FAIL("Error: no PrinterGfx::DrawBitmap() for transparent bitmap");
+}
+
+void PspGraphics::drawBitmap( const SalTwoRect*,
+ const SalBitmap&,
+ SalColor )
+{
+ OSL_FAIL("Error: no PrinterGfx::DrawBitmap() for transparent color");
+}
+
+void PspGraphics::drawMask( const SalTwoRect*,
+ const SalBitmap &,
+ SalColor )
+{
+ OSL_FAIL("Error: PrinterGfx::DrawMask() not implemented");
+}
+
+SalBitmap* PspGraphics::getBitmap( long, long, long, long )
+{
+ DBG_WARNING ("Warning: PrinterGfx::GetBitmap() not implemented");
+ return NULL;
+}
+
+SalColor PspGraphics::getPixel( long, long )
+{
+ OSL_FAIL("Warning: PrinterGfx::GetPixel() not implemented");
+ return 0;
+}
+
+void PspGraphics::invert(long,long,long,long,SalInvert)
+{
+ OSL_FAIL("Warning: PrinterGfx::Invert() not implemented");
+}
+
+//==========================================================================
+
+class ImplPspFontData : public ImplFontData
+{
+private:
+ enum { PSPFD_MAGIC = 0xb5bf01f0 };
+ sal_IntPtr mnFontId;
+
+public:
+ ImplPspFontData( const psp::FastPrintFontInfo& );
+ virtual sal_IntPtr GetFontId() const { return mnFontId; }
+ virtual ImplFontData* Clone() const { return new ImplPspFontData( *this ); }
+ virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const;
+ static bool CheckFontData( const ImplFontData& r ) { return r.CheckMagic( PSPFD_MAGIC ); }
+};
+
+//--------------------------------------------------------------------------
+
+ImplPspFontData::ImplPspFontData( const psp::FastPrintFontInfo& rInfo )
+: ImplFontData( PspGraphics::Info2DevFontAttributes(rInfo), PSPFD_MAGIC ),
+ mnFontId( rInfo.m_nID )
+{}
+
+//--------------------------------------------------------------------------
+
+ImplFontEntry* ImplPspFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
+{
+ ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
+ return pEntry;
+}
+
+//==========================================================================
+
+class PspFontLayout : public GenericSalLayout
+{
+public:
+ PspFontLayout( ::psp::PrinterGfx& );
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void InitFont() const;
+ virtual void DrawText( SalGraphics& ) const;
+private:
+ ::psp::PrinterGfx& mrPrinterGfx;
+ sal_IntPtr mnFontID;
+ int mnFontHeight;
+ int mnFontWidth;
+ bool mbVertical;
+ bool mbArtItalic;
+ bool mbArtBold;
+};
+
+//--------------------------------------------------------------------------
+
+PspFontLayout::PspFontLayout( ::psp::PrinterGfx& rGfx )
+: mrPrinterGfx( rGfx )
+{
+ mnFontID = mrPrinterGfx.GetFontID();
+ mnFontHeight = mrPrinterGfx.GetFontHeight();
+ mnFontWidth = mrPrinterGfx.GetFontWidth();
+ mbVertical = mrPrinterGfx.GetFontVertical();
+ mbArtItalic = mrPrinterGfx.GetArtificialItalic();
+ mbArtBold = mrPrinterGfx.GetArtificialBold();
+}
+
+//--------------------------------------------------------------------------
+
+bool PspFontLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ mbVertical = ((rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0);
+
+ long nUnitsPerPixel = 1;
+ int nOldGlyphId = -1;
+ long nGlyphWidth = 0;
+ int nCharPos = -1;
+ Point aNewPos( 0, 0 );
+ GlyphItem aPrevItem;
+ rtl_TextEncoding aFontEnc = mrPrinterGfx.GetFontMgr().getFontEncoding( mnFontID );
+ for(;;)
+ {
+ bool bRightToLeft;
+ if( !rArgs.GetNextPos( &nCharPos, &bRightToLeft ) )
+ break;
+
+ sal_Unicode cChar = rArgs.mpStr[ nCharPos ];
+ if( bRightToLeft )
+ cChar = GetMirroredChar( cChar );
+ // symbol font aliasing: 0x0020-0x00ff -> 0xf020 -> 0xf0ff
+ if( aFontEnc == RTL_TEXTENCODING_SYMBOL )
+ if( cChar < 256 )
+ cChar += 0xf000;
+ int nGlyphIndex = cChar; // printer glyphs = unicode
+
+ // update fallback_runs if needed
+ psp::CharacterMetric aMetric;
+ mrPrinterGfx.GetFontMgr().getMetrics( mnFontID, cChar, cChar, &aMetric, mbVertical );
+ if( aMetric.width == -1 && aMetric.height == -1 )
+ rArgs.NeedFallback( nCharPos, bRightToLeft );
+
+ // apply pair kerning to prev glyph if requested
+ if( SAL_LAYOUT_KERNING_PAIRS & rArgs.mnFlags )
+ {
+ if( nOldGlyphId > 0 )
+ {
+ const std::list< KernPair >& rKernPairs = mrPrinterGfx.getKernPairs(mbVertical);
+ for( std::list< KernPair >::const_iterator it = rKernPairs.begin();
+ it != rKernPairs.end(); ++it )
+ {
+ if( it->first == nOldGlyphId && it->second == nGlyphIndex )
+ {
+ int nTextScale = mrPrinterGfx.GetFontWidth();
+ if( ! nTextScale )
+ nTextScale = mrPrinterGfx.GetFontHeight();
+ int nKern = (mbVertical ? it->kern_y : it->kern_x) * nTextScale;
+ nGlyphWidth += nKern;
+ aPrevItem.mnNewWidth = nGlyphWidth;
+ break;
+ }
+ }
+ }
+ }
+
+ // finish previous glyph
+ if( nOldGlyphId >= 0 )
+ AppendGlyph( aPrevItem );
+ nOldGlyphId = nGlyphIndex;
+ aNewPos.X() += nGlyphWidth;
+
+ // prepare GlyphItem for appending it in next round
+ nUnitsPerPixel = mrPrinterGfx.GetCharWidth( cChar, cChar, &nGlyphWidth );
+ int nGlyphFlags = bRightToLeft ? GlyphItem::IS_RTL_GLYPH : 0;
+ nGlyphIndex |= GF_ISCHAR;
+ aPrevItem = GlyphItem( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
+ }
+
+ // append last glyph item if any
+ if( nOldGlyphId >= 0 )
+ AppendGlyph( aPrevItem );
+
+ SetOrientation( mrPrinterGfx.GetFontAngle() );
+ SetUnitsPerPixel( nUnitsPerPixel );
+ return (nOldGlyphId >= 0);
+}
+
+class PspServerFontLayout : public ServerFontLayout
+{
+public:
+ PspServerFontLayout( psp::PrinterGfx&, ServerFont& rFont, const ImplLayoutArgs& rArgs );
+
+ virtual void InitFont() const;
+ const sal_Unicode* getTextPtr() const { return maText.getStr() - mnMinCharPos; }
+ int getMinCharPos() const { return mnMinCharPos; }
+ int getMaxCharPos() const { return mnMinCharPos+maText.getLength()-1; }
+private:
+ ::psp::PrinterGfx& mrPrinterGfx;
+ sal_IntPtr mnFontID;
+ int mnFontHeight;
+ int mnFontWidth;
+ bool mbVertical;
+ bool mbArtItalic;
+ bool mbArtBold;
+ rtl::OUString maText;
+ int mnMinCharPos;
+};
+
+PspServerFontLayout::PspServerFontLayout( ::psp::PrinterGfx& rGfx, ServerFont& rFont, const ImplLayoutArgs& rArgs )
+ : ServerFontLayout( rFont ),
+ mrPrinterGfx( rGfx )
+{
+ mnFontID = mrPrinterGfx.GetFontID();
+ mnFontHeight = mrPrinterGfx.GetFontHeight();
+ mnFontWidth = mrPrinterGfx.GetFontWidth();
+ mbVertical = mrPrinterGfx.GetFontVertical();
+ mbArtItalic = mrPrinterGfx.GetArtificialItalic();
+ mbArtBold = mrPrinterGfx.GetArtificialBold();
+ maText = OUString( rArgs.mpStr + rArgs.mnMinCharPos, rArgs.mnEndCharPos - rArgs.mnMinCharPos+1 );
+ mnMinCharPos = rArgs.mnMinCharPos;
+}
+
+void PspServerFontLayout::InitFont() const
+{
+ mrPrinterGfx.SetFont( mnFontID, mnFontHeight, mnFontWidth,
+ mnOrientation, mbVertical, mbArtItalic, mbArtBold );
+}
+
+//--------------------------------------------------------------------------
+
+static void DrawPrinterLayout( const SalLayout& rLayout, ::psp::PrinterGfx& rGfx, bool bIsPspServerFontLayout )
+{
+ const int nMaxGlyphs = 200;
+ sal_uInt32 aGlyphAry[ nMaxGlyphs ]; // TODO: use sal_GlyphId
+ sal_Int32 aWidthAry[ nMaxGlyphs ];
+ sal_Int32 aIdxAry [ nMaxGlyphs ];
+ sal_Unicode aUnicodes[ nMaxGlyphs ];
+ int aCharPosAry [ nMaxGlyphs ];
+
+ Point aPos;
+ long nUnitsPerPixel = rLayout.GetUnitsPerPixel();
+ const sal_Unicode* pText = NULL;
+ int nMinCharPos = 0;
+ int nMaxCharPos = 0;
+ if (bIsPspServerFontLayout)
+ {
+ const PspServerFontLayout * pPspLayout = dynamic_cast<const PspServerFontLayout*>(&rLayout);
+#ifdef ENABLE_GRAPHITE
+ const GraphiteServerFontLayout * pGrLayout = dynamic_cast<const GraphiteServerFontLayout*>(&rLayout);
+#endif
+ if (pPspLayout)
+ {
+ pText = pPspLayout->getTextPtr();
+ nMinCharPos = pPspLayout->getMinCharPos();
+ nMaxCharPos = pPspLayout->getMaxCharPos();
+ }
+#ifdef ENABLE_GRAPHITE
+ else if (pGrLayout)
+ {
+ }
+#endif
+ }
+ for( int nStart = 0;; )
+ {
+ int nGlyphCount = rLayout.GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart, aWidthAry, pText ? aCharPosAry : NULL );
+ if( !nGlyphCount )
+ break;
+
+ sal_Int32 nXOffset = 0;
+ for( int i = 0; i < nGlyphCount; ++i )
+ {
+ nXOffset += aWidthAry[ i ];
+ aIdxAry[ i ] = nXOffset / nUnitsPerPixel;
+ sal_Int32 nGlyphIdx = aGlyphAry[i] & (GF_IDXMASK | GF_ROTMASK);
+ if( pText )
+ aUnicodes[i] = (aCharPosAry[i] >= nMinCharPos && aCharPosAry[i] <= nMaxCharPos) ? pText[ aCharPosAry[i] ] : 0;
+ else
+ aUnicodes[i] = (aGlyphAry[i] & GF_ISCHAR) ? nGlyphIdx : 0;
+ aGlyphAry[i] = nGlyphIdx;
+ }
+
+ rGfx.DrawGlyphs( aPos, (sal_uInt32 *)aGlyphAry, aUnicodes, nGlyphCount, aIdxAry );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+void PspFontLayout::InitFont() const
+{
+ mrPrinterGfx.SetFont( mnFontID, mnFontHeight, mnFontWidth,
+ mnOrientation, mbVertical, mbArtItalic, mbArtBold );
+}
+
+//--------------------------------------------------------------------------
+
+void PspFontLayout::DrawText( SalGraphics& ) const
+{
+ DrawPrinterLayout( *this, mrPrinterGfx, false );
+}
+
+void PspGraphics::DrawServerFontLayout( const ServerFontLayout& rLayout )
+{
+ // print complex text
+ DrawPrinterLayout( rLayout, *m_pPrinterGfx, true );
+}
+
+const ImplFontCharMap* PspGraphics::GetImplFontCharMap() const
+{
+ if( !m_pServerFont[0] )
+ return NULL;
+
+ const ImplFontCharMap* pIFCMap = m_pServerFont[0]->GetImplFontCharMap();
+ return pIFCMap;
+}
+
+bool PspGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
+{
+ if (!m_pServerFont[0])
+ return false;
+ return m_pServerFont[0]->GetFontCapabilities(rFontCapabilities);
+}
+
+sal_uInt16 PspGraphics::SetFont( ImplFontSelectData *pEntry, int nFallbackLevel )
+{
+ // release all fonts that are to be overridden
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( m_pServerFont[i] != NULL )
+ {
+ // old server side font is no longer referenced
+ GlyphCache::GetInstance().UncacheFont( *m_pServerFont[i] );
+ m_pServerFont[i] = NULL;
+ }
+ }
+
+ // return early if there is no new font
+ if( !pEntry )
+ return 0;
+
+ sal_IntPtr nID = pEntry->mpFontData ? pEntry->mpFontData->GetFontId() : 0;
+
+ // determine which font attributes need to be emulated
+ bool bArtItalic = false;
+ bool bArtBold = false;
+ if( pEntry->meItalic == ITALIC_OBLIQUE || pEntry->meItalic == ITALIC_NORMAL )
+ {
+ psp::italic::type eItalic = m_pPrinterGfx->GetFontMgr().getFontItalic( nID );
+ if( eItalic != psp::italic::Italic && eItalic != psp::italic::Oblique )
+ bArtItalic = true;
+ }
+ int nWeight = (int)pEntry->meWeight;
+ int nRealWeight = (int)m_pPrinterGfx->GetFontMgr().getFontWeight( nID );
+ if( nRealWeight <= (int)psp::weight::Medium && nWeight > (int)WEIGHT_MEDIUM )
+ {
+ bArtBold = true;
+ }
+
+ // also set the serverside font for layouting
+ m_bFontVertical = pEntry->mbVertical;
+ if( pEntry->mpFontData )
+ {
+ // requesting a font provided by builtin rasterizer
+ ServerFont* pServerFont = GlyphCache::GetInstance().CacheFont( *pEntry );
+ if( pServerFont != NULL )
+ {
+ if( pServerFont->TestFont() )
+ m_pServerFont[ nFallbackLevel ] = pServerFont;
+ else
+ GlyphCache::GetInstance().UncacheFont( *pServerFont );
+ }
+ }
+
+ // set the printer font
+ return m_pPrinterGfx->SetFont( nID,
+ pEntry->mnHeight,
+ pEntry->mnWidth,
+ pEntry->mnOrientation,
+ pEntry->mbVertical,
+ bArtItalic,
+ bArtBold
+ );
+}
+
+void PspGraphics::SetTextColor( SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->SetTextColor (aColor);
+}
+
+bool PspGraphics::AddTempDevFont( ImplDevFontList*, const String&,const String& )
+{
+ return false;
+}
+
+void RegisterFontSubstitutors( ImplDevFontList* );
+
+void PspGraphics::GetDevFontList( ImplDevFontList *pList )
+{
+ ::std::list< psp::fontID > aList;
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ rMgr.getFontList( aList, m_pJobData->m_pParser, m_pInfoPrinter->m_bCompatMetrics );
+
+ ::std::list< psp::fontID >::iterator it;
+ psp::FastPrintFontInfo aInfo;
+ for (it = aList.begin(); it != aList.end(); ++it)
+ if (rMgr.getFontFastInfo (*it, aInfo))
+ AnnounceFonts( pList, aInfo );
+
+ // register platform specific font substitutions if available
+ if( rMgr.hasFontconfig() )
+ RegisterFontSubstitutors( pList );
+}
+
+void PspGraphics::GetDevFontSubstList( OutputDevice* pOutDev )
+{
+ const psp::PrinterInfo& rInfo = psp::PrinterInfoManager::get().getPrinterInfo( m_pJobData->m_aPrinterName );
+ if( rInfo.m_bPerformFontSubstitution )
+ {
+ for( boost::unordered_map< rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator it = rInfo.m_aFontSubstitutes.begin(); it != rInfo.m_aFontSubstitutes.end(); ++it )
+ pOutDev->ImplAddDevFontSubstitute( it->first, it->second, FONT_SUBSTITUTE_ALWAYS );
+ }
+}
+
+void PspGraphics::GetFontMetric( ImplFontMetricData *pMetric, int )
+{
+ const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ psp::PrintFontInfo aInfo;
+
+ if (rMgr.getFontInfo (m_pPrinterGfx->GetFontID(), aInfo))
+ {
+ ImplDevFontAttributes aDFA = Info2DevFontAttributes( aInfo );
+ static_cast<ImplFontAttributes&>(*pMetric) = aDFA;
+ pMetric->mbDevice = aDFA.mbDevice;
+ pMetric->mbScalableFont = true;
+
+ pMetric->mnOrientation = m_pPrinterGfx->GetFontAngle();
+ pMetric->mnSlant = 0;
+
+ sal_Int32 nTextHeight = m_pPrinterGfx->GetFontHeight();
+ sal_Int32 nTextWidth = m_pPrinterGfx->GetFontWidth();
+ if( ! nTextWidth )
+ nTextWidth = nTextHeight;
+
+ pMetric->mnWidth = nTextWidth;
+ pMetric->mnAscent = ( aInfo.m_nAscend * nTextHeight + 500 ) / 1000;
+ pMetric->mnDescent = ( aInfo.m_nDescend * nTextHeight + 500 ) / 1000;
+ pMetric->mnIntLeading = ( aInfo.m_nLeading * nTextHeight + 500 ) / 1000;
+ pMetric->mnExtLeading = 0;
+ }
+}
+
+sal_uLong PspGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData *pKernPairs )
+{
+ const ::std::list< ::psp::KernPair >& rPairs( m_pPrinterGfx->getKernPairs() );
+ sal_uLong nHavePairs = rPairs.size();
+ if( pKernPairs && nPairs )
+ {
+ ::std::list< ::psp::KernPair >::const_iterator it;
+ unsigned int i;
+ int nTextScale = m_pPrinterGfx->GetFontWidth();
+ if( ! nTextScale )
+ nTextScale = m_pPrinterGfx->GetFontHeight();
+ for( i = 0, it = rPairs.begin(); i < nPairs && i < nHavePairs; i++, ++it )
+ {
+ pKernPairs[i].mnChar1 = it->first;
+ pKernPairs[i].mnChar2 = it->second;
+ pKernPairs[i].mnKern = it->kern_x * nTextScale / 1000;
+ }
+
+ }
+ return nHavePairs;
+}
+
+sal_Bool PspGraphics::GetGlyphBoundRect( long nGlyphIndex, Rectangle& rRect )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return sal_False;
+
+ ServerFont* pSF = m_pServerFont[ nLevel ];
+ if( !pSF )
+ return sal_False;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ const GlyphMetric& rGM = pSF->GetGlyphMetric( nGlyphIndex );
+ rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
+ return sal_True;
+}
+
+sal_Bool PspGraphics::GetGlyphOutline( long nGlyphIndex,
+ ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return sal_False;
+
+ ServerFont* pSF = m_pServerFont[ nLevel ];
+ if( !pSF )
+ return sal_False;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ if( pSF->GetGlyphOutline( nGlyphIndex, rB2DPolyPoly ) )
+ return sal_True;
+
+ return sal_False;
+}
+
+SalLayout* PspGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+{
+ // workaround for printers not handling glyph indexing for non-TT fonts
+ int nFontId = m_pPrinterGfx->GetFontID();
+ if( psp::fonttype::TrueType != psp::PrintFontManager::get().getFontType( nFontId ) )
+ rArgs.mnFlags |= SAL_LAYOUT_DISABLE_GLYPH_PROCESSING;
+ else if( nFallbackLevel > 0 )
+ rArgs.mnFlags &= ~SAL_LAYOUT_DISABLE_GLYPH_PROCESSING;
+
+ GenericSalLayout* pLayout = NULL;
+
+ if( m_pServerFont[ nFallbackLevel ]
+ && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) )
+ {
+#ifdef ENABLE_GRAPHITE
+ // Is this a Graphite font?
+ if (GraphiteServerFontLayout::IsGraphiteEnabledFont(m_pServerFont[nFallbackLevel]))
+ {
+ pLayout = new GraphiteServerFontLayout(*m_pServerFont[nFallbackLevel]);
+ }
+ else
+#endif
+ pLayout = new PspServerFontLayout( *m_pPrinterGfx, *m_pServerFont[nFallbackLevel], rArgs );
+ }
+ else
+ pLayout = new PspFontLayout( *m_pPrinterGfx );
+
+ return pLayout;
+}
+
+//--------------------------------------------------------------------------
+
+sal_Bool PspGraphics::CreateFontSubset(
+ const rtl::OUString& rToFile,
+ const ImplFontData* pFont,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphCount,
+ FontSubsetInfo& rInfo
+ )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ bool bSuccess = rMgr.createFontSubset( rInfo,
+ aFont,
+ rToFile,
+ pGlyphIDs,
+ pEncoding,
+ pWidths,
+ nGlyphCount );
+ return bSuccess;
+}
+
+//--------------------------------------------------------------------------
+
+const void* PspGraphics::GetEmbedFontData( const ImplFontData* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen );
+}
+
+//--------------------------------------------------------------------------
+
+void PspGraphics::FreeEmbedFontData( const void* pData, long nLen )
+{
+ PspGraphics::DoFreeEmbedFontData( pData, nLen );
+}
+
+//--------------------------------------------------------------------------
+
+const Ucs2SIntMap* PspGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded );
+}
+
+//--------------------------------------------------------------------------
+
+void PspGraphics::GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+
+
+// static helpers of PspGraphics
+
+const void* PspGraphics::DoGetEmbedFontData( fontID aFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
+{
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+
+ psp::PrintFontInfo aFontInfo;
+ if( ! rMgr.getFontInfo( aFont, aFontInfo ) )
+ return NULL;
+
+ // fill in font info
+ rInfo.m_nAscent = aFontInfo.m_nAscend;
+ rInfo.m_nDescent = aFontInfo.m_nDescend;
+ rInfo.m_aPSName = rMgr.getPSName( aFont );
+
+ int xMin, yMin, xMax, yMax;
+ rMgr.getFontBoundingBox( aFont, xMin, yMin, xMax, yMax );
+
+ psp::CharacterMetric aMetrics[256];
+ sal_Ucs aUnicodes[256];
+ if( aFontInfo.m_aEncoding == RTL_TEXTENCODING_SYMBOL && aFontInfo.m_eType == psp::fonttype::Type1 )
+ {
+ for( int i = 0; i < 256; i++ )
+ aUnicodes[i] = pUnicodes[i] < 0x0100 ? pUnicodes[i] + 0xf000 : pUnicodes[i];
+ pUnicodes = aUnicodes;
+ }
+ if( ! rMgr.getMetrics( aFont, pUnicodes, 256, aMetrics ) )
+ return NULL;
+
+ OString aSysPath = rMgr.getFontFileSysPath( aFont );
+ struct stat aStat;
+ if( stat( aSysPath.getStr(), &aStat ) )
+ return NULL;
+ int fd = open( aSysPath.getStr(), O_RDONLY );
+ if( fd < 0 )
+ return NULL;
+ void* pFile = mmap( NULL, aStat.st_size, PROT_READ, MAP_SHARED, fd, 0 );
+ close( fd );
+ if( pFile == MAP_FAILED )
+ return NULL;
+
+ *pDataLen = aStat.st_size;
+
+ rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
+ rInfo.m_nCapHeight = yMax; // Well ...
+
+ for( int i = 0; i < 256; i++ )
+ pWidths[i] = (aMetrics[i].width > 0 ? aMetrics[i].width : 0);
+
+ switch( aFontInfo.m_eType )
+ {
+ case psp::fonttype::TrueType:
+ rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
+ break;
+ case psp::fonttype::Type1: {
+ const bool bPFA = ((*(unsigned char*)pFile) < 0x80);
+ rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB;
+ }
+ break;
+ default:
+ return NULL;
+ }
+
+ return pFile;
+}
+
+void PspGraphics::DoFreeEmbedFontData( const void* pData, long nLen )
+{
+ if( pData )
+ munmap( (char*)pData, nLen );
+}
+
+const Ucs2SIntMap* PspGraphics::DoGetFontEncodingVector( fontID aFont, const Ucs2OStrMap** pNonEncoded )
+{
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+
+ psp::PrintFontInfo aFontInfo;
+ if( ! rMgr.getFontInfo( aFont, aFontInfo ) )
+ {
+ if( pNonEncoded )
+ *pNonEncoded = NULL;
+ return NULL;
+ }
+
+ return rMgr.getEncodingMap( aFont, pNonEncoded );
+}
+
+void PspGraphics::DoGetGlyphWidths( psp::fontID aFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ rMgr.getGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+// ----------------------------------------------------------------------------
+
+FontWidth PspGraphics::ToFontWidth (psp::width::type eWidth)
+{
+ switch (eWidth)
+ {
+ case psp::width::UltraCondensed: return WIDTH_ULTRA_CONDENSED;
+ case psp::width::ExtraCondensed: return WIDTH_EXTRA_CONDENSED;
+ case psp::width::Condensed: return WIDTH_CONDENSED;
+ case psp::width::SemiCondensed: return WIDTH_SEMI_CONDENSED;
+ case psp::width::Normal: return WIDTH_NORMAL;
+ case psp::width::SemiExpanded: return WIDTH_SEMI_EXPANDED;
+ case psp::width::Expanded: return WIDTH_EXPANDED;
+ case psp::width::ExtraExpanded: return WIDTH_EXTRA_EXPANDED;
+ case psp::width::UltraExpanded: return WIDTH_ULTRA_EXPANDED;
+ case psp::width::Unknown: return WIDTH_DONTKNOW;
+ default:
+ OSL_FAIL( "unknown width mapping" );
+ break;
+ }
+ return WIDTH_DONTKNOW;
+}
+
+FontWeight PspGraphics::ToFontWeight (psp::weight::type eWeight)
+{
+ switch (eWeight)
+ {
+ case psp::weight::Thin: return WEIGHT_THIN;
+ case psp::weight::UltraLight: return WEIGHT_ULTRALIGHT;
+ case psp::weight::Light: return WEIGHT_LIGHT;
+ case psp::weight::SemiLight: return WEIGHT_SEMILIGHT;
+ case psp::weight::Normal: return WEIGHT_NORMAL;
+ case psp::weight::Medium: return WEIGHT_MEDIUM;
+ case psp::weight::SemiBold: return WEIGHT_SEMIBOLD;
+ case psp::weight::Bold: return WEIGHT_BOLD;
+ case psp::weight::UltraBold: return WEIGHT_ULTRABOLD;
+ case psp::weight::Black: return WEIGHT_BLACK;
+ case psp::weight::Unknown: return WEIGHT_DONTKNOW;
+ default:
+ OSL_FAIL( "unknown weight mapping" );
+ break;
+ }
+ return WEIGHT_DONTKNOW;
+}
+
+FontPitch PspGraphics::ToFontPitch (psp::pitch::type ePitch)
+{
+ switch (ePitch)
+ {
+ case psp::pitch::Fixed: return PITCH_FIXED;
+ case psp::pitch::Variable: return PITCH_VARIABLE;
+ case psp::pitch::Unknown: return PITCH_DONTKNOW;
+ default:
+ OSL_FAIL( "unknown pitch mapping" );
+ break;
+ }
+ return PITCH_DONTKNOW;
+}
+
+FontItalic PspGraphics::ToFontItalic (psp::italic::type eItalic)
+{
+ switch (eItalic)
+ {
+ case psp::italic::Upright: return ITALIC_NONE;
+ case psp::italic::Oblique: return ITALIC_OBLIQUE;
+ case psp::italic::Italic: return ITALIC_NORMAL;
+ case psp::italic::Unknown: return ITALIC_DONTKNOW;
+ default:
+ OSL_FAIL( "unknown italic mapping" );
+ break;
+ }
+ return ITALIC_DONTKNOW;
+}
+
+FontFamily PspGraphics::ToFontFamily (psp::family::type eFamily)
+{
+ switch (eFamily)
+ {
+ case psp::family::Decorative: return FAMILY_DECORATIVE;
+ case psp::family::Modern: return FAMILY_MODERN;
+ case psp::family::Roman: return FAMILY_ROMAN;
+ case psp::family::Script: return FAMILY_SCRIPT;
+ case psp::family::Swiss: return FAMILY_SWISS;
+ case psp::family::System: return FAMILY_SYSTEM;
+ case psp::family::Unknown: return FAMILY_DONTKNOW;
+ default:
+ OSL_FAIL( "unknown family mapping" );
+ break;
+ }
+ return FAMILY_DONTKNOW;
+}
+
+ImplDevFontAttributes PspGraphics::Info2DevFontAttributes( const psp::FastPrintFontInfo& rInfo )
+{
+ ImplDevFontAttributes aDFA;
+ aDFA.maName = rInfo.m_aFamilyName;
+ aDFA.maStyleName = rInfo.m_aStyleName;
+ aDFA.meFamily = ToFontFamily (rInfo.m_eFamilyStyle);
+ aDFA.meWeight = ToFontWeight (rInfo.m_eWeight);
+ aDFA.meItalic = ToFontItalic (rInfo.m_eItalic);
+ aDFA.meWidthType = ToFontWidth (rInfo.m_eWidth);
+ aDFA.mePitch = ToFontPitch (rInfo.m_ePitch);
+ aDFA.mbSymbolFlag = (rInfo.m_aEncoding == RTL_TEXTENCODING_SYMBOL);
+ aDFA.mbSubsettable = rInfo.m_bSubsettable;
+ aDFA.mbEmbeddable = rInfo.m_bEmbeddable;
+
+ switch( rInfo.m_eType )
+ {
+ case psp::fonttype::Builtin:
+ aDFA.mnQuality = 1024;
+ aDFA.mbDevice = true;
+ break;
+ case psp::fonttype::TrueType:
+ aDFA.mnQuality = 512;
+ aDFA.mbDevice = false;
+ break;
+ case psp::fonttype::Type1:
+ aDFA.mnQuality = 0;
+ aDFA.mbDevice = false;
+ break;
+ default:
+ aDFA.mnQuality = 0;
+ aDFA.mbDevice = false;
+ break;
+ }
+
+ aDFA.mbOrientation = true;
+
+ // add font family name aliases
+ ::std::list< OUString >::const_iterator it = rInfo.m_aAliases.begin();
+ bool bHasMapNames = false;
+ for(; it != rInfo.m_aAliases.end(); ++it )
+ {
+ if( bHasMapNames )
+ aDFA.maMapNames.Append( ';' );
+ aDFA.maMapNames.Append( (*it).getStr() );
+ bHasMapNames = true;
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ if( bHasMapNames )
+ {
+ ByteString aOrigName( aDFA.maName, osl_getThreadTextEncoding() );
+ ByteString aAliasNames( aDFA.maMapNames, osl_getThreadTextEncoding() );
+ fprintf( stderr, "using alias names \"%s\" for font family \"%s\"\n",
+ aAliasNames.GetBuffer(), aOrigName.GetBuffer() );
+ }
+#endif
+
+ return aDFA;
+}
+
+// -----------------------------------------------------------------------
+
+void PspGraphics::AnnounceFonts( ImplDevFontList* pFontList, const psp::FastPrintFontInfo& aInfo )
+{
+ int nQuality = 0;
+
+ if( aInfo.m_eType == psp::fonttype::TrueType )
+ {
+ // asian type 1 fonts are not known
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ ByteString aFileName( rMgr.getFontFileSysPath( aInfo.m_nID ) );
+ int nPos = aFileName.SearchBackward( '_' );
+ if( nPos == STRING_NOTFOUND || aFileName.GetChar( nPos+1 ) == '.' )
+ nQuality += 5;
+ else
+ {
+ static const char* pLangBoost = NULL;
+ static bool bOnce = true;
+ if( bOnce )
+ {
+ bOnce = false;
+ const LanguageType aLang = Application::GetSettings().GetUILanguage();
+ switch( aLang )
+ {
+ case LANGUAGE_JAPANESE:
+ pLangBoost = "jan";
+ break;
+ case LANGUAGE_CHINESE:
+ case LANGUAGE_CHINESE_SIMPLIFIED:
+ case LANGUAGE_CHINESE_SINGAPORE:
+ pLangBoost = "zhs";
+ break;
+ case LANGUAGE_CHINESE_TRADITIONAL:
+ case LANGUAGE_CHINESE_HONGKONG:
+ case LANGUAGE_CHINESE_MACAU:
+ pLangBoost = "zht";
+ break;
+ case LANGUAGE_KOREAN:
+ case LANGUAGE_KOREAN_JOHAB:
+ pLangBoost = "kor";
+ break;
+ }
+ }
+
+ if( pLangBoost )
+ if( aFileName.Copy( nPos+1, 3 ).EqualsIgnoreCaseAscii( pLangBoost ) )
+ nQuality += 10;
+ }
+ }
+
+ ImplPspFontData* pFD = new ImplPspFontData( aInfo );
+ pFD->mnQuality += nQuality;
+ pFontList->Add( pFD );
+}
+
+bool PspGraphics::filterText( const String& rOrig, String& rNewText, xub_StrLen nIndex, xub_StrLen& rLen, xub_StrLen& rCutStart, xub_StrLen& rCutStop )
+{
+ if( ! m_pPhoneNr )
+ return false;
+
+ rCutStop = rCutStart = STRING_NOTFOUND;
+
+#define FAX_PHONE_TOKEN "@@#"
+#define FAX_PHONE_TOKEN_LENGTH 3
+#define FAX_END_TOKEN "@@"
+#define FAX_END_TOKEN_LENGTH 2
+
+ bool bRet = false;
+ bool bStarted = false;
+ bool bStopped = false;
+ sal_uInt16 nPos;
+ sal_uInt16 nStart = 0;
+ sal_uInt16 nStop = rLen;
+ String aPhone = rOrig.Copy( nIndex, rLen );
+
+ if( ! m_bPhoneCollectionActive )
+ {
+ if( ( nPos = aPhone.SearchAscii( FAX_PHONE_TOKEN ) ) != STRING_NOTFOUND )
+ {
+ nStart = nPos;
+ m_bPhoneCollectionActive = true;
+ m_aPhoneCollection.Erase();
+ bRet = true;
+ bStarted = true;
+ }
+ }
+ if( m_bPhoneCollectionActive )
+ {
+ bRet = true;
+ nPos = bStarted ? nStart + FAX_PHONE_TOKEN_LENGTH : 0;
+ if( ( nPos = aPhone.SearchAscii( FAX_END_TOKEN, nPos ) ) != STRING_NOTFOUND )
+ {
+ m_bPhoneCollectionActive = false;
+ nStop = nPos + FAX_END_TOKEN_LENGTH;
+ bStopped = true;
+ }
+ int nTokenStart = nStart + (bStarted ? FAX_PHONE_TOKEN_LENGTH : 0);
+ int nTokenStop = nStop - (bStopped ? FAX_END_TOKEN_LENGTH : 0);
+ m_aPhoneCollection += aPhone.Copy( nTokenStart, nTokenStop - nTokenStart );
+ if( ! m_bPhoneCollectionActive )
+ {
+ m_pPhoneNr->AppendAscii( "<Fax#>" );
+ m_pPhoneNr->Append( m_aPhoneCollection );
+ m_pPhoneNr->AppendAscii( "</Fax#>" );
+ m_aPhoneCollection.Erase();
+ }
+ }
+ if( m_aPhoneCollection.Len() > 1024 )
+ {
+ m_bPhoneCollectionActive = false;
+ m_aPhoneCollection.Erase();
+ bRet = false;
+ }
+
+ if( bRet && m_bSwallowFaxNo )
+ {
+ rLen -= nStop - nStart;
+ rCutStart = nStart+nIndex;
+ rCutStop = nStop+nIndex;
+ if( rCutStart )
+ rNewText = rOrig.Copy( 0, rCutStart );
+ rNewText += rOrig.Copy( rCutStop );
+ }
+
+ return bRet && m_bSwallowFaxNo;
+}
+
+bool PspGraphics::drawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap&,
+ const SalBitmap& )
+{
+ return false;
+}
+
+bool PspGraphics::drawAlphaRect( long, long, long, long, sal_uInt8 )
+{
+ return false;
+}
+
+SystemGraphicsData PspGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+ aRes.nSize = sizeof(aRes);
+ aRes.hDrawable = 0;
+ aRes.pXRenderFormat = 0;
+ return aRes;
+}
+
+SystemFontData PspGraphics::GetSysFontData( int nFallbacklevel ) const
+{
+ SystemFontData aSysFontData;
+
+ if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
+ if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+
+ aSysFontData.nSize = sizeof( SystemFontData );
+ aSysFontData.nFontId = 0;
+ aSysFontData.nFontFlags = 0;
+ aSysFontData.bFakeBold = false;
+ aSysFontData.bFakeItalic = false;
+ aSysFontData.bAntialias = true;
+ return aSysFontData;
+}
+
+bool PspGraphics::supportsOperation( OutDevSupportType ) const
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/salbmp.cxx b/vcl/unx/generic/gdi/salbmp.cxx
new file mode 100644
index 000000000000..0c3babc48fdb
--- /dev/null
+++ b/vcl/unx/generic/gdi/salbmp.cxx
@@ -0,0 +1,1160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <errno.h>
+#ifdef FREEBSD
+#include <sys/types.h>
+#endif
+
+#include <osl/endian.h>
+#include <rtl/memory.h>
+
+#include <vcl/bitmap.hxx>
+#include <vcl/salbtype.hxx>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+
+#include <tools/prex.h>
+#include "unx/Xproto.h"
+#include <tools/postx.h>
+#include <unx/salunx.h>
+#include <unx/saldata.hxx>
+#include <unx/saldisp.hxx>
+#include <unx/salgdi.h>
+#include <unx/salbmp.h>
+#include <unx/salinst.h>
+
+// -----------
+// - Defines -
+// -----------
+
+#define SAL_DRAWPIXMAP_MAX_EXT 4096
+
+// -------------
+// - SalBitmap -
+// -------------
+
+SalBitmap* X11SalInstance::CreateSalBitmap()
+{
+ return new X11SalBitmap();
+}
+
+ImplSalBitmapCache* X11SalBitmap::mpCache = NULL;
+sal_uLong X11SalBitmap::mnCacheInstCount = 0;
+
+// -----------------------------------------------------------------------------
+
+X11SalBitmap::X11SalBitmap() :
+ mpDIB( NULL ),
+ mpDDB( NULL ),
+ mbGrey( false )
+{
+}
+
+// -----------------------------------------------------------------------------
+
+X11SalBitmap::~X11SalBitmap()
+{
+ Destroy();
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ImplCreateCache()
+{
+ if( !mnCacheInstCount++ )
+ mpCache = new ImplSalBitmapCache;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ImplDestroyCache()
+{
+ DBG_ASSERT( mnCacheInstCount, "X11SalBitmap::ImplDestroyCache(): underflow" );
+
+ if( mnCacheInstCount && !--mnCacheInstCount )
+ delete mpCache, mpCache = NULL;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ImplRemovedFromCache()
+{
+ if( mpDDB )
+ delete mpDDB, mpDDB = NULL;
+}
+
+// -----------------------------------------------------------------------------
+
+BitmapBuffer* X11SalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
+{
+ DBG_ASSERT( nBitCount == 1 || nBitCount == 4 || nBitCount == 8 || nBitCount == 16 || nBitCount == 24, "Unsupported BitCount!" );
+
+ BitmapBuffer* pDIB = NULL;
+
+ if( rSize.Width() && rSize.Height() )
+ {
+ try
+ {
+ pDIB = new BitmapBuffer;
+ }
+ catch( std::bad_alloc& )
+ {
+ pDIB = NULL;
+ }
+
+ if( pDIB )
+ {
+ const sal_uInt16 nColors = ( nBitCount <= 8 ) ? ( 1 << nBitCount ) : 0;
+
+ pDIB->mnFormat = BMP_FORMAT_BOTTOM_UP;
+
+ switch( nBitCount )
+ {
+ case( 1 ): pDIB->mnFormat |= BMP_FORMAT_1BIT_MSB_PAL; break;
+ case( 4 ): pDIB->mnFormat |= BMP_FORMAT_4BIT_MSN_PAL; break;
+ case( 8 ): pDIB->mnFormat |= BMP_FORMAT_8BIT_PAL; break;
+#ifdef OSL_BIGENDIAN
+ case(16 ):
+ pDIB->mnFormat|= BMP_FORMAT_16BIT_TC_MSB_MASK;
+ pDIB->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f );
+ break;
+#else
+ case(16 ):
+ pDIB->mnFormat|= BMP_FORMAT_16BIT_TC_LSB_MASK;
+ pDIB->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f );
+ break;
+#endif
+ default:
+ nBitCount = 24;
+ //fall through
+ case 24:
+ pDIB->mnFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ break;
+ }
+
+ pDIB->mnWidth = rSize.Width();
+ pDIB->mnHeight = rSize.Height();
+ pDIB->mnScanlineSize = AlignedWidth4Bytes( pDIB->mnWidth * nBitCount );
+ pDIB->mnBitCount = nBitCount;
+
+ if( nColors )
+ {
+ pDIB->maPalette = rPal;
+ pDIB->maPalette.SetEntryCount( nColors );
+ }
+
+ try
+ {
+ pDIB->mpBits = new sal_uInt8[ pDIB->mnScanlineSize * pDIB->mnHeight ];
+ }
+ catch(std::bad_alloc&)
+ {
+ delete pDIB;
+ pDIB = NULL;
+ }
+ }
+ }
+ else
+ pDIB = NULL;
+
+ return pDIB;
+}
+
+// -----------------------------------------------------------------------------
+
+BitmapBuffer* X11SalBitmap::ImplCreateDIB( Drawable aDrawable,
+ int nScreen,
+ long nDrawableDepth,
+ long nX, long nY,
+ long nWidth, long nHeight,
+ bool bGrey )
+{
+ BitmapBuffer* pDIB = NULL;
+
+ if( aDrawable && nWidth && nHeight && nDrawableDepth )
+ {
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ SalXLib* pXLib = pSalDisp->GetXLib();
+ Display* pXDisp = pSalDisp->GetDisplay();
+
+ // do not die on XError here
+ // alternatively one could check the coordinates for being offscreen
+ // but this call can actually work on servers with backing store
+ // defaults even if the rectangle is offscreen
+ // so better catch the XError
+ pXLib->PushXErrorLevel( true );
+ XImage* pImage = XGetImage( pXDisp, aDrawable, nX, nY, nWidth, nHeight, AllPlanes, ZPixmap );
+ bool bWasError = pXLib->HasXErrorOccurred() && pXLib->GetLastXErrorRequestCode() == X_GetImage;
+ pXLib->PopXErrorLevel();
+
+ if( ! bWasError && pImage && pImage->data )
+ {
+ const SalTwoRect aTwoRect = { 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight };
+ BitmapBuffer aSrcBuf;
+ sal_uLong nDstFormat = BMP_FORMAT_BOTTOM_UP;
+ const BitmapPalette* pDstPal = NULL;
+
+ aSrcBuf.mnFormat = BMP_FORMAT_TOP_DOWN;
+ aSrcBuf.mnWidth = nWidth;
+ aSrcBuf.mnHeight = nHeight;
+ aSrcBuf.mnBitCount = pImage->bits_per_pixel;
+ aSrcBuf.mnScanlineSize = pImage->bytes_per_line;
+ aSrcBuf.mpBits = (sal_uInt8*) pImage->data;
+
+ pImage->red_mask = pSalDisp->GetVisual( nScreen ).red_mask;
+ pImage->green_mask = pSalDisp->GetVisual( nScreen ).green_mask;
+ pImage->blue_mask = pSalDisp->GetVisual( nScreen ).blue_mask;
+
+ switch( aSrcBuf.mnBitCount )
+ {
+ case( 1 ):
+ {
+ aSrcBuf.mnFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_1BIT_LSB_PAL : BMP_FORMAT_1BIT_MSB_PAL );
+ nDstFormat |= BMP_FORMAT_1BIT_MSB_PAL;
+ }
+ break;
+
+ case( 4 ):
+ {
+ aSrcBuf.mnFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_4BIT_LSN_PAL : BMP_FORMAT_4BIT_MSN_PAL );
+ nDstFormat |= BMP_FORMAT_4BIT_MSN_PAL;
+ }
+ break;
+
+ case( 8 ):
+ {
+ aSrcBuf.mnFormat |= BMP_FORMAT_8BIT_PAL;
+ nDstFormat |= BMP_FORMAT_8BIT_PAL;
+ }
+ break;
+
+ case( 16 ):
+ {
+ nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ aSrcBuf.maColorMask = ColorMask( pImage->red_mask, pImage->green_mask, pImage->blue_mask );
+
+ if( LSBFirst == pImage->byte_order )
+ {
+ aSrcBuf.mnFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK;
+ }
+ else
+ {
+ aSrcBuf.mnFormat |= BMP_FORMAT_16BIT_TC_MSB_MASK;
+ // aSrcBuf.maColorMask = ColorMask( pImage->red_mask ), SWAPSHORT( pImage->green_mask ), SWAPSHORT( pImage->blue_mask ) );
+ }
+ }
+ break;
+
+ case( 24 ):
+ {
+ if( ( LSBFirst == pImage->byte_order ) && ( pImage->red_mask == 0xFF ) )
+ aSrcBuf.mnFormat |= BMP_FORMAT_24BIT_TC_RGB;
+ else
+ aSrcBuf.mnFormat |= BMP_FORMAT_24BIT_TC_BGR;
+
+ nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ }
+ break;
+
+ case( 32 ):
+ {
+ if( LSBFirst == pImage->byte_order )
+ aSrcBuf.mnFormat |= ( pSalDisp->GetVisual(nScreen).red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_RGBA : BMP_FORMAT_32BIT_TC_BGRA );
+ else
+ aSrcBuf.mnFormat |= ( pSalDisp->GetVisual(nScreen).red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_ABGR : BMP_FORMAT_32BIT_TC_ARGB );
+
+ nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ }
+ break;
+ }
+
+ BitmapPalette& rPal = aSrcBuf.maPalette;
+
+ if( aSrcBuf.mnBitCount == 1 )
+ {
+ rPal.SetEntryCount( 2 );
+ pDstPal = &rPal;
+
+ rPal[ 0 ] = Color( COL_BLACK );
+ rPal[ 1 ] = Color( COL_WHITE );
+ }
+ else if( pImage->depth == 8 && bGrey )
+ {
+ rPal.SetEntryCount( 256 );
+ pDstPal = &rPal;
+
+ for( sal_uInt16 i = 0; i < 256; i++ )
+ {
+ BitmapColor& rBmpCol = rPal[ i ];
+
+ rBmpCol.SetRed( i );
+ rBmpCol.SetGreen( i );
+ rBmpCol.SetBlue( i );
+ }
+
+ }
+ else if( aSrcBuf.mnBitCount <= 8 )
+ {
+ const SalColormap& rColMap = pSalDisp->GetColormap( nScreen );
+ const sal_uInt16 nCols = Min( (sal_uLong)rColMap.GetUsed(), (sal_uLong)(1 << nDrawableDepth) );
+
+ rPal.SetEntryCount( nCols );
+ pDstPal = &rPal;
+
+ for( sal_uInt16 i = 0; i < nCols; i++ )
+ {
+ const SalColor nColor( rColMap.GetColor( i ) );
+ BitmapColor& rBmpCol = rPal[ i ];
+
+ rBmpCol.SetRed( SALCOLOR_RED( nColor ) );
+ rBmpCol.SetGreen( SALCOLOR_GREEN( nColor ) );
+ rBmpCol.SetBlue( SALCOLOR_BLUE( nColor ) );
+ }
+ }
+
+ nDstFormat = aSrcBuf.mnFormat;
+ pDIB = StretchAndConvert( aSrcBuf, aTwoRect, nDstFormat,
+ const_cast<BitmapPalette*>(pDstPal), &aSrcBuf.maColorMask );
+ XDestroyImage( pImage );
+ }
+ }
+
+ return pDIB;
+}
+
+// -----------------------------------------------------------------------------
+
+XImage* X11SalBitmap::ImplCreateXImage( SalDisplay *pSalDisp, int nScreen, long nDepth, const SalTwoRect& rTwoRect ) const
+{
+ XImage* pImage = NULL;
+
+ if( !mpDIB && mpDDB )
+ {
+ const_cast<X11SalBitmap*>(this)->mpDIB =
+ ImplCreateDIB( mpDDB->ImplGetPixmap(),
+ mpDDB->ImplGetScreen(),
+ mpDDB->ImplGetDepth(),
+ 0, 0,
+ mpDDB->ImplGetWidth(),
+ mpDDB->ImplGetHeight(),
+ mbGrey );
+ }
+
+ if( mpDIB && mpDIB->mnWidth && mpDIB->mnHeight )
+ {
+ Display* pXDisp = pSalDisp->GetDisplay();
+ long nWidth = rTwoRect.mnDestWidth;
+ long nHeight = rTwoRect.mnDestHeight;
+
+ if( 1 == GetBitCount() )
+ nDepth = 1;
+
+ pImage = XCreateImage( pXDisp, pSalDisp->GetVisual( nScreen ).GetVisual(),
+ nDepth, ( 1 == nDepth ) ? XYBitmap :ZPixmap, 0, NULL,
+ nWidth, nHeight, 32, 0 );
+
+ if( pImage )
+ {
+ BitmapBuffer* pDstBuf;
+ sal_uLong nDstFormat = BMP_FORMAT_TOP_DOWN;
+ BitmapPalette* pPal = NULL;
+ ColorMask* pMask = NULL;
+
+ switch( pImage->bits_per_pixel )
+ {
+ case( 1 ):
+ nDstFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_1BIT_LSB_PAL : BMP_FORMAT_1BIT_MSB_PAL );
+ break;
+
+ case( 4 ):
+ nDstFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_4BIT_LSN_PAL : BMP_FORMAT_4BIT_MSN_PAL );
+ break;
+
+ case( 8 ):
+ nDstFormat |= BMP_FORMAT_8BIT_PAL;
+ break;
+
+ case( 16 ):
+ {
+ #ifdef OSL_BIGENDIAN
+
+ if( MSBFirst == pImage->byte_order )
+ nDstFormat |= BMP_FORMAT_16BIT_TC_MSB_MASK;
+ else
+ nDstFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK;
+
+ #else /* OSL_LITENDIAN */
+
+ nDstFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK;
+ if( MSBFirst == pImage->byte_order )
+ pImage->byte_order = LSBFirst;
+
+ #endif
+
+ pMask = new ColorMask( pImage->red_mask, pImage->green_mask, pImage->blue_mask );
+ }
+ break;
+
+ case( 24 ):
+ {
+ if( ( LSBFirst == pImage->byte_order ) && ( pImage->red_mask == 0xFF ) )
+ nDstFormat |= BMP_FORMAT_24BIT_TC_RGB;
+ else
+ nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ }
+ break;
+
+ case( 32 ):
+ {
+ if( LSBFirst == pImage->byte_order )
+ nDstFormat |= ( pImage->red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_RGBA : BMP_FORMAT_32BIT_TC_BGRA );
+ else
+ nDstFormat |= ( pImage->red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_ABGR : BMP_FORMAT_32BIT_TC_ARGB );
+ }
+ break;
+ }
+
+ if( pImage->depth == 1 )
+ {
+ pPal = new BitmapPalette( 2 );
+ (*pPal)[ 0 ] = Color( COL_BLACK );
+ (*pPal)[ 1 ] = Color( COL_WHITE );
+ }
+ else if( pImage->depth == 8 && mbGrey )
+ {
+ pPal = new BitmapPalette( 256 );
+
+ for( sal_uInt16 i = 0; i < 256; i++ )
+ {
+ BitmapColor& rBmpCol = (*pPal)[ i ];
+
+ rBmpCol.SetRed( i );
+ rBmpCol.SetGreen( i );
+ rBmpCol.SetBlue( i );
+ }
+
+ }
+ else if( pImage->depth <= 8 )
+ {
+ const SalColormap& rColMap = pSalDisp->GetColormap( nScreen );
+ const sal_uInt16 nCols = Min( (sal_uLong)rColMap.GetUsed(), (sal_uLong)(1 << pImage->depth) );
+
+ pPal = new BitmapPalette( nCols );
+
+ for( sal_uInt16 i = 0; i < nCols; i++ )
+ {
+ const SalColor nColor( rColMap.GetColor( i ) );
+ BitmapColor& rBmpCol = (*pPal)[ i ];
+
+ rBmpCol.SetRed( SALCOLOR_RED( nColor ) );
+ rBmpCol.SetGreen( SALCOLOR_GREEN( nColor ) );
+ rBmpCol.SetBlue( SALCOLOR_BLUE( nColor ) );
+ }
+ }
+
+ pDstBuf = StretchAndConvert( *mpDIB, rTwoRect, nDstFormat, pPal, pMask );
+ delete pPal;
+ delete pMask;
+
+ if( pDstBuf && pDstBuf->mpBits )
+ {
+ // set data in buffer as data member in pImage
+ pImage->data = (char*) pDstBuf->mpBits;
+
+ // destroy buffer; don't destroy allocated data in buffer
+ delete pDstBuf;
+ }
+ else
+ {
+ XDestroyImage( pImage );
+ pImage = NULL;
+ }
+ }
+ }
+
+ return pImage;
+}
+
+// -----------------------------------------------------------------------------
+bool X11SalBitmap::ImplCreateFromDrawable( Drawable aDrawable,
+ int nScreen, long nDrawableDepth,
+ long nX, long nY, long nWidth, long nHeight )
+{
+ Destroy();
+
+ if( aDrawable && nWidth && nHeight && nDrawableDepth )
+ mpDDB = new ImplSalDDB( aDrawable, nScreen, nDrawableDepth, nX, nY, nWidth, nHeight );
+
+ return( mpDDB != NULL );
+}
+// -----------------------------------------------------------------------------
+
+bool
+X11SalBitmap::SnapShot (Display* pDisplay, XLIB_Window hWindow)
+{
+ if (hWindow != None)
+ {
+ XWindowAttributes aAttribute;
+ XGetWindowAttributes (pDisplay, hWindow, &aAttribute);
+ if (aAttribute.map_state == IsViewable)
+ {
+ // get coordinates relative to root window
+ XLIB_Window hPetitFleur;
+ int nRootX, nRootY;
+
+ if (XTranslateCoordinates (pDisplay, hWindow, aAttribute.root,
+ 0, 0, &nRootX, &nRootY, &hPetitFleur))
+ {
+ XWindowAttributes aRootAttribute;
+ XGetWindowAttributes (pDisplay, aAttribute.root, &aRootAttribute);
+
+ int width = aAttribute.width;
+ int height = aAttribute.height;
+ int x = nRootX;
+ int y = nRootY;
+
+ // horizontal range check
+ if (x < 0)
+ {
+ width = width + x;
+ x = 0;
+ }
+ else
+ if (x > aRootAttribute.width)
+ {
+ width = 0;
+ x = aRootAttribute.width;
+ }
+ else
+ if (x + width > aRootAttribute.width)
+ {
+ width = aRootAttribute.width - x;
+ }
+
+ // vertical range check
+ if (y < 0)
+ {
+ height = height + y;
+ y = 0;
+ }
+ else
+ if (y > aRootAttribute.height)
+ {
+ height = 0;
+ y = aRootAttribute.height;
+ }
+ else
+ if (y + height > aRootAttribute.height)
+ {
+ height = aRootAttribute.height - y;
+ }
+
+ if ((width > 0) && (height > 0))
+ {
+ XImage* pImage = XGetImage( pDisplay, aAttribute.root,
+ x, y, width, height, AllPlanes, ZPixmap );
+ bool bSnapShot = ImplCreateFromXImage( pDisplay,
+ aAttribute.root,
+ XScreenNumberOfScreen( aAttribute.screen ),
+ pImage );
+ XDestroyImage (pImage);
+
+ return bSnapShot;
+ }
+ }
+ }
+ }
+
+ return False;
+}
+
+bool
+X11SalBitmap::ImplCreateFromXImage (Display* pDisplay, XLIB_Window hWindow, int nScreen, XImage* pImage)
+{
+ Destroy();
+
+ if (pImage != NULL && pImage->width != 0 && pImage->height != 0 && pImage->depth != 0)
+ {
+ mpDDB = new ImplSalDDB (pDisplay, hWindow, nScreen, pImage);
+ return True;
+ }
+ return False;
+}
+
+ImplSalDDB* X11SalBitmap::ImplGetDDB( Drawable aDrawable,
+ int nScreen,
+ long nDrawableDepth,
+ const SalTwoRect& rTwoRect ) const
+{
+ if( !mpDDB || !mpDDB->ImplMatches( nScreen, nDrawableDepth, rTwoRect ) )
+ {
+ if( mpDDB )
+ {
+ // do we already have a DIB? if not, create aDIB from current DDB first
+ if( !mpDIB )
+ {
+ const_cast<X11SalBitmap*>(this)->mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(),
+ mpDDB->ImplGetScreen(),
+ mpDDB->ImplGetDepth(),
+ 0, 0,
+ mpDDB->ImplGetWidth(),
+ mpDDB->ImplGetHeight(),
+ mbGrey );
+ }
+
+ delete mpDDB, const_cast<X11SalBitmap*>(this)->mpDDB = NULL;
+ }
+
+ if( mpCache )
+ mpCache->ImplRemove( const_cast<X11SalBitmap*>(this) );
+
+ SalTwoRect aTwoRect( rTwoRect );
+ if( aTwoRect.mnSrcX < 0 )
+ {
+ aTwoRect.mnSrcWidth += aTwoRect.mnSrcX;
+ aTwoRect.mnSrcX = 0;
+ }
+ if( aTwoRect.mnSrcY < 0 )
+ {
+ aTwoRect.mnSrcHeight += aTwoRect.mnSrcY;
+ aTwoRect.mnSrcY = 0;
+ }
+
+ // create new DDB from DIB
+ const Size aSize( GetSize() );
+ if( aTwoRect.mnSrcWidth == aTwoRect.mnDestWidth &&
+ aTwoRect.mnSrcHeight == aTwoRect.mnDestHeight )
+ {
+ aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
+ aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width();
+ aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height();
+ }
+ else if( aTwoRect.mnSrcWidth+aTwoRect.mnSrcX > aSize.Width() ||
+ aTwoRect.mnSrcHeight+aTwoRect.mnSrcY > aSize.Height() )
+ {
+ // #i47823# this should not happen at all, but does nonetheless
+ // because BitmapEx allows for mask bitmaps of different size
+ // than image bitmap (broken)
+ if( aTwoRect.mnSrcX >= aSize.Width() ||
+ aTwoRect.mnSrcY >= aSize.Height() )
+ return NULL; // this would be a really mad case
+
+ if( aTwoRect.mnSrcWidth+aTwoRect.mnSrcX > aSize.Width() )
+ {
+ aTwoRect.mnSrcWidth = aSize.Width()-aTwoRect.mnSrcX;
+ if( aTwoRect.mnSrcWidth < 1 )
+ {
+ aTwoRect.mnSrcX = 0;
+ aTwoRect.mnSrcWidth = aSize.Width();
+ }
+ }
+ if( aTwoRect.mnSrcHeight+aTwoRect.mnSrcY > aSize.Height() )
+ {
+ aTwoRect.mnSrcHeight = aSize.Height() - aTwoRect.mnSrcY;
+ if( aTwoRect.mnSrcHeight < 1 )
+ {
+ aTwoRect.mnSrcY = 0;
+ aTwoRect.mnSrcHeight = aSize.Height();
+ }
+ }
+ }
+
+ XImage* pImage = ImplCreateXImage( GetX11SalData()->GetDisplay(), nScreen,
+ nDrawableDepth, aTwoRect );
+
+ if( pImage )
+ {
+ const_cast<X11SalBitmap*>(this)->mpDDB = new ImplSalDDB( pImage, aDrawable, nScreen, aTwoRect );
+ delete[] pImage->data, pImage->data = NULL;
+ XDestroyImage( pImage );
+
+ if( mpCache )
+ mpCache->ImplAdd( const_cast<X11SalBitmap*>(this), mpDDB->ImplGetMemSize() );
+ }
+ }
+
+ return mpDDB;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ImplDraw( Drawable aDrawable,
+ int nScreen,
+ long nDrawableDepth,
+ const SalTwoRect& rTwoRect,
+ const GC& rGC ) const
+{
+ ImplGetDDB( aDrawable, nScreen, nDrawableDepth, rTwoRect );
+ if( mpDDB )
+ mpDDB->ImplDraw( aDrawable, nDrawableDepth, rTwoRect, rGC );
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
+{
+ Destroy();
+ mpDIB = ImplCreateDIB( rSize, nBitCount, rPal );
+
+ return( mpDIB != NULL );
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const SalBitmap& rSSalBmp )
+{
+ Destroy();
+
+ const X11SalBitmap& rSalBmp = static_cast<const X11SalBitmap&>( rSSalBmp );
+
+ if( rSalBmp.mpDIB )
+ {
+ // TODO: reference counting...
+ mpDIB = new BitmapBuffer( *rSalBmp.mpDIB );
+ // TODO: get rid of this when BitmapBuffer gets copy constructor
+ try
+ {
+ mpDIB->mpBits = new sal_uInt8[ mpDIB->mnScanlineSize * mpDIB->mnHeight ];
+ }
+ catch( std::bad_alloc& )
+ {
+ delete mpDIB;
+ mpDIB = NULL;
+ }
+
+ if( mpDIB )
+ memcpy( mpDIB->mpBits, rSalBmp.mpDIB->mpBits, mpDIB->mnScanlineSize * mpDIB->mnHeight );
+ }
+ else if( rSalBmp.mpDDB )
+ ImplCreateFromDrawable( rSalBmp.mpDDB->ImplGetPixmap(),
+ rSalBmp.mpDDB->ImplGetScreen(),
+ rSalBmp.mpDDB->ImplGetDepth(),
+ 0, 0, rSalBmp.mpDDB->ImplGetWidth(), rSalBmp.mpDDB->ImplGetHeight() );
+
+ return( ( !rSalBmp.mpDIB && !rSalBmp.mpDDB ) ||
+ ( rSalBmp.mpDIB && ( mpDIB != NULL ) ) ||
+ ( rSalBmp.mpDDB && ( mpDDB != NULL ) ) );
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const SalBitmap&, SalGraphics* )
+{
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const SalBitmap&, sal_uInt16 )
+{
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas > xBitmapCanvas, Size& rSize, bool bMask )
+{
+ ::com::sun::star::uno::Reference< ::com::sun::star::beans::XFastPropertySet > xFastPropertySet( xBitmapCanvas, ::com::sun::star::uno::UNO_QUERY );
+ if( xFastPropertySet.get() ) {
+ sal_Int32 depth;
+ ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > args;
+
+ if( xFastPropertySet->getFastPropertyValue(bMask ? 2 : 1) >>= args ) {
+ long pixmapHandle;
+ if( ( args[1] >>= pixmapHandle ) && ( args[2] >>= depth ) ) {
+
+ mbGrey = bMask;
+ bool bSuccess = ImplCreateFromDrawable( pixmapHandle, 0, depth, 0, 0, (long) rSize.Width(), (long) rSize.Height() );
+ bool bFreePixmap;
+ if( bSuccess && (args[0] >>= bFreePixmap) && bFreePixmap )
+ XFreePixmap( GetX11SalData()->GetDisplay()->GetDisplay(), pixmapHandle );
+
+ return bSuccess;
+ }
+ }
+ }
+
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::Destroy()
+{
+ if( mpDIB )
+ {
+ delete[] mpDIB->mpBits;
+ delete mpDIB, mpDIB = NULL;
+ }
+
+ if( mpDDB )
+ delete mpDDB, mpDDB = NULL;
+
+ if( mpCache )
+ mpCache->ImplRemove( this );
+}
+
+// -----------------------------------------------------------------------------
+
+Size X11SalBitmap::GetSize() const
+{
+ Size aSize;
+
+ if( mpDIB )
+ aSize.Width() = mpDIB->mnWidth, aSize.Height() = mpDIB->mnHeight;
+ else if( mpDDB )
+ aSize.Width() = mpDDB->ImplGetWidth(), aSize.Height() = mpDDB->ImplGetHeight();
+
+ return aSize;
+}
+
+// -----------------------------------------------------------------------------
+
+sal_uInt16 X11SalBitmap::GetBitCount() const
+{
+ sal_uInt16 nBitCount;
+
+ if( mpDIB )
+ nBitCount = mpDIB->mnBitCount;
+ else if( mpDDB )
+ nBitCount = mpDDB->ImplGetDepth();
+ else
+ nBitCount = 0;
+
+ return nBitCount;
+}
+
+// -----------------------------------------------------------------------------
+
+BitmapBuffer* X11SalBitmap::AcquireBuffer( bool )
+{
+ if( !mpDIB && mpDDB )
+ {
+ mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(),
+ mpDDB->ImplGetScreen(),
+ mpDDB->ImplGetDepth(),
+ 0, 0, mpDDB->ImplGetWidth(), mpDDB->ImplGetHeight(), mbGrey );
+ }
+
+ return mpDIB;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ReleaseBuffer( BitmapBuffer*, bool bReadOnly )
+{
+ if( !bReadOnly )
+ {
+ if( mpDDB )
+ delete mpDDB, mpDDB = NULL;
+
+ if( mpCache )
+ mpCache->ImplRemove( this );
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::GetSystemData( BitmapSystemData& rData )
+{
+ if( mpDDB )
+ {
+ // Rename/retype pDummy to your likings (though X11 Pixmap is
+ // prolly not a good idea, since it's accessed from
+ // non-platform aware code in vcl/bitmap.hxx)
+ rData.aPixmap = (void*)mpDDB->ImplGetPixmap();
+ rData.mnWidth = mpDDB->ImplGetWidth ();
+ rData.mnHeight = mpDDB->ImplGetHeight ();
+ return true;
+ }
+
+ return false;
+}
+
+// --------------
+// - ImplSalDDB -
+// --------------
+
+ImplSalDDB::ImplSalDDB( XImage* pImage, Drawable aDrawable, int nScreen, const SalTwoRect& rTwoRect ) :
+ maPixmap ( 0 ),
+ maTwoRect ( rTwoRect ),
+ mnDepth ( pImage->depth ),
+ mnScreen ( nScreen )
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+
+ if( (maPixmap = XCreatePixmap( pXDisp, aDrawable, ImplGetWidth(), ImplGetHeight(), ImplGetDepth() )) )
+ {
+ XGCValues aValues;
+ GC aGC;
+ int nValues = GCFunction;
+
+ aValues.function = GXcopy;
+
+ if( 1 == mnDepth )
+ {
+ nValues |= ( GCForeground | GCBackground );
+ aValues.foreground = 1, aValues.background = 0;
+ }
+
+ aGC = XCreateGC( pXDisp, maPixmap, nValues, &aValues );
+ XPutImage( pXDisp, maPixmap, aGC, pImage, 0, 0, 0, 0, maTwoRect.mnDestWidth, maTwoRect.mnDestHeight );
+ XFreeGC( pXDisp, aGC );
+ }
+}
+
+// -----------------------------------------------------------------------------------------
+// create from XImage
+
+ImplSalDDB::ImplSalDDB (Display* pDisplay, XLIB_Window hWindow, int nScreen, XImage* pImage) :
+ mnScreen( nScreen )
+{
+ maPixmap = XCreatePixmap (pDisplay, hWindow, pImage->width, pImage->height, pImage->depth);
+ if (maPixmap != 0)
+ {
+ XGCValues aValues;
+ GC aGC;
+ int nValues = GCFunction;
+
+ aValues.function = GXcopy;
+
+ if (pImage->depth == 1)
+ {
+ nValues |= ( GCForeground | GCBackground );
+ aValues.foreground = 1;
+ aValues.background = 0;
+ }
+
+ aGC = XCreateGC (pDisplay, maPixmap, nValues, &aValues);
+ XPutImage (pDisplay, maPixmap, aGC, pImage, 0, 0, 0, 0, pImage->width, pImage->height);
+ XFreeGC (pDisplay, aGC);
+
+ maTwoRect.mnSrcX = 0;
+ maTwoRect.mnSrcY = 0;
+ maTwoRect.mnDestX = 0;
+ maTwoRect.mnDestY = 0;
+ maTwoRect.mnSrcWidth = pImage->width;
+ maTwoRect.mnDestWidth = pImage->width;
+ maTwoRect.mnSrcHeight = pImage->height;
+ maTwoRect.mnDestHeight = pImage->height;
+
+ mnDepth = pImage->depth;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+ImplSalDDB::ImplSalDDB( Drawable aDrawable, int nScreen, long nDrawableDepth, long nX, long nY, long nWidth, long nHeight ) :
+ mnDepth( nDrawableDepth ),
+ mnScreen( nScreen )
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+
+ if( (maPixmap = XCreatePixmap( pXDisp, aDrawable, nWidth, nHeight, nDrawableDepth )) )
+ {
+ XGCValues aValues;
+ GC aGC;
+ int nValues = GCFunction;
+
+ aValues.function = GXcopy;
+
+ if( 1 == mnDepth )
+ {
+ nValues |= ( GCForeground | GCBackground );
+ aValues.foreground = 1, aValues.background = 0;
+ }
+
+ aGC = XCreateGC( pXDisp, maPixmap, nValues, &aValues );
+ ImplDraw( aDrawable, nDrawableDepth, maPixmap, mnDepth,
+ nX, nY, nWidth, nHeight, 0, 0, aGC );
+ XFreeGC( pXDisp, aGC );
+
+ maTwoRect.mnSrcX = maTwoRect.mnSrcY = maTwoRect.mnDestX = maTwoRect.mnDestY = 0;
+ maTwoRect.mnSrcWidth = maTwoRect.mnDestWidth = nWidth;
+ maTwoRect.mnSrcHeight = maTwoRect.mnDestHeight = nHeight;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+ImplSalDDB::~ImplSalDDB()
+{
+ if( maPixmap && ImplGetSVData() )
+ XFreePixmap( GetX11SalData()->GetDisplay()->GetDisplay(), maPixmap );
+}
+
+// -----------------------------------------------------------------------------
+
+bool ImplSalDDB::ImplMatches( int nScreen, long nDepth, const SalTwoRect& rTwoRect ) const
+{
+ bool bRet = sal_False;
+
+ if( ( maPixmap != 0 ) && ( ( mnDepth == nDepth ) || ( 1 == mnDepth ) ) && nScreen == mnScreen)
+ {
+ if( rTwoRect.mnSrcX == maTwoRect.mnSrcX && rTwoRect.mnSrcY == maTwoRect.mnSrcY &&
+ rTwoRect.mnSrcWidth == maTwoRect.mnSrcWidth && rTwoRect.mnSrcHeight == maTwoRect.mnSrcHeight &&
+ rTwoRect.mnDestWidth == maTwoRect.mnDestWidth && rTwoRect.mnDestHeight == maTwoRect.mnDestHeight )
+ {
+ // absolutely indentically
+ bRet = sal_True;
+ }
+ else if( rTwoRect.mnSrcWidth == rTwoRect.mnDestWidth && rTwoRect.mnSrcHeight == rTwoRect.mnDestHeight &&
+ maTwoRect.mnSrcWidth == maTwoRect.mnDestWidth && maTwoRect.mnSrcHeight == maTwoRect.mnDestHeight &&
+ rTwoRect.mnSrcX >= maTwoRect.mnSrcX && rTwoRect.mnSrcY >= maTwoRect.mnSrcY &&
+ ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) <= ( maTwoRect.mnSrcX + maTwoRect.mnSrcWidth ) &&
+ ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) <= ( maTwoRect.mnSrcY + maTwoRect.mnSrcHeight ) )
+ {
+ bRet = sal_True;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalDDB::ImplDraw( Drawable aDrawable, long nDrawableDepth, const SalTwoRect& rTwoRect, const GC& rGC ) const
+{
+ ImplDraw( maPixmap, mnDepth, aDrawable, nDrawableDepth,
+ rTwoRect.mnSrcX - maTwoRect.mnSrcX, rTwoRect.mnSrcY - maTwoRect.mnSrcY,
+ rTwoRect.mnDestWidth, rTwoRect.mnDestHeight,
+ rTwoRect.mnDestX, rTwoRect.mnDestY, rGC );
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalDDB::ImplDraw( Drawable aSrcDrawable, long nSrcDrawableDepth,
+ Drawable aDstDrawable, long,
+ long nSrcX, long nSrcY,
+ long nDestWidth, long nDestHeight,
+ long nDestX, long nDestY, const GC& rGC )
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+
+ if( 1 == nSrcDrawableDepth )
+ {
+ XCopyPlane( pXDisp, aSrcDrawable, aDstDrawable, rGC,
+ nSrcX, nSrcY, nDestWidth, nDestHeight, nDestX, nDestY, 1 );
+ }
+ else
+ {
+ XCopyArea( pXDisp, aSrcDrawable, aDstDrawable, rGC,
+ nSrcX, nSrcY, nDestWidth, nDestHeight, nDestX, nDestY );
+ }
+}
+
+// ----------------------
+// - ImplSalBitmapCache -
+// ----------------------
+
+struct ImplBmpObj
+{
+ X11SalBitmap* mpBmp;
+ sal_uLong mnMemSize;
+ sal_uLong mnFlags;
+
+ ImplBmpObj( X11SalBitmap* pBmp, sal_uLong nMemSize, sal_uLong nFlags ) :
+ mpBmp( pBmp ), mnMemSize( nMemSize ), mnFlags( nFlags ) {}
+};
+
+// -----------------------------------------------------------------------------
+
+ImplSalBitmapCache::ImplSalBitmapCache() :
+ mnTotalSize( 0UL )
+{
+}
+
+// -----------------------------------------------------------------------------
+
+ImplSalBitmapCache::~ImplSalBitmapCache()
+{
+ ImplClear();
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalBitmapCache::ImplAdd( X11SalBitmap* pBmp, sal_uLong nMemSize, sal_uLong nFlags )
+{
+ ImplBmpObj* pObj;
+ bool bFound = sal_False;
+
+ for( pObj = (ImplBmpObj*) maBmpList.Last(); pObj && !bFound; pObj = (ImplBmpObj*) maBmpList.Prev() )
+ if( pObj->mpBmp == pBmp )
+ bFound = sal_True;
+
+ mnTotalSize += nMemSize;
+
+ if( bFound )
+ {
+ mnTotalSize -= pObj->mnMemSize;
+ pObj->mnMemSize = nMemSize, pObj->mnFlags = nFlags;
+ }
+ else
+ maBmpList.Insert( new ImplBmpObj( pBmp, nMemSize, nFlags ), LIST_APPEND );
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalBitmapCache::ImplRemove( X11SalBitmap* pBmp )
+{
+ for( ImplBmpObj* pObj = (ImplBmpObj*) maBmpList.Last(); pObj; pObj = (ImplBmpObj*) maBmpList.Prev() )
+ {
+ if( pObj->mpBmp == pBmp )
+ {
+ maBmpList.Remove( pObj );
+ pObj->mpBmp->ImplRemovedFromCache();
+ mnTotalSize -= pObj->mnMemSize;
+ delete pObj;
+ break;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalBitmapCache::ImplClear()
+{
+ for( ImplBmpObj* pObj = (ImplBmpObj*) maBmpList.First(); pObj; pObj = (ImplBmpObj*) maBmpList.Next() )
+ {
+ pObj->mpBmp->ImplRemovedFromCache();
+ delete pObj;
+ }
+
+ maBmpList.Clear();
+ mnTotalSize = 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/salcvt.cxx b/vcl/unx/generic/gdi/salcvt.cxx
new file mode 100644
index 000000000000..f757f3fc0ab3
--- /dev/null
+++ b/vcl/unx/generic/gdi/salcvt.cxx
@@ -0,0 +1,343 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 "salcvt.hxx"
+
+
+SalConverterCache::SalConverterCache()
+{
+}
+
+SalConverterCache*
+SalConverterCache::GetInstance ()
+{
+ static SalConverterCache* pCvt = NULL;
+ if (pCvt == NULL)
+ pCvt = new SalConverterCache;
+
+ return pCvt;
+}
+
+SalConverterCache::~SalConverterCache()
+{
+}
+
+// ---> FIXME
+#include <stdio.h>
+// <---
+
+rtl_UnicodeToTextConverter
+SalConverterCache::GetU2TConverter( rtl_TextEncoding nEncoding )
+{
+ if( rtl_isOctetTextEncoding( nEncoding ) )
+ {
+ ConverterT& rConverter( m_aConverters[ nEncoding ] );
+ if ( rConverter.mpU2T == NULL )
+ {
+ rConverter.mpU2T =
+ rtl_createUnicodeToTextConverter( nEncoding );
+// ---> FIXME
+if ( rConverter.mpU2T == NULL )
+ fprintf( stderr, "failed to create Unicode -> %i converter\n", nEncoding);
+// <---
+ }
+ return rConverter.mpU2T;
+ }
+ return NULL;
+}
+
+rtl_TextToUnicodeConverter
+SalConverterCache::GetT2UConverter( rtl_TextEncoding nEncoding )
+{
+ if( rtl_isOctetTextEncoding( nEncoding ) )
+ {
+ ConverterT& rConverter( m_aConverters[ nEncoding ] );
+ if ( rConverter.mpT2U == NULL )
+ {
+ rConverter.mpT2U =
+ rtl_createTextToUnicodeConverter( nEncoding );
+// ---> FIXME
+if ( rConverter.mpT2U == NULL )
+ fprintf( stderr, "failed to create %i -> Unicode converter\n", nEncoding );
+// <---
+ }
+ return rConverter.mpT2U;
+ }
+ return NULL;
+}
+
+Bool
+SalConverterCache::IsSingleByteEncoding( rtl_TextEncoding nEncoding )
+{
+ if( rtl_isOctetTextEncoding( nEncoding ) )
+ {
+ ConverterT& rConverter( m_aConverters[ nEncoding ] );
+ if ( ! rConverter.mbValid )
+ {
+ rConverter.mbValid = True;
+
+ rtl_TextEncodingInfo aTextEncInfo;
+ aTextEncInfo.StructSize = sizeof( aTextEncInfo );
+ rtl_getTextEncodingInfo( nEncoding, &aTextEncInfo );
+
+ if ( aTextEncInfo.MinimumCharSize == aTextEncInfo.MaximumCharSize
+ && aTextEncInfo.MinimumCharSize == 1)
+ rConverter.mbSingleByteEncoding = True;
+ else
+ rConverter.mbSingleByteEncoding = False;
+ }
+
+ return rConverter.mbSingleByteEncoding;
+ }
+ return False;
+}
+
+// check whether the character set nEncoding contains the unicode
+// code point nChar. This list has been compiled from the according
+// ttmap files in /usr/openwin/lib/X11/fonts/TrueType/ttmap/
+Bool
+SalConverterCache::EncodingHasChar( rtl_TextEncoding nEncoding,
+ sal_Unicode nChar )
+{
+ Bool bMatch = False;
+
+ switch ( nEncoding )
+ {
+ case RTL_TEXTENCODING_DONTKNOW:
+ bMatch = False;
+ break;
+
+ case RTL_TEXTENCODING_MS_1252:
+ case RTL_TEXTENCODING_ISO_8859_1:
+ case RTL_TEXTENCODING_ISO_8859_15:
+ // handle iso8859-15 and iso8859-1 the same (and both with euro)
+ // handle them also like ms1252
+ // this is due to the fact that so many X fonts say they are iso8859-1
+ // but have the other glyphs anyway because they are really ms1252
+ bMatch = ( /*nChar >= 0x0000 &&*/ nChar <= 0x00ff )
+ || ( nChar == 0x20ac )
+ || ( nChar == 0x201a )
+ || ( nChar == 0x0192 )
+ || ( nChar == 0x201e )
+ || ( nChar == 0x2026 )
+ || ( nChar == 0x2020 )
+ || ( nChar == 0x2021 )
+ || ( nChar == 0x02c6 )
+ || ( nChar == 0x2030 )
+ || ( nChar == 0x0160 )
+ || ( nChar == 0x2039 )
+ || ( nChar == 0x0152 )
+ || ( nChar == 0x017d )
+ || ( nChar == 0x2018 )
+ || ( nChar == 0x2019 )
+ || ( nChar == 0x201c )
+ || ( nChar == 0x201d )
+ || ( nChar == 0x2022 )
+ || ( nChar == 0x2013 )
+ || ( nChar == 0x2014 )
+ || ( nChar == 0x02dc )
+ || ( nChar == 0x2122 )
+ || ( nChar == 0x0161 )
+ || ( nChar == 0x203a )
+ || ( nChar == 0x0153 )
+ || ( nChar == 0x017e )
+ || ( nChar == 0x0178 )
+ ;
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_2:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x017e )
+ || ( nChar >= 0x02c7 && nChar <= 0x02dd );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_4:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x017e )
+ || ( nChar >= 0x02c7 && nChar <= 0x02db );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_5:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00ad )
+ || ( nChar >= 0x0401 && nChar <= 0x045f )
+ || ( nChar == 0x2116 );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_6:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x0600 && nChar <= 0x06ff )
+ || ( nChar >= 0xfb50 && nChar <= 0xfffe );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_7:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00bd )
+ || ( nChar == 0x02bd )
+ || ( nChar >= 0x0384 && nChar <= 0x03ce )
+ || ( nChar >= 0x2014 && nChar <= 0x2019 );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_8:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00f7 )
+ || ( nChar >= 0x05d0 && nChar <= 0x05ea )
+ || ( nChar == 0x2017 );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_9:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x015f );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_13:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x017e )
+ || ( nChar >= 0x2019 && nChar <= 0x201e );
+ break;
+
+ /* real case for RTL_TEXTENCODING_ISO_8859_15
+ case RTL_TEXTENCODING_ISO_8859_15:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00ff )
+ || ( nChar >= 0x0152 && nChar <= 0x017e )
+ || ( nChar == 0x20ac );
+ break;
+ */
+
+ case RTL_TEXTENCODING_JIS_X_0201:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0xff61 && nChar <= 0xff9f );
+ break;
+
+ case RTL_TEXTENCODING_MS_1251:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00bb )
+ || ( nChar >= 0x0401 && nChar <= 0x045f )
+ || ( nChar >= 0x0490 && nChar <= 0x0491 )
+ || ( nChar >= 0x2013 && nChar <= 0x203a )
+ || ( nChar >= 0x2116 && nChar <= 0x2122 );
+ break;
+
+ case RTL_TEXTENCODING_KOI8_R:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00b7 )
+ || ( nChar == 0x00f7 )
+ || ( nChar >= 0x0401 && nChar <= 0x0451 )
+ || ( nChar >= 0x2219 && nChar <= 0x221a )
+ || ( nChar >= 0x2248 && nChar <= 0x2265 )
+ || ( nChar >= 0x2320 && nChar <= 0x2321 )
+ || ( nChar >= 0x2500 && nChar <= 0x25a0 );
+ break;
+
+ case RTL_TEXTENCODING_UNICODE:
+ bMatch = True;
+ break;
+
+ case RTL_TEXTENCODING_EUC_KR:
+ case RTL_TEXTENCODING_BIG5:
+ case RTL_TEXTENCODING_GBK:
+ case RTL_TEXTENCODING_GB_2312:
+ case RTL_TEXTENCODING_MS_1361:
+ case RTL_TEXTENCODING_JIS_X_0208:
+
+ // XXX Big5 and Korean EUC contain Ascii chars, but Solaris
+ // *-big5-1 and *-ksc5601.1992-3 fonts dont, in general CJK fonts
+ // are monospaced, so dont trust them for latin chars
+ if (nChar <= 0xFF)
+ {
+ bMatch = False;
+ break;
+ }
+
+ default:
+ // XXX really convert the unicode char into the encoding
+ // and check for conversion errors, this is expensive !
+ rtl_UnicodeToTextConverter aConverter;
+ rtl_UnicodeToTextContext aContext;
+
+ aConverter = GetU2TConverter(nEncoding);
+ aContext = rtl_createUnicodeToTextContext( aConverter );
+
+ // ---> FIXME
+ if ( aConverter == NULL )
+ return False;
+ // <---
+
+ sal_Char pConversionBuffer[ 32 ];
+ sal_uInt32 nConversionInfo;
+ sal_Size nConvertedChars;
+ sal_Size nSize;
+
+ nSize = rtl_convertUnicodeToText( aConverter, aContext,
+ &nChar, 1, pConversionBuffer, sizeof(pConversionBuffer),
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR,
+ &nConversionInfo, &nConvertedChars );
+
+ rtl_destroyUnicodeToTextContext( aConverter, aContext );
+
+ bMatch = (nConvertedChars == 1)
+ && (nSize == 1 || nSize == 2) // XXX Fix me this is a hack
+ && ((nConversionInfo & RTL_UNICODETOTEXT_INFO_ERROR) == 0);
+ break;
+ }
+
+ return bMatch;
+}
+
+// wrapper for rtl_convertUnicodeToText that handles the usual cases for
+// textconversion in drawtext and gettextwidth routines
+sal_Size
+SalConverterCache::ConvertStringUTF16( const sal_Unicode *pText, int nTextLen,
+ sal_Char *pBuffer, sal_Size nBufferSize, rtl_TextEncoding nEncoding )
+{
+ rtl_UnicodeToTextConverter aConverter = GetU2TConverter(nEncoding);
+
+ const sal_uInt32 nCvtFlags =
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE
+ | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK ;
+ sal_uInt32 nCvtInfo;
+ sal_Size nCvtChars;
+
+ rtl_UnicodeToTextContext aContext =
+ rtl_createUnicodeToTextContext( aConverter );
+
+ sal_Size nSize = rtl_convertUnicodeToText( aConverter, aContext,
+ pText, nTextLen, pBuffer, nBufferSize,
+ nCvtFlags, &nCvtInfo, &nCvtChars );
+
+ rtl_destroyUnicodeToTextContext( aConverter, aContext );
+
+ return nSize;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/salcvt.hxx b/vcl/unx/generic/gdi/salcvt.hxx
new file mode 100644
index 000000000000..896ae4f30b36
--- /dev/null
+++ b/vcl/unx/generic/gdi/salcvt.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef SAL_CONVERTER_CACHE_HXX_
+#define SAL_CONVERTER_CACHE_HXX_
+
+#include <rtl/tencinfo.h>
+#include <rtl/textcvt.h>
+
+#include <unx/salunx.h>
+
+#include <map>
+
+extern "C" const char*
+pGetEncodingName( rtl_TextEncoding nEncoding );
+
+//
+// Cache TextToUnicode and UnicodeToText converter and conversion info which is
+// used in DrawXYZ routines and in the Event loop
+//
+
+class SalConverterCache {
+
+ public:
+ SalConverterCache();
+ ~SalConverterCache();
+ Bool EncodingHasChar(
+ rtl_TextEncoding nEncoding, sal_Unicode nChar );
+ rtl_UnicodeToTextConverter
+ GetU2TConverter( rtl_TextEncoding nEncoding );
+ rtl_TextToUnicodeConverter
+ GetT2UConverter( rtl_TextEncoding nEncoding );
+ Bool IsSingleByteEncoding( rtl_TextEncoding nEncoding );
+ sal_Size ConvertStringUTF16( const sal_Unicode *pText, int nTextLen,
+ sal_Char *pBuffer, sal_Size nBufferSize,
+ rtl_TextEncoding nEncoding);
+
+ static SalConverterCache*
+ GetInstance ();
+
+ private:
+
+ struct ConverterT {
+ rtl_UnicodeToTextConverter mpU2T;
+ rtl_TextToUnicodeConverter mpT2U;
+ Bool mbSingleByteEncoding;
+ Bool mbValid;
+ ConverterT() :
+ mpU2T( NULL ),
+ mpT2U( NULL ),
+ mbSingleByteEncoding( False ),
+ mbValid( False )
+ {
+ }
+ ~ConverterT()
+ {
+ if( mpU2T )
+ rtl_destroyUnicodeToTextConverter( mpU2T );
+ if( mpT2U )
+ rtl_destroyTextToUnicodeConverter( mpT2U );
+ }
+ };
+
+ std::map< rtl_TextEncoding, ConverterT > m_aConverters;
+};
+
+
+
+#endif /* SAL_CONVERTER_CACHE_HXX_ */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx
new file mode 100644
index 000000000000..b1b8d337430d
--- /dev/null
+++ b/vcl/unx/generic/gdi/salgdi.cxx
@@ -0,0 +1,1247 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 "tools/debug.hxx"
+
+#include "basegfx/polygon/b2dpolygon.hxx"
+#include "basegfx/polygon/b2dpolypolygon.hxx"
+#include "basegfx/polygon/b2dpolypolygontools.hxx"
+#include "basegfx/polygon/b2dpolygontools.hxx"
+#include "basegfx/polygon/b2dpolygonclipper.hxx"
+#include "basegfx/polygon/b2dlinegeometry.hxx"
+#include "basegfx/matrix/b2dhommatrix.hxx"
+#include "basegfx/matrix/b2dhommatrixtools.hxx"
+#include "basegfx/polygon/b2dpolypolygoncutter.hxx"
+#include "basegfx/polygon/b2dtrapezoid.hxx"
+
+#include "vcl/jobdata.hxx"
+
+#include "unx/Xproto.h"
+#include "unx/salunx.h"
+#include "unx/saldata.hxx"
+#include "unx/saldisp.hxx"
+#include "unx/salgdi.h"
+#include "unx/salframe.h"
+#include "unx/salvd.h"
+
+#include "printergfx.hxx"
+#include "xrender_peer.hxx"
+#include "region.h"
+
+#include <vector>
+#include <queue>
+#include <set>
+
+// -=-= SalPolyLine =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#define STATIC_POINTS 64
+
+class SalPolyLine
+{
+ XPoint Points_[STATIC_POINTS];
+ XPoint *pFirst_;
+public:
+ inline SalPolyLine( sal_uLong nPoints );
+ inline SalPolyLine( sal_uLong nPoints, const SalPoint *p );
+ inline ~SalPolyLine();
+ inline XPoint &operator [] ( sal_uLong n ) const
+ { return pFirst_[n]; }
+};
+
+inline SalPolyLine::SalPolyLine( sal_uLong nPoints )
+ : pFirst_( nPoints+1 > STATIC_POINTS ? new XPoint[nPoints+1] : Points_ )
+{}
+
+inline SalPolyLine::SalPolyLine( sal_uLong nPoints, const SalPoint *p )
+ : pFirst_( nPoints+1 > STATIC_POINTS ? new XPoint[nPoints+1] : Points_ )
+{
+ for( sal_uLong i = 0; i < nPoints; i++ )
+ {
+ pFirst_[i].x = (short)p[i].mnX;
+ pFirst_[i].y = (short)p[i].mnY;
+ }
+ pFirst_[nPoints] = pFirst_[0]; // close polyline
+}
+
+inline SalPolyLine::~SalPolyLine()
+{ if( pFirst_ != Points_ ) delete [] pFirst_; }
+
+#undef STATIC_POINTS
+// -=-= X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+X11SalGraphics::X11SalGraphics()
+{
+ m_pFrame = NULL;
+ m_pVDev = NULL;
+ m_pDeleteColormap = NULL;
+ hDrawable_ = None;
+ m_aXRenderPicture = 0;
+ m_pXRenderFormat = NULL;
+
+ mpClipRegion = NULL;
+ pPaintRegion_ = NULL;
+
+ pPenGC_ = NULL;
+ nPenPixel_ = 0;
+ nPenColor_ = MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black
+
+ pFontGC_ = NULL;
+ for( int i = 0; i < MAX_FALLBACK; ++i )
+ mpServerFont[i] = NULL;
+
+ nTextPixel_ = 0;
+ nTextColor_ = MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black
+
+#ifdef ENABLE_GRAPHITE
+ // check if graphite fonts have been disabled
+ static const char* pDisableGraphiteStr = getenv( "SAL_DISABLE_GRAPHITE" );
+ bDisableGraphite_ = pDisableGraphiteStr ? (pDisableGraphiteStr[0]!='0') : sal_False;
+#endif
+
+ pBrushGC_ = NULL;
+ nBrushPixel_ = 0;
+ nBrushColor_ = MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ); // White
+ hBrush_ = None;
+
+ pMonoGC_ = NULL;
+ pCopyGC_ = NULL;
+ pMaskGC_ = NULL;
+ pInvertGC_ = NULL;
+ pInvert50GC_ = NULL;
+ pStippleGC_ = NULL;
+ pTrackingGC_ = NULL;
+
+ bWindow_ = sal_False;
+ bPrinter_ = sal_False;
+ bVirDev_ = sal_False;
+ bPenGC_ = sal_False;
+ bFontGC_ = sal_False;
+ bBrushGC_ = sal_False;
+ bMonoGC_ = sal_False;
+ bCopyGC_ = sal_False;
+ bInvertGC_ = sal_False;
+ bInvert50GC_ = sal_False;
+ bStippleGC_ = sal_False;
+ bTrackingGC_ = sal_False;
+ bXORMode_ = sal_False;
+ bDitherBrush_ = sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+X11SalGraphics::~X11SalGraphics()
+{
+ ReleaseFonts();
+ freeResources();
+}
+
+// -=-= SalGraphics / X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalGraphics::freeResources()
+{
+ Display *pDisplay = GetXDisplay();
+
+ DBG_ASSERT( !pPaintRegion_, "pPaintRegion_" );
+ if( mpClipRegion ) XDestroyRegion( mpClipRegion ), mpClipRegion = None;
+
+ if( hBrush_ ) XFreePixmap( pDisplay, hBrush_ ), hBrush_ = None;
+ if( pPenGC_ ) XFreeGC( pDisplay, pPenGC_ ), pPenGC_ = None;
+ if( pFontGC_ ) XFreeGC( pDisplay, pFontGC_ ), pFontGC_ = None;
+ if( pBrushGC_ ) XFreeGC( pDisplay, pBrushGC_ ), pBrushGC_ = None;
+ if( pMonoGC_ ) XFreeGC( pDisplay, pMonoGC_ ), pMonoGC_ = None;
+ if( pCopyGC_ ) XFreeGC( pDisplay, pCopyGC_ ), pCopyGC_ = None;
+ if( pMaskGC_ ) XFreeGC( pDisplay, pMaskGC_ ), pMaskGC_ = None;
+ if( pInvertGC_ ) XFreeGC( pDisplay, pInvertGC_ ), pInvertGC_ = None;
+ if( pInvert50GC_ ) XFreeGC( pDisplay, pInvert50GC_ ), pInvert50GC_ = None;
+ if( pStippleGC_ ) XFreeGC( pDisplay, pStippleGC_ ), pStippleGC_ = None;
+ if( pTrackingGC_ ) XFreeGC( pDisplay, pTrackingGC_ ), pTrackingGC_ = None;
+ if( m_pDeleteColormap )
+ delete m_pDeleteColormap, m_pColormap = m_pDeleteColormap = NULL;
+
+ if( m_aXRenderPicture )
+ XRenderPeer::GetInstance().FreePicture( m_aXRenderPicture ), m_aXRenderPicture = 0;
+
+ bPenGC_ = bFontGC_ = bBrushGC_ = bMonoGC_ = bCopyGC_ = bInvertGC_ = bInvert50GC_ = bStippleGC_ = bTrackingGC_ = false;
+}
+
+void X11SalGraphics::SetDrawable( Drawable aDrawable, int nScreen )
+{
+ // shortcut if nothing changed
+ if( hDrawable_ == aDrawable )
+ return;
+
+ // free screen specific resources if needed
+ if( nScreen != m_nScreen )
+ {
+ freeResources();
+ m_pColormap = &GetX11SalData()->GetDisplay()->GetColormap( nScreen );
+ m_nScreen = nScreen;
+ }
+
+ hDrawable_ = aDrawable;
+ SetXRenderFormat( NULL );
+ if( m_aXRenderPicture )
+ {
+ XRenderPeer::GetInstance().FreePicture( m_aXRenderPicture );
+ m_aXRenderPicture = 0;
+ }
+
+ if( hDrawable_ )
+ {
+ nPenPixel_ = GetPixel( nPenColor_ );
+ nTextPixel_ = GetPixel( nTextColor_ );
+ nBrushPixel_ = GetPixel( nBrushColor_ );
+ }
+}
+
+void X11SalGraphics::Init( SalFrame *pFrame, Drawable aTarget, int nScreen )
+{
+
+ m_pColormap = &GetX11SalData()->GetDisplay()->GetColormap(nScreen);
+ m_nScreen = nScreen;
+ SetDrawable( aTarget, nScreen );
+
+ bWindow_ = sal_True;
+ m_pFrame = pFrame;
+ m_pVDev = NULL;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::DeInit()
+{
+ SetDrawable( None, m_nScreen );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetClipRegion( GC pGC, XLIB_Region pXReg ) const
+{
+ Display *pDisplay = GetXDisplay();
+
+ int n = 0;
+ XLIB_Region Regions[3];
+
+ if( mpClipRegion )
+ Regions[n++] = mpClipRegion;
+
+ if( pXReg && !XEmptyRegion( pXReg ) )
+ Regions[n++] = pXReg;
+
+ if( 0 == n )
+ XSetClipMask( pDisplay, pGC, None );
+ else if( 1 == n )
+ XSetRegion( pDisplay, pGC, Regions[0] );
+ else
+ {
+ XLIB_Region pTmpRegion = XCreateRegion();
+ XIntersectRegion( Regions[0], Regions[1], pTmpRegion );
+
+ XSetRegion( pDisplay, pGC, pTmpRegion );
+ XDestroyRegion( pTmpRegion );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::SelectPen()
+{
+ Display *pDisplay = GetXDisplay();
+
+ if( !pPenGC_ )
+ {
+ XGCValues values;
+ values.subwindow_mode = ClipByChildren;
+ values.fill_rule = EvenOddRule; // Pict import/ Gradient
+ values.graphics_exposures = False;
+
+ pPenGC_ = XCreateGC( pDisplay, hDrawable_,
+ GCSubwindowMode | GCFillRule | GCGraphicsExposures,
+ &values );
+ }
+
+ if( !bPenGC_ )
+ {
+ if( nPenColor_ != SALCOLOR_NONE )
+ XSetForeground( pDisplay, pPenGC_, nPenPixel_ );
+ XSetFunction ( pDisplay, pPenGC_, bXORMode_ ? GXxor : GXcopy );
+ SetClipRegion( pPenGC_ );
+ bPenGC_ = sal_True;
+ }
+
+ return pPenGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::SelectBrush()
+{
+ Display *pDisplay = GetXDisplay();
+
+ DBG_ASSERT( nBrushColor_ != SALCOLOR_NONE, "Brush Transparent" );
+
+ if( !pBrushGC_ )
+ {
+ XGCValues values;
+ values.subwindow_mode = ClipByChildren;
+ values.fill_rule = EvenOddRule; // Pict import/ Gradient
+ values.graphics_exposures = False;
+
+ pBrushGC_ = XCreateGC( pDisplay, hDrawable_,
+ GCSubwindowMode | GCFillRule | GCGraphicsExposures,
+ &values );
+ }
+
+ if( !bBrushGC_ )
+ {
+ if( !bDitherBrush_ )
+ {
+ XSetFillStyle ( pDisplay, pBrushGC_, FillSolid );
+ XSetForeground( pDisplay, pBrushGC_, nBrushPixel_ );
+ if( bPrinter_ )
+ XSetTile( pDisplay, pBrushGC_, None );
+ }
+ else
+ {
+ // Bug in Sun Solaris 2.5.1, XFillPolygon doesn't allways reflect
+ // changes of the tile. PROPERTY_BUG_Tile doesn't fix this !
+ if (GetDisplay()->GetProperties() & PROPERTY_BUG_FillPolygon_Tile)
+ XSetFillStyle ( pDisplay, pBrushGC_, FillSolid );
+
+ XSetFillStyle ( pDisplay, pBrushGC_, FillTiled );
+ XSetTile ( pDisplay, pBrushGC_, hBrush_ );
+ }
+ XSetFunction ( pDisplay, pBrushGC_, bXORMode_ ? GXxor : GXcopy );
+ SetClipRegion( pBrushGC_ );
+
+ bBrushGC_ = sal_True;
+ }
+
+ return pBrushGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::GetTrackingGC()
+{
+ const char dash_list[2] = {2, 2};
+
+ if( !pTrackingGC_ )
+ {
+ XGCValues values;
+
+ values.graphics_exposures = False;
+ values.foreground = m_pColormap->GetBlackPixel()
+ ^ m_pColormap->GetWhitePixel();
+ values.function = GXxor;
+ values.line_width = 1;
+ values.line_style = LineOnOffDash;
+
+ pTrackingGC_ = XCreateGC( GetXDisplay(), GetDrawable(),
+ GCGraphicsExposures | GCForeground | GCFunction
+ | GCLineWidth | GCLineStyle,
+ &values );
+ XSetDashes( GetXDisplay(), pTrackingGC_, 0, dash_list, 2 );
+ }
+
+ if( !bTrackingGC_ )
+ {
+ SetClipRegion( pTrackingGC_ );
+ bTrackingGC_ = sal_True;
+ }
+
+ return pTrackingGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::DrawLines( sal_uLong nPoints,
+ const SalPolyLine &rPoints,
+ GC pGC,
+ bool bClose
+ )
+{
+ // errechne wie viele Linien XWindow auf einmal zeichnen kann
+ sal_uLong nMaxLines = (GetDisplay()->GetMaxRequestSize() - sizeof(xPolyPointReq))
+ / sizeof(xPoint);
+ if( nMaxLines > nPoints ) nMaxLines = nPoints;
+
+ // gebe alle Linien aus, die XWindows zeichnen kann.
+ sal_uLong n;
+ for( n = 0; nPoints - n > nMaxLines; n += nMaxLines - 1 )
+ XDrawLines( GetXDisplay(),
+ GetDrawable(),
+ pGC,
+ &rPoints[n],
+ nMaxLines,
+ CoordModeOrigin );
+
+ if( n < nPoints )
+ XDrawLines( GetXDisplay(),
+ GetDrawable(),
+ pGC,
+ &rPoints[n],
+ nPoints - n,
+ CoordModeOrigin );
+ if( bClose )
+ {
+ if( rPoints[nPoints-1].x != rPoints[0].x || rPoints[nPoints-1].y != rPoints[0].y )
+ drawLine( rPoints[nPoints-1].x, rPoints[nPoints-1].y, rPoints[0].x, rPoints[0].y );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// Dithern: Calculate a dither-pixmap and make a brush of it
+#define P_DELTA 51
+#define DMAP( v, m ) ((v % P_DELTA) > m ? (v / P_DELTA) + 1 : (v / P_DELTA))
+
+BOOL X11SalGraphics::GetDitherPixmap( SalColor nSalColor )
+{
+ static const short nOrdDither8Bit[ 8 ][ 8 ] =
+ {
+ { 0, 38, 9, 48, 2, 40, 12, 50},
+ {25, 12, 35, 22, 28, 15, 37, 24},
+ { 6, 44, 3, 41, 8, 47, 5, 44},
+ {32, 19, 28, 16, 34, 21, 31, 18},
+ { 1, 40, 11, 49, 0, 39, 10, 48},
+ {27, 14, 36, 24, 26, 13, 36, 23},
+ { 8, 46, 4, 43, 7, 45, 4, 42},
+ {33, 20, 30, 17, 32, 20, 29, 16}
+ };
+
+ // test for correct depth (8bit)
+ if( GetColormap().GetVisual().GetDepth() != 8 )
+ return sal_False;
+
+ char pBits[64];
+ char *pBitsPtr = pBits;
+
+ // Set the pallette-entries for the dithering tile
+ sal_uInt8 nSalColorRed = SALCOLOR_RED ( nSalColor );
+ sal_uInt8 nSalColorGreen = SALCOLOR_GREEN ( nSalColor );
+ sal_uInt8 nSalColorBlue = SALCOLOR_BLUE ( nSalColor );
+
+ for( int nY = 0; nY < 8; nY++ )
+ {
+ for( int nX = 0; nX < 8; nX++ )
+ {
+ short nMagic = nOrdDither8Bit[nY][nX];
+ sal_uInt8 nR = P_DELTA * DMAP( nSalColorRed, nMagic );
+ sal_uInt8 nG = P_DELTA * DMAP( nSalColorGreen, nMagic );
+ sal_uInt8 nB = P_DELTA * DMAP( nSalColorBlue, nMagic );
+
+ *pBitsPtr++ = GetColormap().GetPixel( MAKE_SALCOLOR( nR, nG, nB ) );
+ }
+ }
+
+ // create the tile as ximage and an according pixmap -> caching
+ XImage *pImage = XCreateImage( GetXDisplay(),
+ GetColormap().GetXVisual(),
+ 8,
+ ZPixmap,
+ 0, // offset
+ pBits, // data
+ 8, 8, // width & height
+ 8, // bitmap_pad
+ 0 ); // (default) bytes_per_line
+
+ if ( GetDisplay()->GetProperties() & PROPERTY_BUG_Tile )
+ {
+ if (hBrush_)
+ XFreePixmap (GetXDisplay(), hBrush_);
+ hBrush_ = XCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
+ }
+ else
+ if( !hBrush_ )
+ hBrush_ = XCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
+
+ // put the ximage to the pixmap
+ XPutImage( GetXDisplay(),
+ hBrush_,
+ GetDisplay()->GetCopyGC( m_nScreen ),
+ pImage,
+ 0, 0, // Source
+ 0, 0, // Destination
+ 8, 8 ); // width & height
+
+ // destroy image-frame but not palette-data
+ pImage->data = NULL;
+ XDestroyImage( pImage );
+
+ return sal_True;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY ) // const
+{
+ const SalDisplay *pDisplay = GetDisplay();
+
+ rDPIX = pDisplay->GetResolution().A();
+ rDPIY = pDisplay->GetResolution().B();
+ if( !pDisplay->GetExactResolution() && rDPIY < 96 )
+ {
+ rDPIX = Divide( rDPIX * 96, rDPIY );
+ rDPIY = 96;
+ }
+ else if ( rDPIY > 200 )
+ {
+ rDPIX = Divide( rDPIX * 200, rDPIY );
+ rDPIY = 200;
+ }
+
+ // #i12705# equalize x- and y-resolution if they are close enough
+ if( rDPIX != rDPIY )
+ {
+ // different x- and y- resolutions are usually artifacts of
+ // a wrongly calculated screen size.
+#ifdef DEBUG
+ printf("Forcing Resolution from %" SAL_PRIdINT32 "x%" SAL_PRIdINT32 " to %" SAL_PRIdINT32 "x%" SAL_PRIdINT32 "\n",
+ rDPIX,rDPIY,rDPIY,rDPIY);
+#endif
+ rDPIX = rDPIY; // y-resolution is more trustworthy
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+sal_uInt16 X11SalGraphics::GetBitCount() const
+{
+ return GetVisual().GetDepth();
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalGraphics::GetGraphicsWidth() const
+{
+ if( m_pFrame )
+ return m_pFrame->maGeometry.nWidth;
+ else if( m_pVDev )
+ return m_pVDev->GetWidth();
+ else
+ return 0;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalGraphics::GetGraphicsHeight() const
+{
+ if( m_pFrame )
+ return m_pFrame->maGeometry.nHeight;
+ else if( m_pVDev )
+ return m_pVDev->GetHeight();
+ else
+ return 0;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::ResetClipRegion()
+{
+ if( mpClipRegion )
+ {
+ bPenGC_ = sal_False;
+ bFontGC_ = sal_False;
+ bBrushGC_ = sal_False;
+ bMonoGC_ = sal_False;
+ bCopyGC_ = sal_False;
+ bInvertGC_ = sal_False;
+ bInvert50GC_ = sal_False;
+ bStippleGC_ = sal_False;
+ bTrackingGC_ = sal_False;
+
+ XDestroyRegion( mpClipRegion );
+ mpClipRegion = NULL;
+ }
+}
+
+bool X11SalGraphics::setClipRegion( const Region& i_rClip )
+{
+ if( mpClipRegion )
+ XDestroyRegion( mpClipRegion );
+ mpClipRegion = XCreateRegion();
+
+ ImplRegionInfo aInfo;
+ long nX, nY, nW, nH;
+ bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH );
+ while( bRegionRect )
+ {
+ if ( nW && nH )
+ {
+ XRectangle aRect;
+ aRect.x = (short)nX;
+ aRect.y = (short)nY;
+ aRect.width = (unsigned short)nW;
+ aRect.height = (unsigned short)nH;
+
+ XUnionRectWithRegion( &aRect, mpClipRegion, mpClipRegion );
+ }
+ bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
+ }
+
+ // done, invalidate GCs
+ bPenGC_ = sal_False;
+ bFontGC_ = sal_False;
+ bBrushGC_ = sal_False;
+ bMonoGC_ = sal_False;
+ bCopyGC_ = sal_False;
+ bInvertGC_ = sal_False;
+ bInvert50GC_ = sal_False;
+ bStippleGC_ = sal_False;
+ bTrackingGC_ = sal_False;
+
+ if( XEmptyRegion( mpClipRegion ) )
+ {
+ XDestroyRegion( mpClipRegion );
+ mpClipRegion= NULL;
+ }
+ return true;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetLineColor()
+{
+ if( nPenColor_ != SALCOLOR_NONE )
+ {
+ nPenColor_ = SALCOLOR_NONE;
+ bPenGC_ = sal_False;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetLineColor( SalColor nSalColor )
+{
+ if( nPenColor_ != nSalColor )
+ {
+ nPenColor_ = nSalColor;
+ nPenPixel_ = GetPixel( nSalColor );
+ bPenGC_ = sal_False;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetFillColor()
+{
+ if( nBrushColor_ != SALCOLOR_NONE )
+ {
+ bDitherBrush_ = sal_False;
+ nBrushColor_ = SALCOLOR_NONE;
+ bBrushGC_ = sal_False;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetFillColor( SalColor nSalColor )
+{
+ if( nBrushColor_ != nSalColor )
+ {
+ bDitherBrush_ = sal_False;
+ nBrushColor_ = nSalColor;
+ nBrushPixel_ = GetPixel( nSalColor );
+ if( TrueColor != GetColormap().GetVisual().GetClass()
+ && GetColormap().GetColor( nBrushPixel_ ) != nBrushColor_
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0x00 ) // black
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0x80 ) // blue
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0x80, 0x00 ) // green
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0x80, 0x80 ) // cyan
+ && nSalColor != MAKE_SALCOLOR( 0x80, 0x00, 0x00 ) // red
+ && nSalColor != MAKE_SALCOLOR( 0x80, 0x00, 0x80 ) // magenta
+ && nSalColor != MAKE_SALCOLOR( 0x80, 0x80, 0x00 ) // brown
+ && nSalColor != MAKE_SALCOLOR( 0x80, 0x80, 0x80 ) // gray
+ && nSalColor != MAKE_SALCOLOR( 0xC0, 0xC0, 0xC0 ) // light gray
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0xFF ) // light blue
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0xFF, 0x00 ) // light green
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0xFF, 0xFF ) // light cyan
+ && nSalColor != MAKE_SALCOLOR( 0xFF, 0x00, 0x00 ) // light red
+ && nSalColor != MAKE_SALCOLOR( 0xFF, 0x00, 0xFF ) // light magenta
+ && nSalColor != MAKE_SALCOLOR( 0xFF, 0xFF, 0x00 ) // light brown
+ && nSalColor != MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ) )
+ bDitherBrush_ = GetDitherPixmap(nSalColor);
+ bBrushGC_ = sal_False;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetROPLineColor( SalROPColor nROPColor )
+{
+ switch( nROPColor )
+ {
+ case SAL_ROP_0 : // 0
+ nPenPixel_ = (Pixel)0;
+ break;
+ case SAL_ROP_1 : // 1
+ nPenPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
+ break;
+ case SAL_ROP_INVERT : // 2
+ nPenPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
+ break;
+ }
+ nPenColor_ = GetColormap().GetColor( nPenPixel_ );
+ bPenGC_ = sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetROPFillColor( SalROPColor nROPColor )
+{
+ switch( nROPColor )
+ {
+ case SAL_ROP_0 : // 0
+ nBrushPixel_ = (Pixel)0;
+ break;
+ case SAL_ROP_1 : // 1
+ nBrushPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
+ break;
+ case SAL_ROP_INVERT : // 2
+ nBrushPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
+ break;
+ }
+ bDitherBrush_ = sal_False;
+ nBrushColor_ = GetColormap().GetColor( nBrushPixel_ );
+ bBrushGC_ = sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetXORMode( bool bSet, bool )
+{
+ if( !bXORMode_ == bSet )
+ {
+ bXORMode_ = bSet;
+ bPenGC_ = sal_False;
+ bFontGC_ = sal_False;
+ bBrushGC_ = sal_False;
+ bMonoGC_ = sal_False;
+ bCopyGC_ = sal_False;
+ bInvertGC_ = sal_False;
+ bInvert50GC_ = sal_False;
+ bStippleGC_ = sal_False;
+ bTrackingGC_ = sal_False;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawPixel( long nX, long nY )
+{
+ if( nPenColor_ != SALCOLOR_NONE )
+ XDrawPoint( GetXDisplay(), GetDrawable(), SelectPen(), nX, nY );
+}
+
+void X11SalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
+{
+ if( nSalColor != SALCOLOR_NONE )
+ {
+ Display *pDisplay = GetXDisplay();
+
+ if( (nPenColor_ == SALCOLOR_NONE) && !bPenGC_ )
+ {
+ SetLineColor( nSalColor );
+ XDrawPoint( pDisplay, GetDrawable(), SelectPen(), nX, nY );
+ nPenColor_ = SALCOLOR_NONE;
+ bPenGC_ = False;
+ }
+ else
+ {
+ GC pGC = SelectPen();
+
+ if( nSalColor != nPenColor_ )
+ XSetForeground( pDisplay, pGC, GetPixel( nSalColor ) );
+
+ XDrawPoint( pDisplay, GetDrawable(), pGC, nX, nY );
+
+ if( nSalColor != nPenColor_ )
+ XSetForeground( pDisplay, pGC, nPenPixel_ );
+ }
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ if( nPenColor_ != SALCOLOR_NONE )
+ {
+ if ( GetDisplay()->GetProperties() & PROPERTY_BUG_DrawLine )
+ {
+ GC aGC = SelectPen();
+ XDrawPoint (GetXDisplay(), GetDrawable(), aGC, (int)nX1, (int)nY1);
+ XDrawPoint (GetXDisplay(), GetDrawable(), aGC, (int)nX2, (int)nY2);
+ XDrawLine (GetXDisplay(), GetDrawable(), aGC, nX1, nY1, nX2, nY2 );
+ }
+ else
+ XDrawLine( GetXDisplay(), GetDrawable(),SelectPen(),
+ nX1, nY1, nX2, nY2 );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawRect( long nX, long nY, long nDX, long nDY )
+{
+ if( nBrushColor_ != SALCOLOR_NONE )
+ {
+ XFillRectangle( GetXDisplay(),
+ GetDrawable(),
+ SelectBrush(),
+ nX, nY, nDX, nDY );
+ }
+ // Beschreibung DrawRect verkehrt, deshalb -1
+ if( nPenColor_ != SALCOLOR_NONE )
+ XDrawRectangle( GetXDisplay(),
+ GetDrawable(),
+ SelectPen(),
+ nX, nY, nDX-1, nDY-1 );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint *pPtAry )
+{
+ drawPolyLine( nPoints, pPtAry, false );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint *pPtAry, bool bClose )
+{
+ if( nPenColor_ != 0xFFFFFFFF )
+ {
+ SalPolyLine Points( nPoints, pPtAry );
+
+ DrawLines( nPoints, Points, SelectPen(), bClose );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry )
+{
+ if( nPoints == 0 )
+ return;
+
+ if( nPoints < 3 )
+ {
+ if( !bXORMode_ )
+ {
+ if( 1 == nPoints )
+ drawPixel( pPtAry[0].mnX, pPtAry[0].mnY );
+ else
+ drawLine( pPtAry[0].mnX, pPtAry[0].mnY,
+ pPtAry[1].mnX, pPtAry[1].mnY );
+ }
+ return;
+ }
+
+ SalPolyLine Points( nPoints, pPtAry );
+
+ nPoints++;
+
+ /* WORKAROUND: some Xservers (Xorg, VIA chipset in this case)
+ * do not draw the visible part of a polygon
+ * if it overlaps to the left of screen 0,y.
+ * This happens to be the case in the gradient drawn in the
+ * menubar background. workaround for the special case of
+ * of a rectangle overlapping to the left.
+ */
+ if( nPoints == 5 &&
+ Points[ 0 ].x == Points[ 1 ].x &&
+ Points[ 1 ].y == Points[ 2 ].y &&
+ Points[ 2 ].x == Points[ 3 ].x &&
+ Points[ 0 ].x == Points[ 4 ].x && Points[ 0 ].y == Points[ 4 ].y
+ )
+ {
+ bool bLeft = false;
+ bool bRight = false;
+ for(unsigned int i = 0; i < nPoints; i++ )
+ {
+ if( Points[i].x < 0 )
+ bLeft = true;
+ else
+ bRight= true;
+ }
+ if( bLeft && ! bRight )
+ return;
+ if( bLeft && bRight )
+ {
+ for( unsigned int i = 0; i < nPoints; i++ )
+ if( Points[i].x < 0 )
+ Points[i].x = 0;
+ }
+ }
+
+ if( nBrushColor_ != SALCOLOR_NONE )
+ XFillPolygon( GetXDisplay(),
+ GetDrawable(),
+ SelectBrush(),
+ &Points[0], nPoints,
+ Complex, CoordModeOrigin );
+
+ if( nPenColor_ != 0xFFFFFFFF )
+ DrawLines( nPoints, Points, SelectPen(), true );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32 *pPoints,
+ PCONSTSALPOINT *pPtAry )
+{
+ if( nBrushColor_ != SALCOLOR_NONE )
+ {
+ sal_uInt32 i, n;
+ XLIB_Region pXRegA = NULL;
+
+ for( i = 0; i < nPoly; i++ ) {
+ n = pPoints[i];
+ SalPolyLine Points( n, pPtAry[i] );
+ if( n > 2 )
+ {
+ XLIB_Region pXRegB = XPolygonRegion( &Points[0], n+1, WindingRule );
+ if( !pXRegA )
+ pXRegA = pXRegB;
+ else
+ {
+ XXorRegion( pXRegA, pXRegB, pXRegA );
+ XDestroyRegion( pXRegB );
+ }
+ }
+ }
+
+ if( pXRegA )
+ {
+ XRectangle aXRect;
+ XClipBox( pXRegA, &aXRect );
+
+ GC pGC = SelectBrush();
+ SetClipRegion( pGC, pXRegA ); // ??? doppelt
+ XDestroyRegion( pXRegA );
+ bBrushGC_ = sal_False;
+
+ XFillRectangle( GetXDisplay(),
+ GetDrawable(),
+ pGC,
+ aXRect.x, aXRect.y, aXRect.width, aXRect.height );
+ }
+ }
+
+ if( nPenColor_ != SALCOLOR_NONE )
+ for( sal_uInt32 i = 0; i < nPoly; i++ )
+ drawPolyLine( pPoints[i], pPtAry[i], true );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+sal_Bool X11SalGraphics::drawPolyLineBezier( sal_uLong, const SalPoint*, const BYTE* )
+{
+ return sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+sal_Bool X11SalGraphics::drawPolygonBezier( sal_uLong, const SalPoint*, const BYTE* )
+{
+ return sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+sal_Bool X11SalGraphics::drawPolyPolygonBezier( sal_uInt32, const sal_uInt32*,
+ const SalPoint* const*, const BYTE* const* )
+{
+ return sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalGraphics::invert( sal_uLong nPoints,
+ const SalPoint* pPtAry,
+ SalInvert nFlags )
+{
+ SalPolyLine Points ( nPoints, pPtAry );
+
+ GC pGC;
+ if( SAL_INVERT_50 & nFlags )
+ pGC = GetInvert50GC();
+ else
+ if ( SAL_INVERT_TRACKFRAME & nFlags )
+ pGC = GetTrackingGC();
+ else
+ pGC = GetInvertGC();
+
+ if( SAL_INVERT_TRACKFRAME & nFlags )
+ DrawLines ( nPoints, Points, pGC, true );
+ else
+ XFillPolygon( GetXDisplay(),
+ GetDrawable(),
+ pGC,
+ &Points[0], nPoints,
+ Complex, CoordModeOrigin );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+BOOL X11SalGraphics::drawEPS( long,long,long,long,void*,sal_uLong )
+{
+ return sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+XID X11SalGraphics::GetXRenderPicture()
+{
+ XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
+
+ if( !m_aXRenderPicture )
+ {
+ // check xrender support for matching visual
+ XRenderPictFormat* pXRenderFormat = GetXRenderFormat();
+ if( !pXRenderFormat )
+ return 0;
+ // get the matching xrender target for drawable
+ m_aXRenderPicture = rRenderPeer.CreatePicture( hDrawable_, pXRenderFormat, 0, NULL );
+ }
+
+ {
+ // reset clip region
+ // TODO: avoid clip reset if already done
+ XRenderPictureAttributes aAttr;
+ aAttr.clip_mask = None;
+ rRenderPeer.ChangePicture( m_aXRenderPicture, CPClipMask, &aAttr );
+ }
+
+ return m_aXRenderPicture;
+}
+
+XRenderPictFormat* X11SalGraphics::GetXRenderFormat() const
+{
+ if( m_pXRenderFormat == NULL )
+ m_pXRenderFormat = XRenderPeer::GetInstance().FindVisualFormat( GetVisual().visual );
+ return m_pXRenderFormat;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+SystemGraphicsData X11SalGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+
+ aRes.nSize = sizeof(aRes);
+ aRes.pDisplay = GetXDisplay();
+ aRes.hDrawable = hDrawable_;
+ aRes.pVisual = GetVisual().visual;
+ aRes.nScreen = m_nScreen;
+ aRes.nDepth = GetBitCount();
+ aRes.aColormap = GetColormap().GetXColormap();
+ aRes.pXRenderFormat = m_pXRenderFormat;
+ return aRes;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// draw a poly-polygon
+bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency )
+{
+ // nothing to do for empty polypolygons
+ const int nOrigPolyCount = rOrigPolyPoly.count();
+ if( nOrigPolyCount <= 0 )
+ return sal_True;
+
+ // nothing to do if everything is transparent
+ if( (nBrushColor_ == SALCOLOR_NONE)
+ && (nPenColor_ == SALCOLOR_NONE) )
+ return sal_True;
+
+ // cannot handle pencolor!=brushcolor yet
+ if( (nPenColor_ != SALCOLOR_NONE)
+ && (nPenColor_ != nBrushColor_) )
+ return sal_False;
+
+ // TODO: remove the env-variable when no longer needed
+ static const char* pRenderEnv = getenv( "SAL_DISABLE_RENDER_POLY" );
+ if( pRenderEnv )
+ return sal_False;
+
+ // snap to raster if requested
+ basegfx::B2DPolyPolygon aPolyPoly = rOrigPolyPoly;
+ const bool bSnapToRaster = !getAntiAliasB2DDraw();
+ if( bSnapToRaster )
+ aPolyPoly = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges( aPolyPoly );
+
+ // don't bother with polygons outside of visible area
+ const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() );
+ aPolyPoly = basegfx::tools::clipPolyPolygonOnRange( aPolyPoly, aViewRange, true, false );
+ if( !aPolyPoly.count() )
+ return true;
+
+ // tesselate the polypolygon into trapezoids
+ basegfx::B2DTrapezoidVector aB2DTrapVector;
+ basegfx::tools::trapezoidSubdivide( aB2DTrapVector, aPolyPoly );
+ const int nTrapCount = aB2DTrapVector.size();
+ if( !nTrapCount )
+ return true;
+ const bool bDrawn = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency );
+ return bDrawn;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+bool X11SalGraphics::drawFilledTrapezoids( const ::basegfx::B2DTrapezoid* pB2DTraps, int nTrapCount, double fTransparency )
+{
+ if( nTrapCount <= 0 )
+ return true;
+
+ Picture aDstPic = GetXRenderPicture();
+ // check xrender support for this drawable
+ if( !aDstPic )
+ return false;
+
+ // convert the B2DTrapezoids into XRender-Trapezoids
+ typedef std::vector<XTrapezoid> TrapezoidVector;
+ TrapezoidVector aTrapVector( nTrapCount );
+ const basegfx::B2DTrapezoid* pB2DTrap = pB2DTraps;
+ for( int i = 0; i < nTrapCount; ++pB2DTrap, ++i )
+ {
+ XTrapezoid& rTrap = aTrapVector[ i ] ;
+
+ // set y-coordinates
+ const double fY1 = pB2DTrap->getTopY();
+ rTrap.left.p1.y = rTrap.right.p1.y = rTrap.top = XDoubleToFixed( fY1 );
+ const double fY2 = pB2DTrap->getBottomY();
+ rTrap.left.p2.y = rTrap.right.p2.y = rTrap.bottom = XDoubleToFixed( fY2 );
+
+ // set x-coordinates
+ const double fXL1 = pB2DTrap->getTopXLeft();
+ rTrap.left.p1.x = XDoubleToFixed( fXL1 );
+ const double fXR1 = pB2DTrap->getTopXRight();
+ rTrap.right.p1.x = XDoubleToFixed( fXR1 );
+ const double fXL2 = pB2DTrap->getBottomXLeft();
+ rTrap.left.p2.x = XDoubleToFixed( fXL2 );
+ const double fXR2 = pB2DTrap->getBottomXRight();
+ rTrap.right.p2.x = XDoubleToFixed( fXR2 );
+ }
+
+ // get xrender Picture for polygon foreground
+ // TODO: cache it like the target picture which uses GetXRenderPicture()
+ XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
+ SalDisplay::RenderEntry& rEntry = GetDisplay()->GetRenderEntries( m_nScreen )[ 32 ];
+ if( !rEntry.m_aPicture )
+ {
+ Display* pXDisplay = GetXDisplay();
+
+ rEntry.m_aPixmap = ::XCreatePixmap( pXDisplay, hDrawable_, 1, 1, 32 );
+ XRenderPictureAttributes aAttr;
+ aAttr.repeat = true;
+
+ XRenderPictFormat* pXRPF = rRenderPeer.FindStandardFormat( PictStandardARGB32 );
+ rEntry.m_aPicture = rRenderPeer.CreatePicture( rEntry.m_aPixmap, pXRPF, CPRepeat, &aAttr );
+ }
+
+ // set polygon foreground color and opacity
+ XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency );
+ rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 );
+
+ // set clipping
+ // TODO: move into GetXRenderPicture?
+ if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
+ rRenderPeer.SetPictureClipRegion( aDstPic, mpClipRegion );
+
+ // render the trapezoids
+ const XRenderPictFormat* pMaskFormat = rRenderPeer.GetStandardFormatA8();
+ rRenderPeer.CompositeTrapezoids( PictOpOver,
+ rEntry.m_aPicture, aDstPic, pMaskFormat, 0, 0, &aTrapVector[0], aTrapVector.size() );
+
+ return true;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, double fTransparency, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eLineJoin)
+{
+ const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2);
+
+ // #i101491#
+ if( !bIsHairline && (rPolygon.count() > 1000) )
+ {
+ // the used basegfx::tools::createAreaGeometry is simply too
+ // expensive with very big polygons; fallback to caller (who
+ // should use ImplLineConverter normally)
+ // AW: ImplLineConverter had to be removed since it does not even
+ // know LineJoins, so the fallback will now prepare the line geometry
+ // the same way.
+ return false;
+ }
+
+ // temporarily adjust brush color to pen color
+ // since the line is drawn as an area-polygon
+ const SalColor aKeepBrushColor = nBrushColor_;
+ nBrushColor_ = nPenColor_;
+
+ // #i11575#desc5#b adjust B2D tesselation result to raster positions
+ basegfx::B2DPolygon aPolygon = rPolygon;
+ const double fHalfWidth = 0.5 * rLineWidth.getX();
+ aPolygon.transform( basegfx::tools::createTranslateB2DHomMatrix(+fHalfWidth,+fHalfWidth) );
+
+ // shortcut for hairline drawing to improve performance
+ bool bDrawnOk = true;
+ if( bIsHairline )
+ {
+ // hairlines can benefit from a simplified tesselation
+ // e.g. for hairlines the linejoin style can be ignored
+ basegfx::B2DTrapezoidVector aB2DTrapVector;
+ basegfx::tools::createLineTrapezoidFromB2DPolygon( aB2DTrapVector, aPolygon, rLineWidth.getX() );
+
+ // draw tesselation result
+ const int nTrapCount = aB2DTrapVector.size();
+ if( nTrapCount > 0 )
+ bDrawnOk = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency );
+
+ // restore the original brush GC
+ nBrushColor_ = aKeepBrushColor;
+ return bDrawnOk;
+ }
+
+ // get the area polygon for the line polygon
+ if( (rLineWidth.getX() != rLineWidth.getY())
+ && !basegfx::fTools::equalZero( rLineWidth.getY() ) )
+ {
+ // prepare for createAreaGeometry() with anisotropic linewidth
+ aPolygon.transform( basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getX() / rLineWidth.getY()));
+ }
+
+ // create the area-polygon for the line
+ const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin) );
+
+ if( (rLineWidth.getX() != rLineWidth.getY())
+ && !basegfx::fTools::equalZero( rLineWidth.getX() ) )
+ {
+ // postprocess createAreaGeometry() for anisotropic linewidth
+ aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getY() / rLineWidth.getX()));
+ }
+
+ // draw each area polypolygon component individually
+ // to emulate the polypolygon winding rule "non-zero"
+ const int nPolyCount = aAreaPolyPoly.count();
+ for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
+ {
+ const ::basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( nPolyIdx ) );
+ bDrawnOk = drawPolyPolygon( aOnePoly, fTransparency );
+ if( !bDrawnOk )
+ break;
+ }
+
+ // restore the original brush GC
+ nBrushColor_ = aKeepBrushColor;
+ return bDrawnOk;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/salgdi2.cxx b/vcl/unx/generic/gdi/salgdi2.cxx
new file mode 100644
index 000000000000..49dd7174d583
--- /dev/null
+++ b/vcl/unx/generic/gdi/salgdi2.cxx
@@ -0,0 +1,1154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <poll.h>
+
+#include "vcl/salbtype.hxx"
+
+#include "unx/salunx.h"
+#include "unx/saldata.hxx"
+#include "unx/saldisp.hxx"
+#include "unx/salbmp.h"
+#include "unx/salgdi.h"
+#include "unx/salframe.h"
+#include "unx/salvd.h"
+#include "xrender_peer.hxx"
+
+#include "printergfx.hxx"
+
+#include "vcl/bmpacc.hxx"
+#include "vcl/outdata.hxx"
+
+#undef SALGDI2_TESTTRANS
+
+// -=-= debugging =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// -----------------------------------------------------------------------------
+
+#if (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
+#define DBG_TESTTRANS( _def_drawable ) \
+{ \
+ XCopyArea( pXDisp, _def_drawable, aDrawable, GetCopyGC(), \
+ 0, 0, \
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight, \
+ 0, 0 ); \
+}
+#else // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
+#define DBG_TESTTRANS( _def_drawable )
+#endif // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
+
+// -=-= X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::CopyScreenArea( Display* pDisplay,
+ Drawable aSrc, int nScreenSrc, int nSrcDepth,
+ Drawable aDest, int nScreenDest, int nDestDepth,
+ GC aDestGC,
+ int src_x, int src_y,
+ unsigned int w, unsigned int h,
+ int dest_x, int dest_y )
+{
+ if( nSrcDepth == nDestDepth )
+ {
+ if( nScreenSrc == nScreenDest )
+ XCopyArea( pDisplay, aSrc, aDest, aDestGC,
+ src_x, src_y, w, h, dest_x, dest_y );
+ else
+ {
+ SalXLib* pLib = GetX11SalData()->GetDisplay()->GetXLib();
+ pLib->PushXErrorLevel( true );
+ XImage* pImage = XGetImage( pDisplay, aSrc, src_x, src_y, w, h,
+ AllPlanes, ZPixmap );
+ if( pImage )
+ {
+ if( pImage->data )
+ {
+ XPutImage( pDisplay, aDest, aDestGC, pImage,
+ 0, 0, dest_x, dest_y, w, h );
+ }
+ XDestroyImage( pImage );
+ }
+ pLib->PopXErrorLevel();
+ }
+ }
+ else
+ {
+ X11SalBitmap aBM;
+ aBM.ImplCreateFromDrawable( aSrc, nScreenSrc, nSrcDepth, src_x, src_y, w, h );
+ SalTwoRect aTwoRect;
+ aTwoRect.mnSrcX = aTwoRect.mnSrcY = 0;
+ aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = w;
+ aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = h;
+ aTwoRect.mnDestX = dest_x;
+ aTwoRect.mnDestY = dest_y;
+ aBM.ImplDraw( aDest, nScreenDest, nDestDepth, aTwoRect,aDestGC );
+ }
+}
+
+GC X11SalGraphics::CreateGC( Drawable hDrawable, unsigned long nMask )
+{
+ XGCValues values;
+
+ values.graphics_exposures = False;
+ values.foreground = m_pColormap->GetBlackPixel()
+ ^ m_pColormap->GetWhitePixel();
+ values.function = GXxor;
+ values.line_width = 1;
+ values.fill_style = FillStippled;
+ values.stipple = GetDisplay()->GetInvert50( m_nScreen );
+ values.subwindow_mode = ClipByChildren;
+
+ return XCreateGC( GetXDisplay(), hDrawable, nMask | GCSubwindowMode, &values );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline GC X11SalGraphics::GetMonoGC( Pixmap hPixmap )
+{
+ if( !pMonoGC_ )
+ pMonoGC_ = CreateGC( hPixmap );
+
+ if( !bMonoGC_ )
+ {
+ SetClipRegion( pMonoGC_ );
+ bMonoGC_ = sal_True;
+ }
+
+ return pMonoGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline GC X11SalGraphics::GetCopyGC()
+{
+ if( bXORMode_ ) return GetInvertGC();
+
+ if( !pCopyGC_ )
+ pCopyGC_ = CreateGC( GetDrawable() );
+
+ if( !bCopyGC_ )
+ {
+ SetClipRegion( pCopyGC_ );
+ bCopyGC_ = sal_True;
+ }
+ return pCopyGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::GetInvertGC()
+{
+ if( !pInvertGC_ )
+ pInvertGC_ = CreateGC( GetDrawable(),
+ GCGraphicsExposures
+ | GCForeground
+ | GCFunction
+ | GCLineWidth );
+
+ if( !bInvertGC_ )
+ {
+ SetClipRegion( pInvertGC_ );
+ bInvertGC_ = sal_True;
+ }
+ return pInvertGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::GetInvert50GC()
+{
+ if( !pInvert50GC_ )
+ {
+ XGCValues values;
+
+ values.graphics_exposures = False;
+ values.foreground = m_pColormap->GetWhitePixel();
+ values.background = m_pColormap->GetBlackPixel();
+ values.function = GXinvert;
+ values.line_width = 1;
+ values.line_style = LineSolid;
+ unsigned long nValueMask =
+ GCGraphicsExposures
+ | GCForeground
+ | GCBackground
+ | GCFunction
+ | GCLineWidth
+ | GCLineStyle
+ | GCFillStyle
+ | GCStipple;
+
+ char* pEnv = getenv( "SAL_DO_NOT_USE_INVERT50" );
+ if( pEnv && ! strcasecmp( pEnv, "true" ) )
+ {
+ values.fill_style = FillSolid;
+ nValueMask &= ~ GCStipple;
+ }
+ else
+ {
+ values.fill_style = FillStippled;
+ values.stipple = GetDisplay()->GetInvert50( m_nScreen );
+ }
+
+ pInvert50GC_ = XCreateGC( GetXDisplay(), GetDrawable(),
+ nValueMask,
+ &values );
+ }
+
+ if( !bInvert50GC_ )
+ {
+ SetClipRegion( pInvert50GC_ );
+ bInvert50GC_ = sal_True;
+ }
+ return pInvert50GC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline GC X11SalGraphics::GetStippleGC()
+{
+ if( !pStippleGC_ )
+ pStippleGC_ = CreateGC( GetDrawable(),
+ GCGraphicsExposures
+ | GCFillStyle
+ | GCLineWidth );
+
+ if( !bStippleGC_ )
+ {
+ XSetFunction( GetXDisplay(), pStippleGC_, bXORMode_ ? GXxor : GXcopy );
+ SetClipRegion( pStippleGC_ );
+ bStippleGC_ = sal_True;
+ }
+
+ return pStippleGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+int X11SalGraphics::Clip( XLIB_Region pRegion,
+ int &nX,
+ int &nY,
+ unsigned int &nDX,
+ unsigned int &nDY,
+ int &nSrcX,
+ int &nSrcY ) const
+{
+ XRectangle aRect;
+ XClipBox( pRegion, &aRect );
+
+ if( int(nX + nDX) <= int(aRect.x) || nX >= int(aRect.x + aRect.width) )
+ return RectangleOut;
+ if( int(nY + nDY) <= int(aRect.y) || nY >= int(aRect.y + aRect.height) )
+ return RectangleOut;
+
+ if( nX < aRect.x )
+ {
+ nSrcX += aRect.x - nX;
+ nDX -= aRect.x - nX;
+ nX = aRect.x;
+ }
+ else if( int(nX + nDX) > int(aRect.x + aRect.width) )
+ nDX = aRect.x + aRect.width - nX;
+
+ if( nY < aRect.y )
+ {
+ nSrcY += aRect.y - nY;
+ nDY -= aRect.y - nY;
+ nY = aRect.y;
+ }
+ else if( int(nY + nDY) > int(aRect.y + aRect.height) )
+ nDY = aRect.y + aRect.height - nY;
+
+ return RectangleIn;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+int X11SalGraphics::Clip( int &nX,
+ int &nY,
+ unsigned int &nDX,
+ unsigned int &nDY,
+ int &nSrcX,
+ int &nSrcY ) const
+
+{
+ if( pPaintRegion_
+ && RectangleOut == Clip( pPaintRegion_, nX, nY, nDX, nDY, nSrcX, nSrcY ) )
+ return RectangleOut;
+
+ if( mpClipRegion
+ && RectangleOut == Clip( mpClipRegion, nX, nY, nDX, nDY, nSrcX, nSrcY ) )
+ return RectangleOut;
+
+ int nPaint;
+ if( pPaintRegion_ )
+ {
+ nPaint = XRectInRegion( pPaintRegion_, nX, nY, nDX, nDY );
+ if( RectangleOut == nPaint )
+ return RectangleOut;
+ }
+ else
+ nPaint = RectangleIn;
+
+ int nClip;
+ if( mpClipRegion )
+ {
+ nClip = XRectInRegion( mpClipRegion, nX, nY, nDX, nDY );
+ if( RectangleOut == nClip )
+ return RectangleOut;
+ }
+ else
+ nClip = RectangleIn;
+
+ return RectangleIn == nClip && RectangleIn == nPaint
+ ? RectangleIn
+ : RectanglePart;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::SetMask( int &nX,
+ int &nY,
+ unsigned int &nDX,
+ unsigned int &nDY,
+ int &nSrcX,
+ int &nSrcY,
+ Pixmap hClipMask )
+{
+ int n = Clip( nX, nY, nDX, nDY, nSrcX, nSrcY );
+ if( RectangleOut == n )
+ return NULL;
+
+ Display *pDisplay = GetXDisplay();
+
+ if( !pMaskGC_ )
+ pMaskGC_ = CreateGC( GetDrawable() );
+
+ if( RectangleIn == n )
+ {
+ XSetClipMask( pDisplay, pMaskGC_, hClipMask );
+ XSetClipOrigin( pDisplay, pMaskGC_, nX - nSrcX, nY - nSrcY );
+ return pMaskGC_;
+ }
+
+ // - - - - create alternate clip pixmap for region clipping - - - -
+ Pixmap hPixmap = XCreatePixmap( pDisplay, hClipMask, nDX, nDY, 1 );
+
+ if( !hPixmap )
+ {
+#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
+ fprintf( stderr, "X11SalGraphics::SetMask !hPixmap\n" );
+#endif
+ return NULL;
+ }
+
+ // - - - - reset pixmap; all 0 - - - - - - - - - - - - - - - - - - -
+ XFillRectangle( pDisplay,
+ hPixmap,
+ GetDisplay()->GetMonoGC( m_nScreen ),
+ 0, 0,
+ nDX, nDY );
+
+ // - - - - copy pixmap only within region - - - - - - - - - - - - -
+ GC pMonoGC = GetMonoGC( hPixmap );
+ XSetClipOrigin( pDisplay, pMonoGC, -nX, -nY );
+ XCopyArea( pDisplay,
+ hClipMask, // Source
+ hPixmap, // Destination
+ pMonoGC,
+ nSrcX, nSrcY, // Source
+ nDX, nDY, // Width & Height
+ 0, 0 ); // Destination
+
+ XSetClipMask( pDisplay, pMaskGC_, hPixmap );
+ XSetClipOrigin( pDisplay, pMaskGC_, nX, nY );
+
+ XFreePixmap( pDisplay, hPixmap );
+ return pMaskGC_;
+}
+
+// -=-= SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+extern "C"
+{
+ static Bool GraphicsExposePredicate( Display*, XEvent* pEvent, XPointer pFrameWindow )
+ {
+ Bool bRet = False;
+ if( (pEvent->type == GraphicsExpose || pEvent->type == NoExpose) &&
+ pEvent->xnoexpose.drawable == (Drawable)pFrameWindow )
+ {
+ bRet = True;
+ }
+ return bRet;
+ }
+}
+
+
+void X11SalGraphics::YieldGraphicsExpose()
+{
+ // get frame if necessary
+ SalFrame* pFrame = m_pFrame;
+ Display* pDisplay = GetXDisplay();
+ XLIB_Window aWindow = GetDrawable();
+ if( ! pFrame )
+ {
+ const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end() && ! pFrame; ++it )
+ {
+ const SystemEnvData* pEnvData = (*it)->GetSystemData();
+ if( Drawable(pEnvData->aWindow) == aWindow )
+ pFrame = *it;
+ }
+ if( ! pFrame )
+ return;
+ }
+
+ XEvent aEvent;
+ while( XCheckTypedWindowEvent( pDisplay, aWindow, Expose, &aEvent ) )
+ {
+ SalPaintEvent aPEvt( aEvent.xexpose.x, aEvent.xexpose.y, aEvent.xexpose.width+1, aEvent.xexpose.height+1 );
+ pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+
+ do
+ {
+ if( ! GetDisplay()->XIfEventWithTimeout( &aEvent, (XPointer)aWindow, GraphicsExposePredicate ) )
+ // this should not happen at all; still sometimes it happens
+ break;
+
+ if( aEvent.type == NoExpose )
+ break;
+
+ if( pFrame )
+ {
+ SalPaintEvent aPEvt( aEvent.xgraphicsexpose.x, aEvent.xgraphicsexpose.y, aEvent.xgraphicsexpose.width+1, aEvent.xgraphicsexpose.height+1 );
+ pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+ } while( aEvent.xgraphicsexpose.count != 0 );
+}
+
+void X11SalGraphics::copyBits( const SalTwoRect *pPosAry,
+ SalGraphics *pSSrcGraphics )
+{
+ X11SalGraphics* pSrcGraphics = pSSrcGraphics
+ ? static_cast<X11SalGraphics*>(pSSrcGraphics)
+ : this;
+
+ if( pPosAry->mnSrcWidth <= 0
+ || pPosAry->mnSrcHeight <= 0
+ || pPosAry->mnDestWidth <= 0
+ || pPosAry->mnDestHeight <= 0 )
+ {
+ return;
+ }
+
+ int n;
+ if( pSrcGraphics == this )
+ {
+ n = 2;
+ }
+ else if( pSrcGraphics->bWindow_ )
+ {
+ // window or compatible virtual device
+ if( pSrcGraphics->GetDisplay() == GetDisplay() &&
+ pSrcGraphics->m_nScreen == m_nScreen &&
+ pSrcGraphics->GetVisual().GetDepth() == GetVisual().GetDepth()
+ )
+ n = 2; // same Display
+ else
+ n = 1; // printer or other display
+ }
+ else if( pSrcGraphics->bVirDev_ )
+ {
+ // printer compatible virtual device
+ if( bPrinter_ )
+ n = 2; // printer or compatible virtual device == same display
+ else
+ n = 1; // window or compatible virtual device
+ }
+ else
+ n = 0;
+
+ if( n == 2
+ && pPosAry->mnSrcWidth == pPosAry->mnDestWidth
+ && pPosAry->mnSrcHeight == pPosAry->mnDestHeight
+ )
+ {
+ // #i60699# Need to generate graphics exposures (to repaint
+ // obscured areas beneath overlapping windows), src and dest
+ // are the same window.
+ const bool bNeedGraphicsExposures( pSrcGraphics == this &&
+ !bVirDev_ &&
+ pSrcGraphics->bWindow_ );
+
+ GC pCopyGC;
+
+ if( bXORMode_
+ && !pSrcGraphics->bVirDev_
+ && (GetDisplay()->GetProperties() & PROPERTY_BUG_XCopyArea_GXxor) )
+ {
+ Pixmap hPixmap = XCreatePixmap( GetXDisplay(),
+ pSrcGraphics->GetDrawable(), // source
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight,
+ pSrcGraphics->GetBitCount() );
+
+ pCopyGC = GetDisplay()->GetCopyGC( m_nScreen );
+
+ if( bNeedGraphicsExposures )
+ XSetGraphicsExposures( GetXDisplay(),
+ pCopyGC,
+ True );
+
+ XCopyArea( GetXDisplay(),
+ pSrcGraphics->GetDrawable(), // source
+ hPixmap, // destination
+ pCopyGC, // no clipping
+ pPosAry->mnSrcX, pPosAry->mnSrcY,
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight,
+ 0, 0 ); // destination
+ XCopyArea( GetXDisplay(),
+ hPixmap, // source
+ GetDrawable(), // destination
+ GetInvertGC(), // destination clipping
+ 0, 0, // source
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight,
+ pPosAry->mnDestX, pPosAry->mnDestY );
+ XFreePixmap( GetXDisplay(), hPixmap );
+ }
+ else
+ {
+ pCopyGC = GetCopyGC();
+
+ if( bNeedGraphicsExposures )
+ XSetGraphicsExposures( GetXDisplay(),
+ pCopyGC,
+ True );
+
+ XCopyArea( GetXDisplay(),
+ pSrcGraphics->GetDrawable(), // source
+ GetDrawable(), // destination
+ pCopyGC, // destination clipping
+ pPosAry->mnSrcX, pPosAry->mnSrcY,
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight,
+ pPosAry->mnDestX, pPosAry->mnDestY );
+ }
+
+ if( bNeedGraphicsExposures )
+ {
+ YieldGraphicsExpose();
+
+ if( pCopyGC )
+ XSetGraphicsExposures( GetXDisplay(),
+ pCopyGC,
+ False );
+ }
+ }
+ else if( n )
+ {
+ // #i60699# No chance to handle graphics exposures - we copy
+ // to a temp bitmap first, into which no repaints are
+ // technically possible.
+ SalBitmap *pDDB = pSrcGraphics->getBitmap( pPosAry->mnSrcX,
+ pPosAry->mnSrcY,
+ pPosAry->mnSrcWidth,
+ pPosAry->mnSrcHeight );
+
+ if( !pDDB )
+ {
+ stderr0( "SalGraphics::CopyBits !pSrcGraphics->GetBitmap()\n" );
+ return;
+ }
+
+ SalTwoRect aPosAry( *pPosAry );
+
+ aPosAry.mnSrcX = 0, aPosAry.mnSrcY = 0;
+ drawBitmap( &aPosAry, *pDDB );
+
+ delete pDDB;
+ }
+ else {
+ stderr0( "X11SalGraphics::CopyBits from Printer not yet implemented\n" );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void X11SalGraphics::copyArea ( long nDestX, long nDestY,
+ long nSrcX, long nSrcY,
+ long nSrcWidth, long nSrcHeight,
+ sal_uInt16 )
+{
+ SalTwoRect aPosAry;
+
+ aPosAry.mnDestX = nDestX;
+ aPosAry.mnDestY = nDestY;
+ aPosAry.mnDestWidth = nSrcWidth;
+ aPosAry.mnDestHeight = nSrcHeight;
+
+ aPosAry.mnSrcX = nSrcX;
+ aPosAry.mnSrcY = nSrcY;
+ aPosAry.mnSrcWidth = nSrcWidth;
+ aPosAry.mnSrcHeight = nSrcHeight;
+
+ copyBits ( &aPosAry, 0 );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap )
+{
+ const SalDisplay* pSalDisp = GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+ const Drawable aDrawable( GetDrawable() );
+ const SalColormap& rColMap = pSalDisp->GetColormap( m_nScreen );
+ const long nDepth = GetDisplay()->GetVisual( m_nScreen ).GetDepth();
+ GC aGC( GetCopyGC() );
+ XGCValues aOldVal, aNewVal;
+ int nValues = GCForeground | GCBackground;
+
+ if( rSalBitmap.GetBitCount() == 1 )
+ {
+ // set foreground/background values for 1Bit bitmaps
+ XGetGCValues( pXDisp, aGC, nValues, &aOldVal );
+
+ aNewVal.foreground = rColMap.GetWhitePixel();
+ aNewVal.background = rColMap.GetBlackPixel();
+
+ //fdo#33455 handle 1 bit depth pngs with palette entries
+ //to set fore/back colors
+ if (const BitmapBuffer* pBitmapBuffer = const_cast<SalBitmap&>(rSalBitmap).AcquireBuffer(true))
+ {
+ const BitmapPalette& rPalette = pBitmapBuffer->maPalette;
+ if (rPalette.GetEntryCount() == 2)
+ {
+ aNewVal.foreground = rColMap.GetPixel(ImplColorToSal(rPalette[0]));
+ aNewVal.background = rColMap.GetPixel(ImplColorToSal(rPalette[1]));
+ }
+ }
+
+ XChangeGC( pXDisp, aGC, nValues, &aNewVal );
+ }
+
+ static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aDrawable, m_nScreen, nDepth, *pPosAry, aGC );
+
+ if( rSalBitmap.GetBitCount() == 1 )
+ XChangeGC( pXDisp, aGC, nValues, &aOldVal );
+ XFlush( pXDisp );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSrcBitmap,
+ const SalBitmap& rMaskBitmap )
+{
+ DBG_ASSERT( !bPrinter_, "Drawing of transparent bitmaps on printer devices is strictly forbidden" );
+
+ // decide if alpha masking or transparency masking is needed
+ BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rMaskBitmap).AcquireBuffer( sal_True );
+ if( pAlphaBuffer != NULL )
+ {
+ int nMaskFormat = pAlphaBuffer->mnFormat;
+ const_cast<SalBitmap&>(rMaskBitmap).ReleaseBuffer( pAlphaBuffer, sal_True );
+ if( nMaskFormat == BMP_FORMAT_8BIT_PAL )
+ drawAlphaBitmap( *pPosAry, rSrcBitmap, rMaskBitmap );
+ }
+
+ drawMaskedBitmap( pPosAry, rSrcBitmap, rMaskBitmap );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalGraphics::drawMaskedBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransBitmap )
+{
+ const SalDisplay* pSalDisp = GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+ Drawable aDrawable( GetDrawable() );
+
+ // figure work mode depth. If this is a VDev Drawable, use its
+ // bitdepth to create pixmaps for, otherwise, XCopyArea will
+ // refuse to work.
+ const sal_uInt16 nDepth( m_pVDev ?
+ m_pVDev->GetDepth() :
+ pSalDisp->GetVisual( m_nScreen ).GetDepth() );
+ Pixmap aFG( XCreatePixmap( pXDisp, aDrawable, pPosAry->mnDestWidth,
+ pPosAry->mnDestHeight, nDepth ) );
+ Pixmap aBG( XCreatePixmap( pXDisp, aDrawable, pPosAry->mnDestWidth,
+ pPosAry->mnDestHeight, nDepth ) );
+
+ if( aFG && aBG )
+ {
+ GC aTmpGC;
+ XGCValues aValues;
+ const SalColormap& rColMap = pSalDisp->GetColormap( m_nScreen );
+ const int nBlack = rColMap.GetBlackPixel(), nWhite = rColMap.GetWhitePixel();
+ const int nValues = GCFunction | GCForeground | GCBackground;
+ SalTwoRect aTmpRect( *pPosAry ); aTmpRect.mnDestX = aTmpRect.mnDestY = 0;
+
+ // draw paint bitmap in pixmap #1
+ aValues.function = GXcopy, aValues.foreground = nWhite, aValues.background = nBlack;
+ aTmpGC = XCreateGC( pXDisp, aFG, nValues, &aValues );
+ static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aFG, m_nScreen, nDepth, aTmpRect, aTmpGC );
+ DBG_TESTTRANS( aFG );
+
+ // draw background in pixmap #2
+ XCopyArea( pXDisp, aDrawable, aBG, aTmpGC,
+ pPosAry->mnDestX, pPosAry->mnDestY,
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight,
+ 0, 0 );
+
+ DBG_TESTTRANS( aBG );
+
+ // mask out paint bitmap in pixmap #1 (transparent areas 0)
+ aValues.function = GXand, aValues.foreground = 0x00000000, aValues.background = 0xffffffff;
+ XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
+ static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aFG, m_nScreen, 1, aTmpRect, aTmpGC );
+
+ DBG_TESTTRANS( aFG );
+
+ // #105055# For XOR mode, keep background behind bitmap intact
+ if( !bXORMode_ )
+ {
+ // mask out background in pixmap #2 (nontransparent areas 0)
+ aValues.function = GXand, aValues.foreground = 0xffffffff, aValues.background = 0x00000000;
+ XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
+ static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aBG, m_nScreen, 1, aTmpRect, aTmpGC );
+
+ DBG_TESTTRANS( aBG );
+ }
+
+ // merge pixmap #1 and pixmap #2 in pixmap #2
+ aValues.function = GXxor, aValues.foreground = 0xffffffff, aValues.background = 0x00000000;
+ XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
+ XCopyArea( pXDisp, aFG, aBG, aTmpGC,
+ 0, 0,
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight,
+ 0, 0 );
+ DBG_TESTTRANS( aBG );
+
+ // #105055# Disable XOR temporarily
+ sal_Bool bOldXORMode( bXORMode_ );
+ bXORMode_ = sal_False;
+
+ // copy pixmap #2 (result) to background
+ XCopyArea( pXDisp, aBG, aDrawable, GetCopyGC(),
+ 0, 0,
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight,
+ pPosAry->mnDestX, pPosAry->mnDestY );
+
+ DBG_TESTTRANS( aBG );
+
+ bXORMode_ = bOldXORMode;
+
+ XFreeGC( pXDisp, aTmpGC );
+ XFlush( pXDisp );
+ }
+ else
+ drawBitmap( pPosAry, rSalBitmap );
+
+ if( aFG )
+ XFreePixmap( pXDisp, aFG );
+
+ if( aBG )
+ XFreePixmap( pXDisp, aBG );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+bool X11SalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
+ const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp )
+{
+ // non 8-bit alpha not implemented yet
+ if( rAlphaBmp.GetBitCount() != 8 )
+ return false;
+
+ // horizontal mirroring not implemented yet
+ if( rTR.mnDestWidth < 0 )
+ return false;
+
+ // stretched conversion is not implemented yet
+ if( rTR.mnDestWidth != rTR.mnSrcWidth )
+ return false;
+ if( rTR.mnDestHeight!= rTR.mnSrcHeight )
+ return false;
+
+ XRenderPeer& rPeer = XRenderPeer::GetInstance();
+ if( rPeer.GetVersion() < 0x02 )
+ return false;
+
+ // create destination picture
+ Picture aDstPic = GetXRenderPicture();
+ if( !aDstPic )
+ return false;
+
+ const SalDisplay* pSalDisp = GetDisplay();
+ const SalVisual& rSalVis = pSalDisp->GetVisual( m_nScreen );
+ Display* pXDisplay = pSalDisp->GetDisplay();
+
+ // create source Picture
+ int nDepth = m_pVDev ? m_pVDev->GetDepth() : rSalVis.GetDepth();
+ const X11SalBitmap& rSrcX11Bmp = static_cast<const X11SalBitmap&>( rSrcBitmap );
+ ImplSalDDB* pSrcDDB = rSrcX11Bmp.ImplGetDDB( hDrawable_, m_nScreen, nDepth, rTR );
+ if( !pSrcDDB )
+ return false;
+
+ //#i75249# workaround for ImplGetDDB() giving us back a different depth than
+ // we requested. E.g. mask pixmaps are always compatible with the drawable
+ // TODO: find an appropriate picture format for these cases
+ // then remove the workaround below and the one for #i75531#
+ if( nDepth != pSrcDDB->ImplGetDepth() )
+ return false;
+
+ Pixmap aSrcPM = pSrcDDB->ImplGetPixmap();
+ if( !aSrcPM )
+ return false;
+
+ // create source picture
+ // TODO: use scoped picture
+ Visual* pSrcXVisual = rSalVis.GetVisual();
+ XRenderPictFormat* pSrcVisFmt = rPeer.FindVisualFormat( pSrcXVisual );
+ if( !pSrcVisFmt )
+ return false;
+ Picture aSrcPic = rPeer.CreatePicture( aSrcPM, pSrcVisFmt, 0, NULL );
+ if( !aSrcPic )
+ return false;
+
+ // create alpha Picture
+
+ // TODO: use SalX11Bitmap functionality and caching for the Alpha Pixmap
+ // problem is that they don't provide an 8bit Pixmap on a non-8bit display
+ BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rAlphaBmp).AcquireBuffer( sal_True );
+
+ // an XImage needs its data top_down
+ // TODO: avoid wrongly oriented images in upper layers!
+ const int nImageSize = pAlphaBuffer->mnHeight * pAlphaBuffer->mnScanlineSize;
+ const char* pSrcBits = (char*)pAlphaBuffer->mpBits;
+ char* pAlphaBits = new char[ nImageSize ];
+ if( BMP_SCANLINE_ADJUSTMENT( pAlphaBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ memcpy( pAlphaBits, pSrcBits, nImageSize );
+ else
+ {
+ char* pDstBits = pAlphaBits + nImageSize;
+ const int nLineSize = pAlphaBuffer->mnScanlineSize;
+ for(; (pDstBits -= nLineSize) >= pAlphaBits; pSrcBits += nLineSize )
+ memcpy( pDstBits, pSrcBits, nLineSize );
+ }
+
+ // the alpha values need to be inverted for XRender
+ // TODO: make upper layers use standard alpha
+ long* pLDst = (long*)pAlphaBits;
+ for( int i = nImageSize/sizeof(long); --i >= 0; ++pLDst )
+ *pLDst = ~*pLDst;
+
+ char* pCDst = (char*)pLDst;
+ for( int i = nImageSize & (sizeof(long)-1); --i >= 0; ++pCDst )
+ *pCDst = ~*pCDst;
+
+ const XRenderPictFormat* pAlphaFormat = rPeer.GetStandardFormatA8();
+ XImage* pAlphaImg = XCreateImage( pXDisplay, pSrcXVisual, 8, ZPixmap, 0,
+ pAlphaBits, pAlphaBuffer->mnWidth, pAlphaBuffer->mnHeight,
+ pAlphaFormat->depth, pAlphaBuffer->mnScanlineSize );
+
+ Pixmap aAlphaPM = XCreatePixmap( pXDisplay, hDrawable_,
+ rTR.mnDestWidth, rTR.mnDestHeight, 8 );
+
+ XGCValues aAlphaGCV;
+ aAlphaGCV.function = GXcopy;
+ GC aAlphaGC = XCreateGC( pXDisplay, aAlphaPM, GCFunction, &aAlphaGCV );
+ XPutImage( pXDisplay, aAlphaPM, aAlphaGC, pAlphaImg,
+ rTR.mnSrcX, rTR.mnSrcY, 0, 0, rTR.mnDestWidth, rTR.mnDestHeight );
+ XFreeGC( pXDisplay, aAlphaGC );
+ XFree( pAlphaImg );
+ if( pAlphaBits != (char*)pAlphaBuffer->mpBits )
+ delete[] pAlphaBits;
+
+ const_cast<SalBitmap&>(rAlphaBmp).ReleaseBuffer( pAlphaBuffer, sal_True );
+
+ XRenderPictureAttributes aAttr;
+ aAttr.repeat = true;
+ Picture aAlphaPic = rPeer.CreatePicture( aAlphaPM, pAlphaFormat, CPRepeat, &aAttr );
+ if( !aAlphaPic )
+ return false;
+
+ // set clipping
+ if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
+ rPeer.SetPictureClipRegion( aDstPic, mpClipRegion );
+
+ // paint source * mask over destination picture
+ rPeer.CompositePicture( PictOpOver, aSrcPic, aAlphaPic, aDstPic,
+ rTR.mnSrcX, rTR.mnSrcY, 0, 0,
+ rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight );
+
+ // TODO: used ScopedPic
+ rPeer.FreePicture( aAlphaPic );
+ XFreePixmap(pXDisplay, aAlphaPM);
+ rPeer.FreePicture( aSrcPic );
+ return true;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+bool X11SalGraphics::drawAlphaRect( long nX, long nY, long nWidth,
+ long nHeight, sal_uInt8 nTransparency )
+{
+ if( ! m_pFrame && ! m_pVDev )
+ return false;
+
+ if( bPenGC_ || !bBrushGC_ || bXORMode_ )
+ return false; // can only perform solid fills without XOR.
+
+ if( m_pVDev && m_pVDev->GetDepth() < 8 )
+ return false;
+
+ XRenderPeer& rPeer = XRenderPeer::GetInstance();
+ if( rPeer.GetVersion() < 0x02 ) // TODO: replace with better test
+ return false;
+
+ Picture aDstPic = GetXRenderPicture();
+ if( !aDstPic )
+ return false;
+
+ const double fTransparency = (100 - nTransparency) * (1.0/100);
+ const XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency);
+
+ rPeer.FillRectangle( PictOpOver,
+ aDstPic,
+ &aRenderColor,
+ nX, nY,
+ nWidth, nHeight );
+
+ return true;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawBitmap( const SalTwoRect*,
+ const SalBitmap&,
+ SalColor )
+{
+ OSL_FAIL( "::DrawBitmap with transparent color not supported" );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap &rSalBitmap,
+ SalColor nMaskColor )
+{
+ const SalDisplay* pSalDisp = GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+ Drawable aDrawable( GetDrawable() );
+ Pixmap aStipple( XCreatePixmap( pXDisp, aDrawable,
+ pPosAry->mnDestWidth,
+ pPosAry->mnDestHeight, 1 ) );
+
+ if( aStipple )
+ {
+ SalTwoRect aTwoRect( *pPosAry ); aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
+ GC aTmpGC;
+ XGCValues aValues;
+
+ // create a stipple bitmap first (set bits are changed to unset bits and vice versa)
+ aValues.function = GXcopyInverted;
+ aValues.foreground = 1, aValues.background = 0;
+ aTmpGC = XCreateGC( pXDisp, aStipple, GCFunction | GCForeground | GCBackground, &aValues );
+ static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aStipple, m_nScreen, 1, aTwoRect, aTmpGC );
+
+ XFreeGC( pXDisp, aTmpGC );
+
+ // Set stipple and draw rectangle
+ GC aStippleGC( GetStippleGC() );
+ int nX = pPosAry->mnDestX, nY = pPosAry->mnDestY;
+
+ XSetStipple( pXDisp, aStippleGC, aStipple );
+ XSetTSOrigin( pXDisp, aStippleGC, nX, nY );
+ XSetForeground( pXDisp, aStippleGC, GetPixel( nMaskColor ) );
+ XFillRectangle( pXDisp, aDrawable, aStippleGC,
+ nX, nY,
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight );
+ XFreePixmap( pXDisp, aStipple );
+ XFlush( pXDisp );
+ }
+ else
+ drawBitmap( pPosAry, rSalBitmap );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalBitmap *X11SalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
+{
+ if( bPrinter_ && !bVirDev_ )
+ return NULL;
+
+ bool bFakeWindowBG = false;
+
+ // normalize
+ if( nDX < 0 )
+ {
+ nX += nDX;
+ nDX = -nDX;
+ }
+ if ( nDY < 0 )
+ {
+ nY += nDY;
+ nDY = -nDY;
+ }
+
+ if( bWindow_ && !bVirDev_ )
+ {
+ XWindowAttributes aAttrib;
+
+ XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib );
+ if( aAttrib.map_state != IsViewable )
+ bFakeWindowBG = true;
+ else
+ {
+ long nOrgDX = nDX, nOrgDY = nDY;
+
+ // clip to window size
+ if ( nX < 0 )
+ {
+ nDX += nX;
+ nX = 0;
+ }
+ if ( nY < 0 )
+ {
+ nDY += nY;
+ nY = 0;
+ }
+ if( nX + nDX > aAttrib.width )
+ nDX = aAttrib.width - nX;
+ if( nY + nDY > aAttrib.height )
+ nDY = aAttrib.height - nY;
+
+ // inside ?
+ if( nDX <= 0 || nDY <= 0 )
+ {
+ bFakeWindowBG = true;
+ nDX = nOrgDX;
+ nDY = nOrgDY;
+ }
+ }
+ }
+
+ X11SalBitmap* pSalBitmap = new X11SalBitmap;
+ sal_uInt16 nBitCount = GetBitCount();
+
+ if( &GetDisplay()->GetColormap( m_nScreen ) != &GetColormap() )
+ nBitCount = 1;
+
+ if( ! bFakeWindowBG )
+ pSalBitmap->ImplCreateFromDrawable( GetDrawable(), m_nScreen, nBitCount, nX, nY, nDX, nDY );
+ else
+ pSalBitmap->Create( Size( nDX, nDY ), (nBitCount > 8) ? 24 : nBitCount, BitmapPalette( nBitCount > 8 ? nBitCount : 0 ) );
+
+ return pSalBitmap;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalColor X11SalGraphics::getPixel( long nX, long nY )
+{
+ if( bWindow_ && !bVirDev_ )
+ {
+ XWindowAttributes aAttrib;
+
+ XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib );
+ if( aAttrib.map_state != IsViewable )
+ {
+ stderr0( "X11SalGraphics::GetPixel drawable not viewable\n" );
+ return 0;
+ }
+ }
+
+ XImage *pXImage = XGetImage( GetXDisplay(),
+ GetDrawable(),
+ nX, nY,
+ 1, 1,
+ AllPlanes,
+ ZPixmap );
+ if( !pXImage )
+ {
+ stderr0( "X11SalGraphics::GetPixel !XGetImage()\n" );
+ return 0;
+ }
+
+ XColor aXColor;
+
+ aXColor.pixel = XGetPixel( pXImage, 0, 0 );
+ XDestroyImage( pXImage );
+
+ return GetColormap().GetColor( aXColor.pixel );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::invert( long nX,
+ long nY,
+ long nDX,
+ long nDY,
+ SalInvert nFlags )
+{
+ GC pGC;
+ if( SAL_INVERT_50 & nFlags )
+ {
+ pGC = GetInvert50GC();
+ XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY );
+ }
+ else
+ {
+ if ( SAL_INVERT_TRACKFRAME & nFlags )
+ {
+ pGC = GetTrackingGC();
+ XDrawRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY );
+ }
+ else
+ {
+ pGC = GetInvertGC();
+ XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY );
+ }
+ }
+}
+
+bool X11SalGraphics::supportsOperation( OutDevSupportType eType ) const
+{
+ bool bRet = false;
+ switch( eType )
+ {
+ case OutDevSupport_TransparentRect:
+ case OutDevSupport_B2DDraw:
+ {
+ XRenderPeer& rPeer = XRenderPeer::GetInstance();
+ if( rPeer.GetVersion() >= 0x02 )
+ {
+ const SalDisplay* pSalDisp = GetDisplay();
+ const SalVisual& rSalVis = pSalDisp->GetVisual( m_nScreen );
+
+ Visual* pDstXVisual = rSalVis.GetVisual();
+ XRenderPictFormat* pDstVisFmt = rPeer.FindVisualFormat( pDstXVisual );
+ if( pDstVisFmt )
+ bRet = true;
+ }
+ }
+ break;
+ default: break;
+ }
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/salgdi3.cxx b/vcl/unx/generic/gdi/salgdi3.cxx
new file mode 100644
index 000000000000..c60bf49fff0e
--- /dev/null
+++ b/vcl/unx/generic/gdi/salgdi3.cxx
@@ -0,0 +1,1695 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <math.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "sal/alloca.h"
+#include "sal/types.h"
+
+#include "rtl/tencinfo.h"
+
+#include "osl/file.hxx"
+
+#include "tools/string.hxx"
+#include "tools/debug.hxx"
+#include "tools/stream.hxx"
+
+#include "basegfx/polygon/b2dpolypolygon.hxx"
+
+#include "i18npool/mslangid.hxx"
+
+#include <boost/unordered_set.hpp>
+
+#include <vcl/sysdata.hxx>
+#include "printergfx.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/jobdata.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/svapp.hxx"
+
+#include "unx/salunx.h"
+#include "unx/saldata.hxx"
+#include "unx/saldisp.hxx"
+#include "unx/salgdi.h"
+#include "unx/pspgraphics.h"
+#include "unx/salvd.h"
+
+#include "salcvt.hxx"
+#include "gcach_xpeer.hxx"
+#include "xrender_peer.hxx"
+#include "impfont.hxx"
+#include "salframe.hxx"
+#include "outdev.h"
+
+
+
+#ifdef ENABLE_GRAPHITE
+#include <graphite_layout.hxx>
+#include <graphite_serverfont.hxx>
+#endif
+
+struct cairo_surface_t;
+struct cairo_t;
+struct cairo_font_face_t;
+typedef void* FT_Face;
+struct cairo_matrix_t {
+ double xx; double yx;
+ double xy; double yy;
+ double x0; double y0;
+};
+struct cairo_glyph_t
+{
+ unsigned long index;
+ double x;
+ double y;
+};
+struct BOX
+{
+ short x1, x2, y1, y2;
+};
+struct _XRegion
+{
+ long size;
+ long numRects;
+ BOX *rects;
+ BOX extents;
+};
+using ::rtl::OUString;
+// ===========================================================================
+
+// PspKernInfo allows on-demand-querying of psprint provided kerning info (#i29881#)
+class PspKernInfo : public ExtraKernInfo
+{
+public:
+ PspKernInfo( int nFontId ) : ExtraKernInfo(nFontId) {}
+protected:
+ virtual void Initialize() const;
+};
+
+//--------------------------------------------------------------------------
+
+void PspKernInfo::Initialize() const
+{
+ mbInitialized = true;
+
+ // get the kerning pairs from psprint
+ const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ typedef std::list< psp::KernPair > PspKernPairs;
+ const PspKernPairs& rKernPairs = rMgr.getKernPairs( mnFontId );
+ if( rKernPairs.empty() )
+ return;
+
+ PspKernPairs::const_iterator it = rKernPairs.begin();
+ for(; it != rKernPairs.end(); ++it )
+ {
+ ImplKernPairData aKernPair = { it->first, it->second, it->kern_x };
+ maUnicodeKernPairs.insert( aKernPair );
+ }
+}
+
+// ----------------------------------------------------------------------------
+//
+// X11SalGraphics
+//
+// ----------------------------------------------------------------------------
+
+GC
+X11SalGraphics::GetFontGC()
+{
+ Display *pDisplay = GetXDisplay();
+
+ if( !pFontGC_ )
+ {
+ XGCValues values;
+ values.subwindow_mode = ClipByChildren;
+ values.fill_rule = EvenOddRule; // Pict import/ Gradient
+ values.graphics_exposures = False;
+ values.foreground = nTextPixel_;
+ pFontGC_ = XCreateGC( pDisplay, hDrawable_,
+ GCSubwindowMode | GCFillRule
+ | GCGraphicsExposures | GCForeground,
+ &values );
+ }
+ if( !bFontGC_ )
+ {
+ XSetForeground( pDisplay, pFontGC_, nTextPixel_ );
+ SetClipRegion( pFontGC_ );
+ bFontGC_ = sal_True;
+ }
+
+ return pFontGC_;
+}
+
+//--------------------------------------------------------------------------
+
+bool X11SalGraphics::setFont( const ImplFontSelectData *pEntry, int nFallbackLevel )
+{
+ // release all no longer needed font resources
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( mpServerFont[i] != NULL )
+ {
+ // old server side font is no longer referenced
+ GlyphCache::GetInstance().UncacheFont( *mpServerFont[i] );
+ mpServerFont[i] = NULL;
+ }
+ }
+
+ // return early if there is no new font
+ if( !pEntry )
+ return false;
+
+ bFontVertical_ = pEntry->mbVertical;
+
+ // return early if this is not a valid font for this graphics
+ if( !pEntry->mpFontData )
+ return false;
+
+ // handle the request for a non-native X11-font => use the GlyphCache
+ ServerFont* pServerFont = GlyphCache::GetInstance().CacheFont( *pEntry );
+ if( pServerFont != NULL )
+ {
+ // ignore fonts with e.g. corrupted font files
+ if( !pServerFont->TestFont() )
+ {
+ GlyphCache::GetInstance().UncacheFont( *pServerFont );
+ return false;
+ }
+
+ // register to use the font
+ mpServerFont[ nFallbackLevel ] = pServerFont;
+
+ // apply font specific-hint settings if needed
+ // TODO: also disable it for reference devices
+ if( !bPrinter_ )
+ {
+ ImplServerFontEntry* pSFE = static_cast<ImplServerFontEntry*>( pEntry->mpFontEntry );
+ pSFE->HandleFontOptions();
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+ImplFontOptions* GetFCFontOptions( const ImplFontAttributes& rFontAttributes, int nSize);
+
+void ImplServerFontEntry::HandleFontOptions( void )
+{
+ if( !mpServerFont )
+ return;
+ if( !mbGotFontOptions )
+ {
+ // get and cache the font options
+ mbGotFontOptions = true;
+ mpFontOptions.reset(GetFCFontOptions( *maFontSelData.mpFontData,
+ maFontSelData.mnHeight ));
+ }
+ // apply the font options
+ mpServerFont->SetFontOptions( mpFontOptions );
+}
+
+//--------------------------------------------------------------------------
+
+namespace {
+
+class CairoWrapper
+{
+private:
+ oslModule mpCairoLib;
+
+ cairo_surface_t* (*mp_xlib_surface_create_with_xrender_format)(Display *, Drawable , Screen *, XRenderPictFormat *, int , int );
+ void (*mp_surface_destroy)(cairo_surface_t *);
+ cairo_t* (*mp_create)(cairo_surface_t *);
+ void (*mp_destroy)(cairo_t*);
+ void (*mp_clip)(cairo_t*);
+ void (*mp_rectangle)(cairo_t*, double, double, double, double);
+ cairo_font_face_t * (*mp_ft_font_face_create_for_ft_face)(FT_Face, int);
+ cairo_font_face_t * (*mp_ft_font_face_create_for_pattern)(void*);
+ void (*mp_set_font_face)(cairo_t *, cairo_font_face_t *);
+ void (*mp_font_face_destroy)(cairo_font_face_t *);
+ void (*mp_matrix_init_identity)(cairo_matrix_t *);
+ void (*mp_matrix_scale)(cairo_matrix_t *, double, double);
+ void (*mp_matrix_rotate)(cairo_matrix_t *, double);
+ void (*mp_set_font_matrix)(cairo_t *, const cairo_matrix_t *);
+ void (*mp_show_glyphs)(cairo_t *, const cairo_glyph_t *, int );
+ void (*mp_set_source_rgb)(cairo_t *, double , double , double );
+ void (*mp_set_font_options)(cairo_t *, const void *);
+ void (*mp_ft_font_options_substitute)(const void*, void*);
+
+ bool canEmbolden() const { return mp_ft_font_face_create_for_pattern != NULL; }
+
+ CairoWrapper();
+public:
+ static CairoWrapper& get();
+ bool isValid() const { return (mpCairoLib != NULL); }
+ bool isCairoRenderable(const ServerFont& rFont);
+
+ cairo_surface_t* xlib_surface_create_with_xrender_format(Display *pDisplay, Drawable drawable, Screen *pScreen, XRenderPictFormat *pFormat, int width, int height)
+ { return (*mp_xlib_surface_create_with_xrender_format)(pDisplay, drawable, pScreen, pFormat, width, height); }
+ void surface_destroy(cairo_surface_t *surface) { (*mp_surface_destroy)(surface); }
+ cairo_t* create(cairo_surface_t *surface) { return (*mp_create)(surface); }
+ void destroy(cairo_t *cr) { (*mp_destroy)(cr); }
+ void clip(cairo_t *cr) { (*mp_clip)(cr); }
+ void rectangle(cairo_t *cr, double x, double y, double width, double height)
+ { (*mp_rectangle)(cr, x, y, width, height); }
+ cairo_font_face_t* ft_font_face_create_for_ft_face(FT_Face face, int load_flags)
+ { return (*mp_ft_font_face_create_for_ft_face)(face, load_flags); }
+ cairo_font_face_t* ft_font_face_create_for_pattern(void *pattern)
+ {
+ return mp_ft_font_face_create_for_pattern
+ ? (*mp_ft_font_face_create_for_pattern)(pattern)
+ : NULL;
+ }
+ void set_font_face(cairo_t *cr, cairo_font_face_t *font_face)
+ { (*mp_set_font_face)(cr, font_face); }
+ void font_face_destroy(cairo_font_face_t *font_face)
+ { (*mp_font_face_destroy)(font_face); }
+ void matrix_init_identity(cairo_matrix_t *matrix)
+ { (*mp_matrix_init_identity)(matrix); }
+ void matrix_scale(cairo_matrix_t *matrix, double sx, double sy)
+ { (*mp_matrix_scale)(matrix, sx, sy); }
+ void matrix_rotate(cairo_matrix_t *matrix, double radians)
+ { (*mp_matrix_rotate)(matrix, radians); }
+ void set_font_matrix(cairo_t *cr, const cairo_matrix_t *matrix)
+ { (*mp_set_font_matrix)(cr, matrix); }
+ void show_glyphs(cairo_t *cr, const cairo_glyph_t *glyphs, int no_glyphs)
+ { (*mp_show_glyphs)(cr, glyphs, no_glyphs); }
+ void set_source_rgb(cairo_t *cr, double red, double green, double blue)
+ { (*mp_set_source_rgb)(cr, red, green, blue); }
+ void set_font_options(cairo_t *cr, const void *options)
+ { (*mp_set_font_options)(cr, options); }
+ void ft_font_options_substitute(const void *options, void *pattern)
+ { (*mp_ft_font_options_substitute)(options, pattern); }
+};
+
+static CairoWrapper* pCairoInstance = NULL;
+
+CairoWrapper& CairoWrapper::get()
+{
+ if( ! pCairoInstance )
+ pCairoInstance = new CairoWrapper();
+ return *pCairoInstance;
+}
+
+CairoWrapper::CairoWrapper()
+: mpCairoLib( NULL )
+{
+ static const char* pDisableCairoText = getenv( "SAL_DISABLE_CAIROTEXT" );
+ if( pDisableCairoText && (pDisableCairoText[0] != '0') )
+ return;
+
+ int nDummy;
+ if( !XQueryExtension( GetX11SalData()->GetDisplay()->GetDisplay(), "RENDER", &nDummy, &nDummy, &nDummy ) )
+ return;
+
+#ifdef MACOSX
+ OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libcairo.2.dylib" ));
+#else
+ OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libcairo.so.2" ));
+#endif
+ mpCairoLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT );
+ if( !mpCairoLib )
+ return;
+
+#ifdef DEBUG
+ // check cairo version
+ int (*p_version)();
+ p_version = (int(*)()) osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_version" );
+ const int nVersion = p_version ? (*p_version)() : 0;
+ fprintf( stderr, "CAIRO version=%d\n", nVersion );
+#endif
+
+ mp_xlib_surface_create_with_xrender_format = (cairo_surface_t* (*)(Display *, Drawable , Screen *, XRenderPictFormat *, int , int ))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_xlib_surface_create_with_xrender_format" );
+ mp_surface_destroy = (void(*)(cairo_surface_t*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_surface_destroy" );
+ mp_create = (cairo_t*(*)(cairo_surface_t*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_create" );
+ mp_destroy = (void(*)(cairo_t*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_destroy" );
+ mp_clip = (void(*)(cairo_t*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_clip" );
+ mp_rectangle = (void(*)(cairo_t*, double, double, double, double))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_rectangle" );
+ mp_ft_font_face_create_for_ft_face = (cairo_font_face_t * (*)(FT_Face, int))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_ft_font_face_create_for_ft_face" );
+ mp_ft_font_face_create_for_pattern = (cairo_font_face_t * (*)(void*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_ft_font_face_create_for_pattern" );
+ mp_set_font_face = (void (*)(cairo_t *, cairo_font_face_t *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_face" );
+ mp_font_face_destroy = (void (*)(cairo_font_face_t *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_font_face_destroy" );
+ mp_matrix_init_identity = (void (*)(cairo_matrix_t *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_init_identity" );
+ mp_matrix_scale = (void (*)(cairo_matrix_t *, double, double))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_scale" );
+ mp_matrix_rotate = (void (*)(cairo_matrix_t *, double))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_rotate" );
+ mp_set_font_matrix = (void (*)(cairo_t *, const cairo_matrix_t *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_matrix" );
+ mp_show_glyphs = (void (*)(cairo_t *, const cairo_glyph_t *, int ))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_show_glyphs" );
+ mp_set_source_rgb = (void (*)(cairo_t *, double , double , double ))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_source_rgb" );
+ mp_set_font_options = (void (*)(cairo_t *, const void *options ))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_options" );
+ mp_ft_font_options_substitute = (void (*)(const void *, void *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_ft_font_options_substitute" );
+
+ if( !(
+ mp_xlib_surface_create_with_xrender_format &&
+ mp_surface_destroy &&
+ mp_create &&
+ mp_destroy &&
+ mp_clip &&
+ mp_rectangle &&
+ mp_ft_font_face_create_for_ft_face &&
+ mp_set_font_face &&
+ mp_font_face_destroy &&
+ mp_matrix_init_identity &&
+ mp_matrix_scale &&
+ mp_matrix_rotate &&
+ mp_set_font_matrix &&
+ mp_show_glyphs &&
+ mp_set_source_rgb &&
+ mp_set_font_options &&
+ mp_ft_font_options_substitute
+ ) )
+ {
+ osl_unloadModule( mpCairoLib );
+ mpCairoLib = NULL;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "not all needed symbols were found\n" );
+#endif
+ }
+}
+
+bool CairoWrapper::isCairoRenderable(const ServerFont& rFont)
+{
+ return rFont.GetFtFace() && isValid() && rFont.GetAntialiasAdvice() &&
+ (rFont.NeedsArtificialBold() ? canEmbolden() : true);
+}
+
+} //namespace
+
+CairoFontsCache::LRUFonts CairoFontsCache::maLRUFonts;
+int CairoFontsCache::mnRefCount = 0;
+
+CairoFontsCache::CairoFontsCache()
+{
+ ++mnRefCount;
+}
+
+CairoFontsCache::~CairoFontsCache()
+{
+ --mnRefCount;
+ if (!mnRefCount && !maLRUFonts.empty())
+ {
+ CairoWrapper &rCairo = CairoWrapper::get();
+ LRUFonts::iterator aEnd = maLRUFonts.end();
+ for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI)
+ rCairo.font_face_destroy((cairo_font_face_t*)aI->first);
+ }
+}
+
+void CairoFontsCache::CacheFont(void *pFont, const CairoFontsCache::CacheId &rId)
+{
+ maLRUFonts.push_front( std::pair<void*, CairoFontsCache::CacheId>(pFont, rId) );
+ if (maLRUFonts.size() > 8)
+ {
+ CairoWrapper &rCairo = CairoWrapper::get();
+ rCairo.font_face_destroy((cairo_font_face_t*)maLRUFonts.back().first);
+ maLRUFonts.pop_back();
+ }
+}
+
+void* CairoFontsCache::FindCachedFont(const CairoFontsCache::CacheId &rId)
+{
+ LRUFonts::iterator aEnd = maLRUFonts.end();
+ for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI)
+ if (aI->second == rId)
+ return aI->first;
+ return NULL;
+}
+
+void X11SalGraphics::DrawCairoAAFontString( const ServerFontLayout& rLayout )
+{
+ std::vector<cairo_glyph_t> cairo_glyphs;
+ cairo_glyphs.reserve( 256 );
+
+ Point aPos;
+ sal_GlyphId aGlyphId;
+ for( int nStart = 0; rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
+ {
+ cairo_glyph_t aGlyph;
+ aGlyph.index = aGlyphId & GF_IDXMASK;
+ aGlyph.x = aPos.X();
+ aGlyph.y = aPos.Y();
+ cairo_glyphs.push_back(aGlyph);
+ }
+
+ if (cairo_glyphs.empty())
+ return;
+
+ // find a XRenderPictFormat compatible with the Drawable
+ XRenderPictFormat* pVisualFormat = GetXRenderFormat();
+ DBG_ASSERT( pVisualFormat!=NULL, "no matching XRenderPictFormat for text" );
+ if( !pVisualFormat )
+ return;
+
+ CairoWrapper &rCairo = CairoWrapper::get();
+
+ Display* pDisplay = GetXDisplay();
+
+ cairo_surface_t *surface = rCairo.xlib_surface_create_with_xrender_format (pDisplay,
+ hDrawable_, ScreenOfDisplay(pDisplay, m_nScreen), pVisualFormat, SAL_MAX_INT16, SAL_MAX_INT16);
+
+ /*
+ * It might be ideal to cache surface and cairo context between calls and
+ * only destroy it when the drawable changes, but to do that we need to at
+ * least change the SalFrame etc impls to dtor the SalGraphics *before* the
+ * destruction of the windows they reference
+ */
+ cairo_t *cr = rCairo.create(surface);
+ rCairo.surface_destroy(surface);
+
+ if (const void *pOptions = Application::GetSettings().GetStyleSettings().GetCairoFontOptions())
+ rCairo.set_font_options( cr, pOptions);
+
+ if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
+ {
+ for (long i = 0; i < mpClipRegion->numRects; ++i)
+ {
+ rCairo.rectangle(cr,
+ mpClipRegion->rects[i].x1,
+ mpClipRegion->rects[i].y1,
+ mpClipRegion->rects[i].x2 - mpClipRegion->rects[i].x1,
+ mpClipRegion->rects[i].y2 - mpClipRegion->rects[i].y1);
+ }
+ rCairo.clip(cr);
+ }
+
+ rCairo.set_source_rgb(cr,
+ SALCOLOR_RED(nTextColor_)/255.0,
+ SALCOLOR_GREEN(nTextColor_)/255.0,
+ SALCOLOR_BLUE(nTextColor_)/255.0);
+
+ ServerFont& rFont = rLayout.GetServerFont();
+
+ cairo_font_face_t* font_face = NULL;
+
+ void* pFace = rFont.GetFtFace();
+ CairoFontsCache::CacheId aId;
+ aId.mpFace = pFace;
+ aId.mpOptions = rFont.GetFontOptions().get();
+ aId.mbEmbolden = rFont.NeedsArtificialBold();
+ font_face = (cairo_font_face_t*)m_aCairoFontsCache.FindCachedFont(aId);
+ if (!font_face)
+ {
+ const ImplFontOptions *pOptions = rFont.GetFontOptions().get();
+ void *pPattern = pOptions ? pOptions->GetPattern(pFace, aId.mbEmbolden) : NULL;
+ if (pPattern)
+ font_face = rCairo.ft_font_face_create_for_pattern(pPattern);
+ if (!font_face)
+ font_face = rCairo.ft_font_face_create_for_ft_face(pFace, rFont.GetLoadFlags());
+ m_aCairoFontsCache.CacheFont(font_face, aId);
+ }
+
+ rCairo.set_font_face(cr, font_face);
+
+ cairo_matrix_t m;
+ const ImplFontSelectData& rFSD = rFont.GetFontSelData();
+ int nWidth = rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
+
+ rCairo.matrix_init_identity(&m);
+
+ if (rLayout.GetOrientation())
+ rCairo.matrix_rotate(&m, (3600 - rLayout.GetOrientation()) * M_PI / 1800.0);
+
+ rCairo.matrix_scale(&m, nWidth, rFSD.mnHeight);
+ if (rFont.NeedsArtificialItalic())
+ m.xy = -m.xx * 0x6000L / 0x10000L;
+
+ rCairo.set_font_matrix(cr, &m);
+ rCairo.show_glyphs(cr, &cairo_glyphs[0], cairo_glyphs.size());
+ rCairo.destroy(cr);
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::DrawServerAAFontString( const ServerFontLayout& rLayout )
+{
+ // get xrender target for this drawable
+ Picture aDstPic = GetXRenderPicture();
+ if( !aDstPic )
+ return;
+
+ // get a XRenderPicture for the font foreground
+ // TODO: move into own method
+ XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
+ XRenderPictFormat* pVisualFormat = (XRenderPictFormat*)GetXRenderFormat();
+ DBG_ASSERT( pVisualFormat, "we already have a render picture, but XRenderPictFormat==NULL???");
+ const int nVisualDepth = pVisualFormat->depth;
+ SalDisplay::RenderEntry& rEntry = GetDisplay()->GetRenderEntries( m_nScreen )[ nVisualDepth ];
+ if( !rEntry.m_aPicture )
+ {
+ // create and cache XRenderPicture for the font foreground
+ Display* pDisplay = GetXDisplay();
+#ifdef DEBUG
+ int iDummy;
+ unsigned uDummy;
+ XLIB_Window wDummy;
+ unsigned int nDrawDepth;
+ ::XGetGeometry( pDisplay, hDrawable_, &wDummy, &iDummy, &iDummy,
+ &uDummy, &uDummy, &uDummy, &nDrawDepth );
+ DBG_ASSERT( static_cast<unsigned>(nVisualDepth) == nDrawDepth, "depth messed up for XRender" );
+#endif
+
+ rEntry.m_aPixmap = ::XCreatePixmap( pDisplay, hDrawable_, 1, 1, nVisualDepth );
+
+ XRenderPictureAttributes aAttr;
+ aAttr.repeat = true;
+ rEntry.m_aPicture = rRenderPeer.CreatePicture ( rEntry.m_aPixmap, pVisualFormat, CPRepeat, &aAttr );
+ }
+
+ // set font foreground color and opacity
+ XRenderColor aRenderColor = GetXRenderColor( nTextColor_ );
+ rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 );
+
+ // set clipping
+ // TODO: move into GetXRenderPicture()?
+ if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
+ rRenderPeer.SetPictureClipRegion( aDstPic, mpClipRegion );
+
+ ServerFont& rFont = rLayout.GetServerFont();
+ X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
+ GlyphSet aGlyphSet = rGlyphPeer.GetGlyphSet( rFont, m_nScreen );
+
+ Point aPos;
+ static const int MAXGLYPHS = 160;
+ sal_GlyphId aGlyphAry[ MAXGLYPHS ];
+ int nMaxGlyphs = rLayout.GetOrientation() ? 1 : MAXGLYPHS;
+ for( int nStart = 0;;)
+ {
+ int nGlyphs = rLayout.GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart );
+ if( !nGlyphs )
+ break;
+
+ // #i51924# avoid 32->16bit coordinate truncation problem in X11
+ // TODO: reevaluate once displays with >30000 pixels are available
+ if( aPos.X() >= 30000 || aPos.Y() >= 30000 )
+ continue;
+
+ unsigned int aRenderAry[ MAXGLYPHS ];
+ for( int i = 0; i < nGlyphs; ++i )
+ aRenderAry[ i ] = rGlyphPeer.GetGlyphId( rFont, aGlyphAry[i] );
+ rRenderPeer.CompositeString32( rEntry.m_aPicture, aDstPic,
+ aGlyphSet, aPos.X(), aPos.Y(), aRenderAry, nGlyphs );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+bool X11SalGraphics::DrawServerAAForcedString( const ServerFontLayout& rLayout )
+{
+ ServerFont& rFont = rLayout.GetServerFont();
+
+ // prepare glyphs and get extent of operation
+ X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
+ int nXmin = 0;
+ int nXmax = 0;
+ int nYmin = 0;
+ int nYmax = 0;
+ int nStart = 0;
+ Point aPos;
+ sal_GlyphId nGlyph;
+ for( bool bFirst=true; rLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
+ {
+ const RawBitmap* const pRawBitmap = rGlyphPeer.GetRawBitmap( rFont, nGlyph );
+ if( !pRawBitmap )
+ continue;
+
+ const int nX1 = aPos.X() + pRawBitmap->mnXOffset;
+ const int nY1 = aPos.Y() + pRawBitmap->mnYOffset;
+ const int nX2 = nX1 + pRawBitmap->mnWidth;
+ const int nY2 = nY1 + pRawBitmap->mnHeight;
+
+ if( bFirst )
+ {
+ bFirst = false;
+ nXmin = nX1;
+ nXmax = nX2;
+ nYmin = nY1;
+ nYmax = nY2;
+ }
+ else
+ {
+ if( nXmin > nX1 ) nXmin = nX1;
+ if( nXmax < nX2 ) nXmax = nX2;
+ if( nYmin > nY1 ) nYmin = nY1;
+ if( nYmax < nY2 ) nYmax = nY2;
+ }
+ }
+
+ // get XImage
+ GetDisplay()->GetXLib()->PushXErrorLevel( true );
+ Display* pDisplay = GetXDisplay();
+
+ XRectangle aXRect;
+ long nWidth = 1, nHeight = 1;
+ if( m_pFrame )
+ nWidth = m_pFrame->maGeometry.nWidth, nHeight = m_pFrame->maGeometry.nHeight;
+ else if( m_pVDev )
+ nWidth = m_pVDev->GetWidth(), nHeight = m_pVDev->GetHeight();
+
+ if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
+ {
+ // get bounding box
+ XClipBox( mpClipRegion, &aXRect );
+ // clip with window
+ if( aXRect.x < 0 ) aXRect.x = 0;
+
+ if( aXRect.y < 0 ) aXRect.y = 0;
+ if( aXRect.width+aXRect.x > nWidth ) aXRect.width = nWidth-aXRect.x;
+ if( aXRect.height+aXRect.y > nHeight ) aXRect.height = nHeight-aXRect.y;
+ }
+ else
+ {
+ aXRect.x = 0;
+ aXRect.y = 0;
+ aXRect.width = nWidth;
+ aXRect.height = nHeight;
+ }
+ if( m_pFrame )
+ {
+ // clip with screen
+ int nScreenX = m_pFrame->maGeometry.nX+aXRect.x;
+ int nScreenY = m_pFrame->maGeometry.nY+aXRect.y;
+ const Size& rScreenSize = GetDisplay()->getDataForScreen( m_nScreen ).m_aSize;
+ int nScreenW = rScreenSize.Width();
+ int nScreenH = rScreenSize.Height();
+ if( nScreenX < 0 )
+ aXRect.x -= nScreenX, aXRect.width += nScreenX;
+ if( nScreenX+aXRect.width > nScreenW )
+ aXRect.width = nScreenW-nScreenX;
+ if( nScreenY < 0 )
+ aXRect.y -= nScreenY, aXRect.height += nScreenY;
+ if( nScreenY+aXRect.height > nScreenH )
+ aXRect.height = nScreenH-nScreenY;
+ }
+
+
+ if( nXmin < aXRect.x ) nXmin = aXRect.x;
+ if( nYmin < aXRect.y ) nYmin = aXRect.y;
+ if( nXmax >= aXRect.x+aXRect.width ) nXmax = aXRect.x + aXRect.width - 1;
+ if( nYmax >= aXRect.y+aXRect.height ) nYmax = aXRect.y + aXRect.height - 1;
+
+ if( nXmin > nXmax )
+ return false;
+ if( nYmin > nYmax )
+ return false;
+
+ XImage* pImg = XGetImage( pDisplay, hDrawable_,
+ nXmin, nYmin,
+ (nXmax-nXmin+1), (nYmax-nYmin+1),
+ ~0, ZPixmap );
+ if( pImg == NULL )
+ {
+ if( m_pFrame )
+ {
+ // the reason we did not get an image could be that the frame
+ // geometry changed in the meantime; lets get the current geometry
+ // and clip against the current window size as well as the screen
+ // with the current frame position
+ const Size& rScreenSize = GetDisplay()->getDataForScreen(m_nScreen).m_aSize;
+ int nScreenW = rScreenSize.Width();
+ int nScreenH = rScreenSize.Height();
+ XLIB_Window aRoot = None;
+ int x = 0, y = 0;
+ unsigned int w = 0, h = 0, bw = 0, d;
+ XGetGeometry( pDisplay, hDrawable_, &aRoot, &x, &y, &w, &h, &bw, &d );
+ XTranslateCoordinates( pDisplay, hDrawable_, aRoot, 0, 0, &x, &y, &aRoot );
+ if( nXmin + x < 0 ) // clip on left screen edge
+ nXmin += x-nXmin;
+ if( nYmin + y < 0 ) // clip on top screen edge
+ nYmin += y-nYmin;
+ if( nXmax >= int(w) ) // clip on right window egde
+ nXmax = w-1;
+ if( nYmax >= int(h) ) // clip on bottom window edge
+ nYmax = h-1;
+ if( nXmax + x >= nScreenW ) // clip on right screen edge
+ nXmax -= (nXmax + x - nScreenW)+1;
+ if( nYmax + y >= nScreenH ) // clip on bottom screen edge
+ nYmax -= (nYmax + y - nScreenH)+1;
+ if( nXmax >= nXmin && nYmax >= nYmin )
+ {
+ // try again to get the image
+ pImg = XGetImage( pDisplay, hDrawable_,
+ nXmin, nYmin,
+ (nXmax-nXmin+1), (nYmax-nYmin+1),
+ ~0, ZPixmap );
+ }
+ }
+ if( pImg == NULL )
+ {
+ GetDisplay()->GetXLib()->PopXErrorLevel();
+ return false;
+ }
+ }
+
+ // prepare context
+ GC nGC = GetFontGC();
+ XGCValues aGCVal;
+ XGetGCValues( pDisplay, nGC, GCForeground, &aGCVal );
+
+ unsigned long nOrigColor = XGetPixel( pImg, 0, 0 );
+ XPutPixel( pImg, 0, 0, aGCVal.foreground );
+ unsigned char aColor[4];
+ aColor[0] = pImg->data[0];
+ aColor[1] = pImg->data[1];
+ aColor[2] = pImg->data[2];
+ aColor[3] = pImg->data[3];
+ XPutPixel( pImg, 0, 0, nOrigColor );
+
+ // work on XImage
+ const int bpp = pImg->bits_per_pixel >> 3;
+ for( nStart = 0; rLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
+ {
+ const RawBitmap* const pRawBitmap = rGlyphPeer.GetRawBitmap( rFont, nGlyph );
+ if( !pRawBitmap )
+ continue;
+
+ const int nX1 = aPos.X() + pRawBitmap->mnXOffset;
+ const int nY1 = aPos.Y() + pRawBitmap->mnYOffset;
+
+ if( (nX1 <= nXmax) && (int(nX1 + pRawBitmap->mnWidth) > nXmin)
+ && (nY1 <= nYmax) && (int(nY1 + pRawBitmap->mnHeight) > nYmin) )
+ {
+ const unsigned char* p10 = pRawBitmap->mpBits;
+ unsigned char* p20 = (unsigned char*)pImg->data; // dest left limit
+ p20 += (nY1 - nYmin) * pImg->bytes_per_line;
+ unsigned char* p21 = p20 + (nX1 - nXmin + pImg->xoffset) * bpp;
+ int y = pRawBitmap->mnHeight;
+ if( y > nYmax - nY1 )
+ y = nYmax - nY1 + 1;
+ while( --y >= 0 )
+ {
+ if( p20 >= (unsigned char*)pImg->data )
+ {
+ unsigned char* const p22 = p20 + pImg->width * bpp; // dest right limit
+ unsigned char* pDst = p21;
+ const unsigned char* pSrc = p10;
+ for( int x = pRawBitmap->mnWidth; (--x >= 0) && (p22 > pDst); ++pSrc )
+ {
+ if( (*pSrc == 0) || (p20 > pDst) ) // keep background
+ pDst += bpp;
+ else if( *pSrc == 0xFF ) // paint foreground
+ {
+ const unsigned char* pColor = aColor;
+ for( int z = bpp; --z >= 0; ++pColor, ++pDst )
+ *pDst = *pColor;
+ }
+ else // blend fg into bg
+ {
+ const unsigned char* pColor = aColor;
+ for( int z = bpp; --z >= 0; ++pColor, ++pDst )
+ // theoretically it should be *257) >> 16
+ // but the error is <0.4% worst case and we are in
+ // the innermost loop of very perf-sensitive code
+
+ *pDst += (*pSrc * ((int)*pColor - *pDst)) >> 8;
+ }
+ }
+ }
+ p10 += pRawBitmap->mnScanlineSize;
+ p20 += pImg->bytes_per_line;
+ p21 += pImg->bytes_per_line;
+ }
+ }
+ }
+
+ // put XImage
+ XPutImage( pDisplay, hDrawable_, nGC, pImg,
+ 0, 0, nXmin, nYmin, (nXmax - nXmin + 1), (nYmax - nYmin + 1) );
+ XDestroyImage( pImg );
+
+ GetDisplay()->GetXLib()->PopXErrorLevel();
+ return true;
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::DrawServerSimpleFontString( const ServerFontLayout& rSalLayout )
+{
+ ServerFont& rFont = rSalLayout.GetServerFont();
+ X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
+
+ Display* pDisplay = GetXDisplay();
+ GC nGC = GetFontGC();
+
+ XGCValues aGCVal;
+ aGCVal.fill_style = FillStippled;
+ aGCVal.line_width = 0;
+ GC tmpGC = XCreateGC( pDisplay, hDrawable_, GCFillStyle|GCLineWidth, &aGCVal );
+ XCopyGC( pDisplay, nGC, (1<<GCLastBit)-(1+GCFillStyle+GCLineWidth), tmpGC );
+
+ Point aPos;
+ sal_GlyphId nGlyph;
+ for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
+ {
+ // #i51924# avoid 32->16bit coordinate truncation problem in X11
+ // TODO: reevaluate once displays with >30000 pixels are available
+ if( aPos.X() >= 30000 || aPos.Y() >= 30000 )
+ continue;
+
+ Pixmap aStipple = rGlyphPeer.GetPixmap( rFont, nGlyph, m_nScreen );
+ const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyph );
+
+ if( aStipple != None )
+ {
+ const int nDestX = aPos.X() + rGM.GetOffset().X();
+ const int nDestY = aPos.Y() + rGM.GetOffset().Y();
+
+ aGCVal.stipple = aStipple;
+ aGCVal.ts_x_origin = nDestX;
+ aGCVal.ts_y_origin = nDestY;
+ XChangeGC( pDisplay, tmpGC, GCStipple|GCTileStipXOrigin|GCTileStipYOrigin, &aGCVal );
+
+ const int nWidth = rGM.GetSize().Width();
+ const int nHeight = rGM.GetSize().Height();
+ XFillRectangle( pDisplay, hDrawable_, tmpGC, nDestX, nDestY, nWidth, nHeight );
+ }
+ }
+
+ XFreeGC( pDisplay, tmpGC );
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::DrawServerFontLayout( const ServerFontLayout& rLayout )
+{
+ // draw complex text
+ ServerFont& rFont = rLayout.GetServerFont();
+ const bool bVertical = rFont.GetFontSelData().mbVertical;
+
+ if( !bVertical && CairoWrapper::get().isCairoRenderable(rFont) )
+ DrawCairoAAFontString( rLayout );
+ else
+ {
+ X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
+ if( rGlyphPeer.GetGlyphSet( rFont, m_nScreen ) )
+ DrawServerAAFontString( rLayout );
+ else if( !rGlyphPeer.ForcedAntialiasing( rFont, m_nScreen ) )
+ DrawServerSimpleFontString( rLayout );
+ else
+ DrawServerAAForcedString( rLayout );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+const ImplFontCharMap* X11SalGraphics::GetImplFontCharMap() const
+{
+ if( !mpServerFont[0] )
+ return NULL;
+
+ const ImplFontCharMap* pIFCMap = mpServerFont[0]->GetImplFontCharMap();
+ return pIFCMap;
+}
+
+bool X11SalGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rGetImplFontCapabilities) const
+{
+ if (!mpServerFont[0])
+ return false;
+ return mpServerFont[0]->GetFontCapabilities(rGetImplFontCapabilities);
+}
+
+// ----------------------------------------------------------------------------
+//
+// SalGraphics
+//
+// ----------------------------------------------------------------------------
+
+sal_uInt16 X11SalGraphics::SetFont( ImplFontSelectData *pEntry, int nFallbackLevel )
+{
+ sal_uInt16 nRetVal = 0;
+ if( !setFont( pEntry, nFallbackLevel ) )
+ nRetVal |= SAL_SETFONT_BADFONT;
+ if( bPrinter_ || (mpServerFont[ nFallbackLevel ] != NULL) )
+ nRetVal |= SAL_SETFONT_USEDRAWTEXTARRAY;
+ return nRetVal;
+}
+
+// ----------------------------------------------------------------------------
+
+void
+X11SalGraphics::SetTextColor( SalColor nSalColor )
+{
+ if( nTextColor_ != nSalColor )
+ {
+ nTextColor_ = nSalColor;
+ nTextPixel_ = GetPixel( nSalColor );
+ bFontGC_ = sal_False;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+bool X11SalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
+ const String& rFileURL, const String& rFontName )
+{
+ // inform PSP font manager
+ rtl::OUString aUSystemPath;
+ OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFileURL, aUSystemPath ) );
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ OString aOFileName( OUStringToOString( aUSystemPath, aEncoding ) );
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ int nFontId = rMgr.addFontFile( aOFileName, 0 );
+ if( !nFontId )
+ return false;
+
+ // prepare font data
+ psp::FastPrintFontInfo aInfo;
+ rMgr.getFontFastInfo( nFontId, aInfo );
+ aInfo.m_aFamilyName = rFontName;
+
+ // inform glyph cache of new font
+ ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo );
+ aDFA.mnQuality += 5800;
+
+ int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
+ if( nFaceNum < 0 )
+ nFaceNum = 0;
+
+ GlyphCache& rGC = X11GlyphCache::GetInstance();
+ const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
+ rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA );
+
+ // announce new font to device's font list
+ rGC.AnnounceFonts( pFontList );
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+
+void RegisterFontSubstitutors( ImplDevFontList* );
+
+void X11SalGraphics::GetDevFontList( ImplDevFontList *pList )
+{
+ // prepare the GlyphCache using psprint's font infos
+ X11GlyphCache& rGC = X11GlyphCache::GetInstance();
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ ::std::list< psp::fontID > aList;
+ ::std::list< psp::fontID >::iterator it;
+ psp::FastPrintFontInfo aInfo;
+ rMgr.getFontList( aList );
+ for( it = aList.begin(); it != aList.end(); ++it )
+ {
+ if( !rMgr.getFontFastInfo( *it, aInfo ) )
+ continue;
+
+ // the GlyphCache must not bother with builtin fonts because
+ // it cannot access or use them anyway
+ if( aInfo.m_eType == psp::fonttype::Builtin )
+ continue;
+
+ // normalize face number to the GlyphCache
+ int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
+ if( nFaceNum < 0 )
+ nFaceNum = 0;
+
+ // for fonts where extra kerning info can be provided on demand
+ // an ExtraKernInfo object is supplied
+ const ExtraKernInfo* pExtraKernInfo = NULL;
+ if( aInfo.m_eType == psp::fonttype::Type1 )
+ pExtraKernInfo = new PspKernInfo( *it );
+
+ // inform GlyphCache about this font provided by the PsPrint subsystem
+ ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo );
+ aDFA.mnQuality += 4096;
+ const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
+ rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA, pExtraKernInfo );
+ }
+
+ // announce glyphcache fonts
+ rGC.AnnounceFonts( pList );
+
+ // register platform specific font substitutions if available
+ if( rMgr.hasFontconfig() )
+ RegisterFontSubstitutors( pList );
+
+ ImplGetSVData()->maGDIData.mbNativeFontConfig = rMgr.hasFontconfig();
+}
+
+// ----------------------------------------------------------------------------
+
+void X11SalGraphics::GetDevFontSubstList( OutputDevice* )
+{
+ // no device specific font substitutions on X11 needed
+}
+
+// ----------------------------------------------------------------------------
+
+void cairosubcallback( void* pPattern )
+{
+ CairoWrapper& rCairo = CairoWrapper::get();
+ if( !rCairo.isValid() )
+ return;
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const void* pFontOptions = rStyleSettings.GetCairoFontOptions();
+ if( !pFontOptions )
+ return;
+ rCairo.ft_font_options_substitute( pFontOptions, pPattern );
+}
+
+ImplFontOptions* GetFCFontOptions( const ImplFontAttributes& rFontAttributes, int nSize)
+{
+ // TODO: get rid of these insane enum-conversions
+ // e.g. by using the classic vclenum values inside VCL
+
+ psp::FastPrintFontInfo aInfo;
+ // set family name
+ aInfo.m_aFamilyName = rFontAttributes.GetFamilyName();
+ // set italic
+ switch( rFontAttributes.GetSlant() )
+ {
+ case ITALIC_NONE:
+ aInfo.m_eItalic = psp::italic::Upright;
+ break;
+ case ITALIC_NORMAL:
+ aInfo.m_eItalic = psp::italic::Italic;
+ break;
+ case ITALIC_OBLIQUE:
+ aInfo.m_eItalic = psp::italic::Oblique;
+ break;
+ default:
+ aInfo.m_eItalic = psp::italic::Unknown;
+ break;
+ }
+ // set weight
+ switch( rFontAttributes.GetWeight() )
+ {
+ case WEIGHT_THIN:
+ aInfo.m_eWeight = psp::weight::Thin;
+ break;
+ case WEIGHT_ULTRALIGHT:
+ aInfo.m_eWeight = psp::weight::UltraLight;
+ break;
+ case WEIGHT_LIGHT:
+ aInfo.m_eWeight = psp::weight::Light;
+ break;
+ case WEIGHT_SEMILIGHT:
+ aInfo.m_eWeight = psp::weight::SemiLight;
+ break;
+ case WEIGHT_NORMAL:
+ aInfo.m_eWeight = psp::weight::Normal;
+ break;
+ case WEIGHT_MEDIUM:
+ aInfo.m_eWeight = psp::weight::Medium;
+ break;
+ case WEIGHT_SEMIBOLD:
+ aInfo.m_eWeight = psp::weight::SemiBold;
+ break;
+ case WEIGHT_BOLD:
+ aInfo.m_eWeight = psp::weight::Bold;
+ break;
+ case WEIGHT_ULTRABOLD:
+ aInfo.m_eWeight = psp::weight::UltraBold;
+ break;
+ case WEIGHT_BLACK:
+ aInfo.m_eWeight = psp::weight::Black;
+ break;
+ default:
+ aInfo.m_eWeight = psp::weight::Unknown;
+ break;
+ }
+ // set width
+ switch( rFontAttributes.GetWidthType() )
+ {
+ case WIDTH_ULTRA_CONDENSED:
+ aInfo.m_eWidth = psp::width::UltraCondensed;
+ break;
+ case WIDTH_EXTRA_CONDENSED:
+ aInfo.m_eWidth = psp::width::ExtraCondensed;
+ break;
+ case WIDTH_CONDENSED:
+ aInfo.m_eWidth = psp::width::Condensed;
+ break;
+ case WIDTH_SEMI_CONDENSED:
+ aInfo.m_eWidth = psp::width::SemiCondensed;
+ break;
+ case WIDTH_NORMAL:
+ aInfo.m_eWidth = psp::width::Normal;
+ break;
+ case WIDTH_SEMI_EXPANDED:
+ aInfo.m_eWidth = psp::width::SemiExpanded;
+ break;
+ case WIDTH_EXPANDED:
+ aInfo.m_eWidth = psp::width::Expanded;
+ break;
+ case WIDTH_EXTRA_EXPANDED:
+ aInfo.m_eWidth = psp::width::ExtraExpanded;
+ break;
+ case WIDTH_ULTRA_EXPANDED:
+ aInfo.m_eWidth = psp::width::UltraExpanded;
+ break;
+ default:
+ aInfo.m_eWidth = psp::width::Unknown;
+ break;
+ }
+
+ const psp::PrintFontManager& rPFM = psp::PrintFontManager::get();
+ return rPFM.getFontOptions(aInfo, nSize, cairosubcallback);
+}
+
+// ----------------------------------------------------------------------------
+
+void
+X11SalGraphics::GetFontMetric( ImplFontMetricData *pMetric, int nFallbackLevel )
+{
+ if( nFallbackLevel >= MAX_FALLBACK )
+ return;
+
+ if( mpServerFont[nFallbackLevel] != NULL )
+ {
+ long rDummyFactor;
+ mpServerFont[nFallbackLevel]->FetchFontMetric( *pMetric, rDummyFactor );
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+sal_uLong
+X11SalGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData *pKernPairs )
+{
+ if( ! bPrinter_ )
+ {
+ if( mpServerFont[0] != NULL )
+ {
+ ImplKernPairData* pTmpKernPairs;
+ sal_uLong nGotPairs = mpServerFont[0]->GetKernPairs( &pTmpKernPairs );
+ for( unsigned int i = 0; i < nPairs && i < nGotPairs; ++i )
+ pKernPairs[ i ] = pTmpKernPairs[ i ];
+ delete[] pTmpKernPairs;
+ return nGotPairs;
+ }
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+
+sal_Bool X11SalGraphics::GetGlyphBoundRect( long nGlyphIndex, Rectangle& rRect )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel < 0 || nLevel >= MAX_FALLBACK )
+ return sal_False;
+
+ ServerFont* pSF = mpServerFont[ nLevel ];
+ if( !pSF )
+ return sal_False;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ const GlyphMetric& rGM = pSF->GetGlyphMetric( nGlyphIndex );
+ rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
+ return sal_True;
+}
+
+// ---------------------------------------------------------------------------
+
+sal_Bool X11SalGraphics::GetGlyphOutline( long nGlyphIndex,
+ ::basegfx::B2DPolyPolygon& rPolyPoly )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return sal_False;
+
+ ServerFont* pSF = mpServerFont[ nLevel ];
+ if( !pSF )
+ return sal_False;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ if( pSF->GetGlyphOutline( nGlyphIndex, rPolyPoly ) )
+ return sal_True;
+
+ return sal_False;
+}
+
+//--------------------------------------------------------------------------
+
+SalLayout* X11SalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+{
+ SalLayout* pLayout = NULL;
+
+ if( mpServerFont[ nFallbackLevel ]
+ && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) )
+ {
+#ifdef ENABLE_GRAPHITE
+ // Is this a Graphite font?
+ if (!bDisableGraphite_ &&
+ GraphiteServerFontLayout::IsGraphiteEnabledFont(mpServerFont[nFallbackLevel]))
+ {
+ pLayout = new GraphiteServerFontLayout(*mpServerFont[nFallbackLevel]);
+ }
+ else
+#endif
+ pLayout = new ServerFontLayout( *mpServerFont[ nFallbackLevel ] );
+ }
+
+ return pLayout;
+}
+
+//--------------------------------------------------------------------------
+
+SystemFontData X11SalGraphics::GetSysFontData( int nFallbacklevel ) const
+{
+ SystemFontData aSysFontData;
+ aSysFontData.nSize = sizeof( SystemFontData );
+ aSysFontData.nFontId = 0;
+
+ if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
+ if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+
+ if (mpServerFont[nFallbacklevel] != NULL)
+ {
+ ServerFont* rFont = mpServerFont[nFallbacklevel];
+ aSysFontData.nFontId = rFont->GetFtFace();
+ aSysFontData.nFontFlags = rFont->GetLoadFlags();
+ aSysFontData.bFakeBold = rFont->NeedsArtificialBold();
+ aSysFontData.bFakeItalic = rFont->NeedsArtificialItalic();
+ aSysFontData.bAntialias = rFont->GetAntialiasAdvice();
+ aSysFontData.bVerticalCharacterType = rFont->GetFontSelData().mbVertical;
+ }
+
+ return aSysFontData;
+}
+
+//--------------------------------------------------------------------------
+
+sal_Bool X11SalGraphics::CreateFontSubset(
+ const rtl::OUString& rToFile,
+ const ImplFontData* pFont,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphCount,
+ FontSubsetInfo& rInfo
+ )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ bool bSuccess = rMgr.createFontSubset( rInfo,
+ aFont,
+ rToFile,
+ pGlyphIDs,
+ pEncoding,
+ pWidths,
+ nGlyphCount );
+ return bSuccess;
+}
+
+//--------------------------------------------------------------------------
+
+const void* X11SalGraphics::GetEmbedFontData( const ImplFontData* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen );
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::FreeEmbedFontData( const void* pData, long nLen )
+{
+ PspGraphics::DoFreeEmbedFontData( pData, nLen );
+}
+
+//--------------------------------------------------------------------------
+
+const Ucs2SIntMap* X11SalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded );
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+
+// ===========================================================================
+// platform specific font substitution hooks
+
+class FcPreMatchSubstititution
+: public ImplPreMatchFontSubstitution
+{
+public:
+ bool FindFontSubstitute( ImplFontSelectData& ) const;
+
+private:
+ typedef ::boost::unordered_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >
+ CachedFontMapType;
+ mutable CachedFontMapType maCachedFontMap;
+};
+
+class FcGlyphFallbackSubstititution
+: public ImplGlyphFallbackFontSubstitution
+{
+ // TODO: add a cache
+public:
+ bool FindFontSubstitute( ImplFontSelectData&, OUString& rMissingCodes ) const;
+};
+
+void RegisterFontSubstitutors( ImplDevFontList* pList )
+{
+ // init font substitution defaults
+ int nDisableBits = 0;
+#ifdef SOLARIS
+ nDisableBits = 1; // disable "font fallback" here on default
+#endif
+ // apply the environment variable if any
+ const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
+ if( pEnvStr )
+ {
+ if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
+ nDisableBits = (*pEnvStr - '0');
+ else
+ nDisableBits = ~0U; // no specific bits set: disable all
+ }
+
+ // register font fallback substitutions (unless disabled by bit0)
+ if( (nDisableBits & 1) == 0 )
+ {
+ static FcPreMatchSubstititution aSubstPreMatch;
+ pList->SetPreMatchHook( &aSubstPreMatch );
+ }
+
+ // register glyph fallback substitutions (unless disabled by bit1)
+ if( (nDisableBits & 2) == 0 )
+ {
+ static FcGlyphFallbackSubstititution aSubstFallback;
+ pList->SetFallbackHook( &aSubstFallback );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static ImplFontSelectData GetFcSubstitute(const ImplFontSelectData &rFontSelData, OUString& rMissingCodes )
+{
+ ImplFontSelectData aRet(rFontSelData);
+
+ const rtl::OString aLangAttrib = MsLangId::convertLanguageToIsoByteString( rFontSelData.meLanguage );
+
+ psp::italic::type eItalic = psp::italic::Unknown;
+ if( rFontSelData.GetSlant() != ITALIC_DONTKNOW )
+ {
+ switch( rFontSelData.GetSlant() )
+ {
+ case ITALIC_NONE: eItalic = psp::italic::Upright; break;
+ case ITALIC_NORMAL: eItalic = psp::italic::Italic; break;
+ case ITALIC_OBLIQUE: eItalic = psp::italic::Oblique; break;
+ default:
+ break;
+ }
+ }
+
+ psp::weight::type eWeight = psp::weight::Unknown;
+ if( rFontSelData.GetWeight() != WEIGHT_DONTKNOW )
+ {
+ switch( rFontSelData.GetWeight() )
+ {
+ case WEIGHT_THIN: eWeight = psp::weight::Thin; break;
+ case WEIGHT_ULTRALIGHT: eWeight = psp::weight::UltraLight; break;
+ case WEIGHT_LIGHT: eWeight = psp::weight::Light; break;
+ case WEIGHT_SEMILIGHT: eWeight = psp::weight::SemiLight; break;
+ case WEIGHT_NORMAL: eWeight = psp::weight::Normal; break;
+ case WEIGHT_MEDIUM: eWeight = psp::weight::Medium; break;
+ case WEIGHT_SEMIBOLD: eWeight = psp::weight::SemiBold; break;
+ case WEIGHT_BOLD: eWeight = psp::weight::Bold; break;
+ case WEIGHT_ULTRABOLD: eWeight = psp::weight::UltraBold; break;
+ case WEIGHT_BLACK: eWeight = psp::weight::Black; break;
+ default:
+ break;
+ }
+ }
+
+ psp::width::type eWidth = psp::width::Unknown;
+ if( rFontSelData.GetWidthType() != WIDTH_DONTKNOW )
+ {
+ switch( rFontSelData.GetWidthType() )
+ {
+ case WIDTH_ULTRA_CONDENSED: eWidth = psp::width::UltraCondensed; break;
+ case WIDTH_EXTRA_CONDENSED: eWidth = psp::width::ExtraCondensed; break;
+ case WIDTH_CONDENSED: eWidth = psp::width::Condensed; break;
+ case WIDTH_SEMI_CONDENSED: eWidth = psp::width::SemiCondensed; break;
+ case WIDTH_NORMAL: eWidth = psp::width::Normal; break;
+ case WIDTH_SEMI_EXPANDED: eWidth = psp::width::SemiExpanded; break;
+ case WIDTH_EXPANDED: eWidth = psp::width::Expanded; break;
+ case WIDTH_EXTRA_EXPANDED: eWidth = psp::width::ExtraExpanded; break;
+ case WIDTH_ULTRA_EXPANDED: eWidth = psp::width::UltraExpanded; break;
+ default:
+ break;
+ }
+ }
+
+ psp::pitch::type ePitch = psp::pitch::Unknown;
+ if( rFontSelData.GetPitch() != PITCH_DONTKNOW )
+ {
+ switch( rFontSelData.GetPitch() )
+ {
+ case PITCH_FIXED: ePitch=psp::pitch::Fixed; break;
+ case PITCH_VARIABLE: ePitch=psp::pitch::Variable; break;
+ default:
+ break;
+ }
+ }
+
+ const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ aRet.maSearchName = rMgr.Substitute( rFontSelData.maTargetName, rMissingCodes, aLangAttrib, eItalic, eWeight, eWidth, ePitch);
+
+ switch (eItalic)
+ {
+ case psp::italic::Upright: aRet.meItalic = ITALIC_NONE; break;
+ case psp::italic::Italic: aRet.meItalic = ITALIC_NORMAL; break;
+ case psp::italic::Oblique: aRet.meItalic = ITALIC_OBLIQUE; break;
+ default:
+ break;
+ }
+
+ switch (eWeight)
+ {
+ case psp::weight::Thin: aRet.meWeight = WEIGHT_THIN; break;
+ case psp::weight::UltraLight: aRet.meWeight = WEIGHT_ULTRALIGHT; break;
+ case psp::weight::Light: aRet.meWeight = WEIGHT_LIGHT; break;
+ case psp::weight::SemiLight: aRet.meWeight = WEIGHT_SEMILIGHT; break;
+ case psp::weight::Normal: aRet.meWeight = WEIGHT_NORMAL; break;
+ case psp::weight::Medium: aRet.meWeight = WEIGHT_MEDIUM; break;
+ case psp::weight::SemiBold: aRet.meWeight = WEIGHT_SEMIBOLD; break;
+ case psp::weight::Bold: aRet.meWeight = WEIGHT_BOLD; break;
+ case psp::weight::UltraBold: aRet.meWeight = WEIGHT_ULTRABOLD; break;
+ case psp::weight::Black: aRet.meWeight = WEIGHT_BLACK; break;
+ default:
+ break;
+ }
+
+ switch (eWidth)
+ {
+ case psp::width::UltraCondensed: aRet.meWidthType = WIDTH_ULTRA_CONDENSED; break;
+ case psp::width::ExtraCondensed: aRet.meWidthType = WIDTH_EXTRA_CONDENSED; break;
+ case psp::width::Condensed: aRet.meWidthType = WIDTH_CONDENSED; break;
+ case psp::width::SemiCondensed: aRet.meWidthType = WIDTH_SEMI_CONDENSED; break;
+ case psp::width::Normal: aRet.meWidthType = WIDTH_NORMAL; break;
+ case psp::width::SemiExpanded: aRet.meWidthType = WIDTH_SEMI_EXPANDED; break;
+ case psp::width::Expanded: aRet.meWidthType = WIDTH_EXPANDED; break;
+ case psp::width::ExtraExpanded: aRet.meWidthType = WIDTH_EXTRA_EXPANDED; break;
+ case psp::width::UltraExpanded: aRet.meWidthType = WIDTH_ULTRA_EXPANDED; break;
+ default:
+ break;
+ }
+
+ switch (ePitch)
+ {
+ case psp::pitch::Fixed: aRet.mePitch = PITCH_FIXED; break;
+ case psp::pitch::Variable: aRet.mePitch = PITCH_VARIABLE; break;
+ default:
+ break;
+ }
+
+ return aRet;
+}
+
+namespace
+{
+ bool uselessmatch(const ImplFontSelectData &rOrig, const ImplFontSelectData &rNew)
+ {
+ return
+ (
+ rOrig.maTargetName == rNew.maSearchName &&
+ rOrig.meWeight == rNew.meWeight &&
+ rOrig.meItalic == rNew.meItalic &&
+ rOrig.mePitch == rNew.mePitch &&
+ rOrig.meWidthType == rNew.meWidthType
+ );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+bool FcPreMatchSubstititution::FindFontSubstitute( ImplFontSelectData &rFontSelData ) const
+{
+ // We dont' actually want to talk to Fontconfig at all for symbol fonts
+ if( rFontSelData.IsSymbolFont() )
+ return false;
+ // StarSymbol is a unicode font, but it still deserves the symbol flag
+ if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
+ || 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
+ return false;
+
+ CachedFontMapType::const_iterator itr = maCachedFontMap.find(rFontSelData.maTargetName);
+ if (itr != maCachedFontMap.end())
+ {
+ // Cached substitution pair
+ rFontSelData.maSearchName = itr->second;
+ return true;
+ }
+
+ rtl::OUString aDummy;
+ const ImplFontSelectData aOut = GetFcSubstitute( rFontSelData, aDummy );
+
+ maCachedFontMap.insert(
+ CachedFontMapType::value_type(rFontSelData.maTargetName, aOut.maSearchName));
+
+ if( !aOut.maSearchName.Len() )
+ return false;
+
+ const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
+
+#ifdef DEBUG
+ const ByteString aOrigName( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
+ const ByteString aSubstName( aOut.maSearchName, RTL_TEXTENCODING_UTF8 );
+ printf( "FcPreMatchSubstititution \"%s\" bipw=%d%d%d%d -> ",
+ aOrigName.GetBuffer(), rFontSelData.meWeight, rFontSelData.meItalic,
+ rFontSelData.mePitch, rFontSelData.meWidthType );
+ if( !bHaveSubstitute )
+ printf( "no substitute available\n" );
+ else
+ printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.GetBuffer(),
+ aOut.meWeight, aOut.meItalic, aOut.mePitch, aOut.meWidthType );
+#endif
+
+ if( bHaveSubstitute )
+ rFontSelData = aOut;
+
+ return bHaveSubstitute;
+}
+
+// -----------------------------------------------------------------------
+
+bool FcGlyphFallbackSubstititution::FindFontSubstitute( ImplFontSelectData& rFontSelData,
+ rtl::OUString& rMissingCodes ) const
+{
+ // We dont' actually want to talk to Fontconfig at all for symbol fonts
+ if( rFontSelData.IsSymbolFont() )
+ return false;
+ // StarSymbol is a unicode font, but it still deserves the symbol flag
+ if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
+ || 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
+ return false;
+
+ const ImplFontSelectData aOut = GetFcSubstitute( rFontSelData, rMissingCodes );
+ // TODO: cache the unicode + srcfont specific result
+ // FC doing it would be preferable because it knows the invariables
+ // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
+ // whereas we would have to check for every size or attribute
+ if( !aOut.maSearchName.Len() )
+ return false;
+
+ const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
+
+#ifdef DEBUG
+ const ByteString aOrigName( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
+ const ByteString aSubstName( aOut.maSearchName, RTL_TEXTENCODING_UTF8 );
+ printf( "FcGFSubstititution \"%s\" bipw=%d%d%d%d ->",
+ aOrigName.GetBuffer(), rFontSelData.meWeight, rFontSelData.meItalic,
+ rFontSelData.mePitch, rFontSelData.meWidthType );
+ if( !bHaveSubstitute )
+ printf( "no substitute available\n" );
+ else
+ printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.GetBuffer(),
+ aOut.meWeight, aOut.meItalic, aOut.mePitch, aOut.meWidthType );
+#endif
+
+ if( bHaveSubstitute )
+ rFontSelData = aOut;
+
+ return bHaveSubstitute;
+}
+
+// ===========================================================================
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/salprnpsp.cxx b/vcl/unx/generic/gdi/salprnpsp.cxx
new file mode 100644
index 000000000000..009621a9e22e
--- /dev/null
+++ b/vcl/unx/generic/gdi/salprnpsp.cxx
@@ -0,0 +1,1489 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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"
+
+/**
+ this file implements the sal printer interface ( SalPrinter, SalInfoPrinter
+ and some printer relevant methods of SalInstance and SalGraphicsData )
+
+ as aunderlying library the printer features of psprint are used.
+
+ The query methods of a SalInfoPrinter are implemented by querying psprint
+
+ The job methods of a SalPrinter are implemented by calling psprint
+ printer job functions.
+ */
+
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include "rtl/ustring.hxx"
+
+#include "osl/module.h"
+
+#include "vcl/svapp.hxx"
+#include "vcl/print.hxx"
+#include "vcl/pdfwriter.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include <unx/salunx.h>
+#include "unx/saldisp.hxx"
+#include "unx/salinst.h"
+#include "unx/salprn.h"
+#include "unx/salframe.h"
+#include "unx/pspgraphics.h"
+#include "unx/saldata.hxx"
+
+#include "jobset.h"
+#include "print.h"
+#include "salptype.hxx"
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+using namespace psp;
+using namespace com::sun::star;
+
+using ::rtl::OUString;
+using ::rtl::OUStringHash;
+using ::rtl::OUStringToOString;
+
+/*
+ * static helpers
+ */
+
+static oslModule driverLib = NULL;
+extern "C"
+{
+typedef int(*setupFunction)(PrinterInfo&);
+static setupFunction pSetupFunction = NULL;
+typedef int(*faxFunction)(String&);
+static faxFunction pFaxNrFunction = NULL;
+}
+
+static String getPdfDir( const PrinterInfo& rInfo )
+{
+ String aDir;
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( ! aToken.compareToAscii( "pdf=", 4 ) )
+ {
+ sal_Int32 nPos = 0;
+ aDir = aToken.getToken( 1, '=', nPos );
+ if( ! aDir.Len() )
+ aDir = String( ByteString( getenv( "HOME" ) ), osl_getThreadTextEncoding() );
+ break;
+ }
+ }
+ return aDir;
+}
+
+static void getPaLib()
+{
+ if( ! driverLib )
+ {
+ OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( _XSALSET_LIBNAME ) );
+ driverLib = osl_loadModuleRelative( (oslGenericFunction)getPaLib, aLibName.pData, SAL_LOADMODULE_DEFAULT );
+ if ( !driverLib )
+ {
+ return;
+ }
+
+ pSetupFunction = (setupFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_SetupPrinterDriver" );
+ if ( !pSetupFunction )
+ fprintf( stderr, "could not resolve Sal_SetupPrinterDriver\n" );
+
+ pFaxNrFunction = (faxFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_queryFaxNumber" );
+ if ( !pFaxNrFunction )
+ fprintf( stderr, "could not resolve Sal_queryFaxNumber\n" );
+ }
+}
+
+inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); }
+
+inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); }
+
+static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData )
+{
+ pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT);
+
+ // copy page size
+ String aPaper;
+ int width, height;
+
+ rData.m_aContext.getPageSize( aPaper, width, height );
+ pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 ));
+
+ pJobSetup->mnPaperWidth = 0;
+ pJobSetup->mnPaperHeight = 0;
+ if( pJobSetup->mePaperFormat == PAPER_USER )
+ {
+ // transform to 100dth mm
+ width = PtTo10Mu( width );
+ height = PtTo10Mu( height );
+
+ if( rData.m_eOrientation == psp::orientation::Portrait )
+ {
+ pJobSetup->mnPaperWidth = width;
+ pJobSetup->mnPaperHeight= height;
+ }
+ else
+ {
+ pJobSetup->mnPaperWidth = height;
+ pJobSetup->mnPaperHeight= width;
+ }
+ }
+
+ // copy input slot
+ const PPDKey* pKey = NULL;
+ const PPDValue* pValue = NULL;
+
+ pJobSetup->mnPaperBin = 0;
+ if( rData.m_pParser )
+ pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
+ if( pKey )
+ pValue = rData.m_aContext.getValue( pKey );
+ if( pKey && pValue )
+ {
+ for( pJobSetup->mnPaperBin = 0;
+ pValue != pKey->getValue( pJobSetup->mnPaperBin ) &&
+ pJobSetup->mnPaperBin < pKey->countValues();
+ pJobSetup->mnPaperBin++ )
+ ;
+ if( pJobSetup->mnPaperBin >= pKey->countValues() )
+ pJobSetup->mnPaperBin = 0;
+ }
+
+ // copy duplex
+ pKey = NULL;
+ pValue = NULL;
+
+ pJobSetup->meDuplexMode = DUPLEX_UNKNOWN;
+ if( rData.m_pParser )
+ pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
+ if( pKey )
+ pValue = rData.m_aContext.getValue( pKey );
+ if( pKey && pValue )
+ {
+ if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) ||
+ pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 )
+ )
+ {
+ pJobSetup->meDuplexMode = DUPLEX_OFF;
+ }
+ else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) )
+ {
+ pJobSetup->meDuplexMode = DUPLEX_LONGEDGE;
+ }
+ else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) )
+ {
+ pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE;
+ }
+ }
+
+ // copy the whole context
+ if( pJobSetup->mpDriverData )
+ rtl_freeMemory( pJobSetup->mpDriverData );
+
+ int nBytes;
+ void* pBuffer = NULL;
+ if( rData.getStreamBuffer( pBuffer, nBytes ) )
+ {
+ pJobSetup->mnDriverDataLen = nBytes;
+ pJobSetup->mpDriverData = (sal_uInt8*)pBuffer;
+ }
+ else
+ {
+ pJobSetup->mnDriverDataLen = 0;
+ pJobSetup->mpDriverData = NULL;
+ }
+}
+
+static bool passFileToCommandLine( const String& rFilename, const String& rCommandLine, bool bRemoveFile = true )
+{
+ bool bSuccess = false;
+
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ ByteString aCmdLine( rCommandLine, aEncoding );
+ ByteString aFilename( rFilename, aEncoding );
+
+ bool bPipe = aCmdLine.Search( "(TMP)" ) != STRING_NOTFOUND ? false : true;
+
+ // setup command line for exec
+ if( ! bPipe )
+ while( aCmdLine.SearchAndReplace( "(TMP)", aFilename ) != STRING_NOTFOUND )
+ ;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s commandline: \"%s\"\n",
+ bPipe ? "piping to" : "executing",
+ aCmdLine.GetBuffer() );
+ struct stat aStat;
+ if( stat( aFilename.GetBuffer(), &aStat ) )
+ fprintf( stderr, "stat( %s ) failed\n", aFilename.GetBuffer() );
+ fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.GetBuffer(), (long)aStat.st_mode );
+#endif
+ const char* argv[4];
+ if( ! ( argv[ 0 ] = getenv( "SHELL" ) ) )
+ argv[ 0 ] = "/bin/sh";
+ argv[ 1 ] = "-c";
+ argv[ 2 ] = aCmdLine.GetBuffer();
+ argv[ 3 ] = 0;
+
+ bool bHavePipes = false;
+ int pid, fd[2];
+
+ if( bPipe )
+ bHavePipes = pipe( fd ) ? false : true;
+ if( ( pid = fork() ) > 0 )
+ {
+ if( bPipe && bHavePipes )
+ {
+ close( fd[0] );
+ char aBuffer[ 2048 ];
+ FILE* fp = fopen( aFilename.GetBuffer(), "r" );
+ while( fp && ! feof( fp ) )
+ {
+ int nBytes = fread( aBuffer, 1, sizeof( aBuffer ), fp );
+ if( nBytes )
+ write( fd[ 1 ], aBuffer, nBytes );
+ }
+ fclose( fp );
+ close( fd[ 1 ] );
+ }
+ int status = 0;
+ waitpid( pid, &status, 0 );
+ if( ! status )
+ bSuccess = true;
+ }
+ else if( ! pid )
+ {
+ if( bPipe && bHavePipes )
+ {
+ close( fd[1] );
+ if( fd[0] != STDIN_FILENO ) // not probable, but who knows :)
+ dup2( fd[0], STDIN_FILENO );
+ }
+ execv( argv[0], const_cast<char**>(argv) );
+ fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.GetBuffer() );
+ _exit( 1 );
+ }
+ else
+ fprintf( stderr, "failed to fork\n" );
+
+ // clean up the mess
+ if( bRemoveFile )
+ unlink( aFilename.GetBuffer() );
+
+ return bSuccess;
+}
+
+static bool sendAFax( const String& rFaxNumber, const String& rFileName, const String& rCommand )
+{
+ std::list< OUString > aFaxNumbers;
+
+ if( ! rFaxNumber.Len() )
+ {
+ getPaLib();
+ if( pFaxNrFunction )
+ {
+ String aNewNr;
+ if( pFaxNrFunction( aNewNr ) )
+ aFaxNumbers.push_back( OUString( aNewNr ) );
+ }
+ }
+ else
+ {
+ sal_Int32 nIndex = 0;
+ OUString aFaxes( rFaxNumber );
+ OUString aBeginToken( RTL_CONSTASCII_USTRINGPARAM("<Fax#>") );
+ OUString aEndToken( RTL_CONSTASCII_USTRINGPARAM("</Fax#>") );
+ while( nIndex != -1 )
+ {
+ nIndex = aFaxes.indexOf( aBeginToken, nIndex );
+ if( nIndex != -1 )
+ {
+ sal_Int32 nBegin = nIndex + aBeginToken.getLength();
+ nIndex = aFaxes.indexOf( aEndToken, nIndex );
+ if( nIndex != -1 )
+ {
+ aFaxNumbers.push_back( aFaxes.copy( nBegin, nIndex-nBegin ) );
+ nIndex += aEndToken.getLength();
+ }
+ }
+ }
+ }
+
+ bool bSuccess = true;
+ if( aFaxNumbers.begin() != aFaxNumbers.end() )
+ {
+ while( aFaxNumbers.begin() != aFaxNumbers.end() && bSuccess )
+ {
+ String aCmdLine( rCommand );
+ String aFaxNumber( aFaxNumbers.front() );
+ aFaxNumbers.pop_front();
+ while( aCmdLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PHONE)" ) ), aFaxNumber ) != STRING_NOTFOUND )
+ ;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "sending fax to \"%s\"\n", OUStringToOString( aFaxNumber, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ bSuccess = passFileToCommandLine( rFileName, aCmdLine, false );
+ }
+ }
+ else
+ bSuccess = false;
+
+ // clean up temp file
+ unlink( ByteString( rFileName, osl_getThreadTextEncoding() ).GetBuffer() );
+
+ return bSuccess;
+}
+
+static bool createPdf( const String& rToFile, const String& rFromFile, const String& rCommandLine )
+{
+ String aCommandLine( rCommandLine );
+ while( aCommandLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(OUTFILE)" ) ), rToFile ) != STRING_NOTFOUND )
+ ;
+ return passFileToCommandLine( rFromFile, aCommandLine );
+}
+
+/*
+ * SalInstance
+ */
+
+// -----------------------------------------------------------------------
+
+SalInfoPrinter* X11SalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pJobSetup )
+{
+ mbPrinterInit = true;
+ // create and initialize SalInfoPrinter
+ PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter;
+
+ if( pJobSetup )
+ {
+ PrinterInfoManager& rManager( PrinterInfoManager::get() );
+ PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) );
+ pPrinter->m_aJobData = aInfo;
+ pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData );
+
+ if( pJobSetup->mpDriverData )
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
+
+ pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX;
+ pJobSetup->maPrinterName = pQueueInfo->maPrinterName;
+ pJobSetup->maDriver = aInfo.m_aDriverName;
+ copyJobDataToJobSetup( pJobSetup, aInfo );
+
+ // set/clear backwards compatibility flag
+ bool bStrictSO52Compatibility = false;
+ boost::unordered_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
+ pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
+
+ if( compat_it != pJobSetup->maValueMap.end() )
+ {
+ if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
+ bStrictSO52Compatibility = true;
+ }
+ pPrinter->m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
+ }
+
+
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+SalPrinter* X11SalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
+{
+ mbPrinterInit = true;
+ // create and initialize SalPrinter
+ PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter );
+ pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData;
+
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::DestroyPrinter( SalPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
+{
+ mbPrinterInit = true;
+ PrinterInfoManager& rManager( PrinterInfoManager::get() );
+ static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
+ if( ! pNoSyncDetection || ! *pNoSyncDetection )
+ {
+ // #i62663# synchronize possible asynchronouse printer detection now
+ rManager.checkPrintersChanged( true );
+ }
+ ::std::list< OUString > aPrinters;
+ rManager.listPrinters( aPrinters );
+
+ for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it )
+ {
+ const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) );
+ // Neuen Eintrag anlegen
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+ pInfo->maPrinterName = *it;
+ pInfo->maDriver = rInfo.m_aDriverName;
+ pInfo->maLocation = rInfo.m_aLocation;
+ pInfo->maComment = rInfo.m_aComment;
+ pInfo->mpSysData = NULL;
+
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ String aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( aToken.CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL )
+ {
+ pInfo->maLocation = getPdfDir( rInfo );
+ break;
+ }
+ }
+
+ pList->Add( pInfo );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
+{
+ delete pInfo;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::GetPrinterQueueState( SalPrinterQueueInfo* )
+{
+ mbPrinterInit = true;
+}
+
+// -----------------------------------------------------------------------
+
+String X11SalInstance::GetDefaultPrinter()
+{
+ mbPrinterInit = true;
+ PrinterInfoManager& rManager( PrinterInfoManager::get() );
+ return rManager.getDefaultPrinter();
+}
+
+// =======================================================================
+
+PspSalInfoPrinter::PspSalInfoPrinter()
+{
+ m_pGraphics = NULL;
+ m_bPapersInit = false;
+}
+
+// -----------------------------------------------------------------------
+
+PspSalInfoPrinter::~PspSalInfoPrinter()
+{
+ if( m_pGraphics )
+ {
+ delete m_pGraphics;
+ m_pGraphics = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* )
+{
+ m_aPaperFormats.clear();
+ m_bPapersInit = true;
+
+ if( m_aJobData.m_pParser )
+ {
+ const PPDKey* pKey = m_aJobData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ if( pKey )
+ {
+ int nValues = pKey->countValues();
+ for( int i = 0; i < nValues; i++ )
+ {
+ const PPDValue* pValue = pKey->getValue( i );
+ int nWidth = 0, nHeight = 0;
+ m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight );
+ PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight ));
+ m_aPaperFormats.push_back( aInfo );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* )
+{
+ return 900;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* PspSalInfoPrinter::GetGraphics()
+{
+ // return a valid pointer only once
+ // the reasoning behind this is that we could have different
+ // SalGraphics that can run in multiple threads
+ // (future plans)
+ SalGraphics* pRet = NULL;
+ if( ! m_pGraphics )
+ {
+ m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, NULL, false, this );
+ m_pGraphics->SetLayout( 0 );
+ pRet = m_pGraphics;
+ }
+ return pRet;
+}
+
+// -----------------------------------------------------------------------
+
+void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics )
+{
+ if( pGraphics == m_pGraphics )
+ {
+ delete pGraphics;
+ m_pGraphics = NULL;
+ }
+ return;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool PspSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pJobSetup )
+{
+ if( ! pFrame || ! pJobSetup )
+ return sal_False;
+
+ getPaLib();
+
+ if( ! pSetupFunction )
+ return sal_False;
+
+ PrinterInfoManager& rManager = PrinterInfoManager::get();
+
+ PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) );
+ if ( pJobSetup->mpDriverData )
+ {
+ SetData( ~0, pJobSetup );
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
+ }
+
+ if( pSetupFunction( aInfo ) )
+ {
+ rtl_freeMemory( pJobSetup->mpDriverData );
+ pJobSetup->mpDriverData = NULL;
+
+ int nBytes;
+ void* pBuffer = NULL;
+ aInfo.getStreamBuffer( pBuffer, nBytes );
+ pJobSetup->mnDriverDataLen = nBytes;
+ pJobSetup->mpDriverData = (sal_uInt8*)pBuffer;
+
+ // copy everything to job setup
+ copyJobDataToJobSetup( pJobSetup, aInfo );
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
+ return sal_True;
+ }
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+// This function gets the driver data and puts it into pJobSetup
+// If pJobSetup->mpDriverData is NOT NULL, then the independend
+// data should be merged into the driver data
+// If pJobSetup->mpDriverData IS NULL, then the driver defaults
+// should be merged into the independent data
+sal_Bool PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup )
+{
+ // set/clear backwards compatibility flag
+ bool bStrictSO52Compatibility = false;
+ boost::unordered_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
+ pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
+
+ if( compat_it != pJobSetup->maValueMap.end() )
+ {
+ if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
+ bStrictSO52Compatibility = true;
+ }
+ m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
+
+ if( pJobSetup->mpDriverData )
+ return SetData( ~0, pJobSetup );
+
+ copyJobDataToJobSetup( pJobSetup, m_aJobData );
+
+ return sal_True;
+}
+
+// -----------------------------------------------------------------------
+
+// This function merges the independ driver data
+// and sets the new independ data in pJobSetup
+// Only the data must be changed, where the bit
+// in nGetDataFlags is set
+sal_Bool PspSalInfoPrinter::SetData(
+ sal_uLong nSetDataFlags,
+ ImplJobSetup* pJobSetup )
+{
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ if( aData.m_pParser )
+ {
+ const PPDKey* pKey;
+ const PPDValue* pValue;
+
+ // merge papersize if necessary
+ if( nSetDataFlags & SAL_JOBSET_PAPERSIZE )
+ {
+ String aPaper;
+
+ if( pJobSetup->mePaperFormat == PAPER_USER )
+ aPaper = aData.m_pParser->matchPaper(
+ TenMuToPt( pJobSetup->mnPaperWidth ),
+ TenMuToPt( pJobSetup->mnPaperHeight ) );
+ else
+ aPaper = rtl::OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1);
+
+ pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : NULL;
+
+ // some PPD files do not specify the standard paper names (e.g. C5 instead of EnvC5)
+ // try to find the correct paper anyway using the size
+ if( pKey && ! pValue && pJobSetup->mePaperFormat != PAPER_USER )
+ {
+ PaperInfo aInfo( pJobSetup->mePaperFormat );
+ aPaper = aData.m_pParser->matchPaper(
+ TenMuToPt( aInfo.getWidth() ),
+ TenMuToPt( aInfo.getHeight() ) );
+ pValue = pKey->getValueCaseInsensitive( aPaper );
+ }
+
+ if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) )
+ return sal_False;
+ }
+
+ // merge paperbin if necessary
+ if( nSetDataFlags & SAL_JOBSET_PAPERBIN )
+ {
+ pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
+ if( pKey )
+ {
+ int nPaperBin = pJobSetup->mnPaperBin;
+ if( nPaperBin >= pKey->countValues() )
+ pValue = pKey->getDefaultValue();
+ else
+ pValue = pKey->getValue( pJobSetup->mnPaperBin );
+
+ // may fail due to constraints;
+ // real paper bin is copied back to jobsetup in that case
+ aData.m_aContext.setValue( pKey, pValue );
+ }
+ // if printer has no InputSlot key simply ignore this setting
+ // (e.g. SGENPRT has no InputSlot)
+ }
+
+ // merge orientation if necessary
+ if( nSetDataFlags & SAL_JOBSET_ORIENTATION )
+ aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait;
+
+ // merge duplex if necessary
+ if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE )
+ {
+ pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
+ if( pKey )
+ {
+ pValue = NULL;
+ switch( pJobSetup->meDuplexMode )
+ {
+ case DUPLEX_OFF:
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
+ if( pValue == NULL )
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "SimplexNoTumble" ) ) );
+ break;
+ case DUPLEX_SHORTEDGE:
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexTumble" ) ) );
+ break;
+ case DUPLEX_LONGEDGE:
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexNoTumble" ) ) );
+ break;
+ case DUPLEX_UNKNOWN:
+ default:
+ pValue = 0;
+ break;
+ }
+ if( ! pValue )
+ pValue = pKey->getDefaultValue();
+ aData.m_aContext.setValue( pKey, pValue );
+ }
+ }
+
+ m_aJobData = aData;
+ copyJobDataToJobSetup( pJobSetup, aData );
+ return sal_True;
+ }
+
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+void PspSalInfoPrinter::GetPageInfo(
+ const ImplJobSetup* pJobSetup,
+ long& rOutWidth, long& rOutHeight,
+ long& rPageOffX, long& rPageOffY,
+ long& rPageWidth, long& rPageHeight )
+{
+ if( ! pJobSetup )
+ return;
+
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ // get the selected page size
+ if( aData.m_pParser )
+ {
+
+ String aPaper;
+ int width, height;
+ int left = 0, top = 0, right = 0, bottom = 0;
+ int nDPI = aData.m_aContext.getRenderResolution();
+
+
+ if( aData.m_eOrientation == psp::orientation::Portrait )
+ {
+ aData.m_aContext.getPageSize( aPaper, width, height );
+ aData.m_pParser->getMargins( aPaper, left, right, top, bottom );
+ }
+ else
+ {
+ aData.m_aContext.getPageSize( aPaper, height, width );
+ aData.m_pParser->getMargins( aPaper, top, bottom, right, left );
+ }
+
+ rPageWidth = width * nDPI / 72;
+ rPageHeight = height * nDPI / 72;
+ rPageOffX = left * nDPI / 72;
+ rPageOffY = top * nDPI / 72;
+ rOutWidth = ( width - left - right ) * nDPI / 72;
+ rOutHeight = ( height - top - bottom ) * nDPI / 72;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup )
+{
+ if( ! pJobSetup )
+ return 0;
+
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
+ return pKey ? pKey->countValues() : 0;
+}
+
+// -----------------------------------------------------------------------
+
+String PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, sal_uLong nPaperBin )
+{
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ String aRet;
+ if( aData.m_pParser )
+ {
+ const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
+ if( ! pKey || nPaperBin >= (sal_uLong)pKey->countValues() )
+ aRet = aData.m_pParser->getDefaultInputSlot();
+ else
+ {
+ const PPDValue* pValue = pKey->getValue( nPaperBin );
+ if( pValue )
+ aRet = aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption );
+ }
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, sal_uInt16 nType )
+{
+ switch( nType )
+ {
+ case PRINTER_CAPABILITIES_SUPPORTDIALOG:
+ return 1;
+ case PRINTER_CAPABILITIES_COPIES:
+ return 0xffff;
+ case PRINTER_CAPABILITIES_COLLATECOPIES:
+ {
+ // see if the PPD contains a value to set Collate to True
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ) : NULL;
+ const PPDValue* pVal = pKey ? pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ) : NULL;
+
+ // PPDs don't mention the number of possible collated copies.
+ // so let's guess as many as we want ?
+ return pVal ? 0xffff : 0;
+ }
+ case PRINTER_CAPABILITIES_SETORIENTATION:
+ return 1;
+ case PRINTER_CAPABILITIES_SETDUPLEX:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPERBIN:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPERSIZE:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPER:
+ return 0;
+ case PRINTER_CAPABILITIES_FAX:
+ return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "fax" ) ? 1 : 0;
+ case PRINTER_CAPABILITIES_PDF:
+ if( PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "pdf" ) )
+ return 1;
+ else
+ {
+ // see if the PPD contains a value to set Collate to True
+ JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName );
+ if( pJobSetup->mpDriverData )
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+ return aData.m_nPDFDevice > 0 ? 1 : 0;
+ }
+ case PRINTER_CAPABILITIES_EXTERNALDIALOG:
+ return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "external_dialog" ) ? 1 : 0;
+ case PRINTER_CAPABILITIES_USEPULLMODEL:
+ {
+ // see if the PPD contains a value to set Collate to True
+ JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName );
+ if( pJobSetup->mpDriverData )
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+ return aData.m_nPDFDevice > 0 ? 1 : 0;
+ }
+ default: break;
+ };
+ return 0;
+}
+
+// =======================================================================
+
+/*
+ * SalPrinter
+ */
+
+ PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter )
+ : m_bFax( false ),
+ m_bPdf( false ),
+ m_bSwallowFaxNo( false ),
+ m_bIsPDFWriterJob( false ),
+ m_pGraphics( NULL ),
+ m_nCopies( 1 ),
+ m_bCollate( false ),
+ m_pInfoPrinter( pInfoPrinter )
+{
+}
+
+// -----------------------------------------------------------------------
+
+PspSalPrinter::~PspSalPrinter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+static String getTmpName()
+{
+ rtl::OUString aTmp, aSys;
+ osl_createTempFile( NULL, NULL, &aTmp.pData );
+ osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData );
+
+ return aSys;
+}
+
+sal_Bool PspSalPrinter::StartJob(
+ const XubString* pFileName,
+ const XubString& rJobName,
+ const XubString& rAppName,
+ sal_uLong nCopies,
+ bool bCollate,
+ bool bDirect,
+ ImplJobSetup* pJobSetup )
+{
+ GetSalData()->m_pInstance->jobStartedPrinterUpdate();
+
+ m_bFax = false;
+ m_bPdf = false;
+ m_aFileName = pFileName ? *pFileName : String();
+ m_aTmpFile = String();
+ m_nCopies = nCopies;
+ m_bCollate = bCollate;
+
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
+ if( m_nCopies > 1 )
+ {
+ // in case user did not do anything (m_nCopies=1)
+ // take the default from jobsetup
+ m_aJobData.m_nCopies = m_nCopies;
+ m_aJobData.setCollate( bCollate );
+ }
+
+ // check wether this printer is configured as fax
+ int nMode = 0;
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( ! aToken.compareToAscii( "fax", 3 ) )
+ {
+ m_bFax = true;
+ m_aTmpFile = getTmpName();
+ nMode = S_IRUSR | S_IWUSR;
+
+ ::boost::unordered_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it;
+ it = pJobSetup->maValueMap.find( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FAX#")) );
+ if( it != pJobSetup->maValueMap.end() )
+ m_aFaxNr = it->second;
+
+ sal_Int32 nPos = 0;
+ m_bSwallowFaxNo = ! aToken.getToken( 1, '=', nPos ).compareToAscii( "swallow", 7 ) ? true : false;
+
+ break;
+ }
+ if( ! aToken.compareToAscii( "pdf=", 4 ) )
+ {
+ m_bPdf = true;
+ m_aTmpFile = getTmpName();
+ nMode = S_IRUSR | S_IWUSR;
+
+ if( ! m_aFileName.Len() )
+ {
+ m_aFileName = getPdfDir( rInfo );
+ m_aFileName.Append( '/' );
+ m_aFileName.Append( rJobName );
+ m_aFileName.AppendAscii( ".pdf" );
+ }
+ break;
+ }
+ }
+ m_aPrinterGfx.Init( m_aJobData );
+
+ // set/clear backwards compatibility flag
+ bool bStrictSO52Compatibility = false;
+ boost::unordered_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
+ pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
+
+ if( compat_it != pJobSetup->maValueMap.end() )
+ {
+ if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
+ bStrictSO52Compatibility = true;
+ }
+ m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
+
+ return m_aPrintJob.StartJob( m_aTmpFile.Len() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, bDirect ) ? sal_True : sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool PspSalPrinter::EndJob()
+{
+ sal_Bool bSuccess = sal_False;
+ if( m_bIsPDFWriterJob )
+ bSuccess = sal_True;
+ else
+ {
+ bSuccess = m_aPrintJob.EndJob();
+
+ if( bSuccess )
+ {
+ // check for fax
+ if( m_bFax )
+ {
+
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
+ // sendAFax removes the file after use
+ bSuccess = sendAFax( m_aFaxNr, m_aTmpFile, rInfo.m_aCommand );
+ }
+ else if( m_bPdf )
+ {
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
+ bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand );
+ }
+ }
+ }
+ GetSalData()->m_pInstance->jobEndedPrinterUpdate();
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool PspSalPrinter::AbortJob()
+{
+ sal_Bool bAbort = m_aPrintJob.AbortJob() ? sal_True : sal_False;
+ GetSalData()->m_pInstance->jobEndedPrinterUpdate();
+ return bAbort;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, sal_Bool )
+{
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
+ m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL, m_bSwallowFaxNo, m_pInfoPrinter );
+ m_pGraphics->SetLayout( 0 );
+ if( m_nCopies > 1 )
+ {
+ // in case user did not do anything (m_nCopies=1)
+ // take the default from jobsetup
+ m_aJobData.m_nCopies = m_nCopies;
+ m_aJobData.setCollate( m_nCopies > 1 && m_bCollate );
+ }
+
+ m_aPrintJob.StartPage( m_aJobData );
+ m_aPrinterGfx.Init( m_aPrintJob );
+
+ return m_pGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool PspSalPrinter::EndPage()
+{
+ sal_Bool bResult = m_aPrintJob.EndPage();
+ m_aPrinterGfx.Clear();
+ return bResult ? sal_True : sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong PspSalPrinter::GetErrorCode()
+{
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+struct PDFNewJobParameters
+{
+ Size maPageSize;
+ sal_uInt16 mnPaperBin;
+
+ PDFNewJobParameters( const Size& i_rSize = Size(),
+ sal_uInt16 i_nPaperBin = 0xffff )
+ : maPageSize( i_rSize ), mnPaperBin( i_nPaperBin ) {}
+
+ bool operator!=(const PDFNewJobParameters& rComp ) const
+ {
+ Size aCompLSSize( rComp.maPageSize.Height(), rComp.maPageSize.Width() );
+ return
+ (maPageSize != rComp.maPageSize && maPageSize != aCompLSSize)
+ || mnPaperBin != rComp.mnPaperBin
+ ;
+ }
+
+ bool operator==(const PDFNewJobParameters& rComp) const
+ {
+ return ! this->operator!=(rComp);
+ }
+};
+
+struct PDFPrintFile
+{
+ rtl::OUString maTmpURL;
+ PDFNewJobParameters maParameters;
+
+ PDFPrintFile( const rtl::OUString& i_rURL, const PDFNewJobParameters& i_rNewParameters )
+ : maTmpURL( i_rURL )
+ , maParameters( i_rNewParameters ) {}
+};
+
+sal_Bool PspSalPrinter::StartJob( const String* i_pFileName, const String& i_rJobName, const String& i_rAppName,
+ ImplJobSetup* i_pSetupData, vcl::PrinterController& i_rController )
+{
+ OSL_TRACE( "StartJob with controller: pFilename = %s", i_pFileName ? rtl::OUStringToOString( *i_pFileName, RTL_TEXTENCODING_UTF8 ).getStr() : "<nil>" );
+ // mark for endjob
+ m_bIsPDFWriterJob = true;
+ // reset IsLastPage
+ i_rController.setLastPage( sal_False );
+
+ // update job data
+ if( i_pSetupData )
+ JobData::constructFromStreamBuffer( i_pSetupData->mpDriverData, i_pSetupData->mnDriverDataLen, m_aJobData );
+
+ OSL_ASSERT( m_aJobData.m_nPDFDevice > 0 );
+ m_aJobData.m_nPDFDevice = 1;
+
+ // possibly create one job for collated output
+ sal_Bool bSinglePrintJobs = sal_False;
+ beans::PropertyValue* pSingleValue = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) );
+ if( pSingleValue )
+ {
+ pSingleValue->Value >>= bSinglePrintJobs;
+ }
+
+ int nCopies = i_rController.getPrinter()->GetCopyCount();
+ bool bCollate = i_rController.getPrinter()->IsCollateCopy();
+
+ // notify start of real print job
+ i_rController.jobStarted();
+
+ // setup PDFWriter context
+ vcl::PDFWriter::PDFWriterContext aContext;
+ aContext.Version = vcl::PDFWriter::PDF_1_4;
+ aContext.Tagged = false;
+ aContext.EmbedStandardFonts = true;
+ aContext.DocumentLocale = Application::GetSettings().GetLocale();
+ aContext.ColorMode = i_rController.getPrinter()->GetPrinterOptions().IsConvertToGreyscales()
+ ? vcl::PDFWriter::DrawGreyscale : vcl::PDFWriter::DrawColor;
+
+ // prepare doc info
+ aContext.DocumentInfo.Title = i_rJobName;
+ aContext.DocumentInfo.Creator = i_rAppName;
+ aContext.DocumentInfo.Producer = i_rAppName;
+
+ // define how we handle metafiles in PDFWriter
+ vcl::PDFWriter::PlayMetafileContext aMtfContext;
+ aMtfContext.m_bOnlyLosslessCompression = true;
+
+ boost::shared_ptr<vcl::PDFWriter> pWriter;
+ std::vector< PDFPrintFile > aPDFFiles;
+ boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() );
+ int nAllPages = i_rController.getFilteredPageCount();
+ i_rController.createProgressDialog();
+ bool bAborted = false;
+ PDFNewJobParameters aLastParm;
+
+ aContext.DPIx = pPrinter->ImplGetDPIX();
+ aContext.DPIy = pPrinter->ImplGetDPIY();
+ for( int nPage = 0; nPage < nAllPages && ! bAborted; nPage++ )
+ {
+ if( nPage == nAllPages-1 )
+ i_rController.setLastPage( sal_True );
+
+ // get the page's metafile
+ GDIMetaFile aPageFile;
+ vcl::PrinterController::PageSize aPageSize = i_rController.getFilteredPageFile( nPage, aPageFile );
+ if( i_rController.isProgressCanceled() )
+ {
+ bAborted = true;
+ if( nPage != nAllPages-1 )
+ {
+ i_rController.createProgressDialog();
+ i_rController.setLastPage( sal_True );
+ i_rController.getFilteredPageFile( nPage, aPageFile );
+ }
+ }
+ else
+ {
+ pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
+ pPrinter->SetPaperSizeUser( aPageSize.aSize, true );
+ PDFNewJobParameters aNewParm( pPrinter->GetPaperSize(), pPrinter->GetPaperBin() );
+
+ // create PDF writer on demand
+ // either on first page
+ // or on paper format change - cups does not support multiple paper formats per job (yet?)
+ // so we need to start a new job to get a new paper format from the printer
+ // orientation switches (that is switch of height and width) is handled transparently by CUPS
+ if( ! pWriter ||
+ (aNewParm != aLastParm && ! i_pFileName ) )
+ {
+ if( pWriter )
+ {
+ pWriter->Emit();
+ }
+ // produce PDF file
+ OUString aPDFUrl;
+ if( i_pFileName )
+ aPDFUrl = *i_pFileName;
+ else
+ osl_createTempFile( NULL, NULL, &aPDFUrl.pData );
+ // normalize to file URL
+ if( aPDFUrl.compareToAscii( "file:", 5 ) != 0 )
+ {
+ // this is not a file URL, but it should
+ // form it into a osl friendly file URL
+ rtl::OUString aTmp;
+ osl_getFileURLFromSystemPath( aPDFUrl.pData, &aTmp.pData );
+ aPDFUrl = aTmp;
+ }
+ // save current file and paper format
+ aLastParm = aNewParm;
+ aPDFFiles.push_back( PDFPrintFile( aPDFUrl, aNewParm ) );
+ // update context
+ aContext.URL = aPDFUrl;
+
+ // create and initialize PDFWriter
+ #if defined __SUNPRO_CC
+ #pragma disable_warn
+ #endif
+ pWriter.reset( new vcl::PDFWriter( aContext, uno::Reference< beans::XMaterialHolder >() ) );
+ #if defined __SUNPRO_CC
+ #pragma enable_warn
+ #endif
+ }
+
+ pWriter->NewPage( TenMuToPt( aNewParm.maPageSize.Width() ),
+ TenMuToPt( aNewParm.maPageSize.Height() ),
+ vcl::PDFWriter::Portrait );
+
+ pWriter->PlayMetafile( aPageFile, aMtfContext, NULL );
+ }
+ }
+
+ // emit the last file
+ if( pWriter )
+ pWriter->Emit();
+
+ // handle collate, copy count and multiple jobs correctly
+ int nOuterJobs = 1;
+ if( bSinglePrintJobs )
+ {
+ nOuterJobs = nCopies;
+ m_aJobData.m_nCopies = 1;
+ }
+ else
+ {
+ if( bCollate )
+ {
+ if( aPDFFiles.size() == 1 && pPrinter->HasSupport( SUPPORT_COLLATECOPY ) )
+ {
+ m_aJobData.setCollate( true );
+ m_aJobData.m_nCopies = nCopies;
+ }
+ else
+ {
+ nOuterJobs = nCopies;
+ m_aJobData.m_nCopies = 1;
+ }
+ }
+ else
+ {
+ m_aJobData.setCollate( false );
+ m_aJobData.m_nCopies = nCopies;
+ }
+ }
+
+ // spool files
+ if( ! i_pFileName && ! bAborted )
+ {
+ bool bFirstJob = true;
+ for( int nCurJob = 0; nCurJob < nOuterJobs; nCurJob++ )
+ {
+ for( size_t i = 0; i < aPDFFiles.size(); i++ )
+ {
+ oslFileHandle pFile = NULL;
+ osl_openFile( aPDFFiles[i].maTmpURL.pData, &pFile, osl_File_OpenFlag_Read );
+ if( pFile )
+ {
+ osl_setFilePos( pFile, osl_Pos_Absolut, 0 );
+ std::vector< char > buffer( 0x10000, 0 );
+ // update job data with current page size
+ Size aPageSize( aPDFFiles[i].maParameters.maPageSize );
+ m_aJobData.setPaper( TenMuToPt( aPageSize.Width() ), TenMuToPt( aPageSize.Height() ) );
+ // update job data with current paperbin
+ m_aJobData.setPaperBin( aPDFFiles[i].maParameters.mnPaperBin );
+
+ // spool current file
+ FILE* fp = PrinterInfoManager::get().startSpool( pPrinter->GetName(), i_rController.isDirectPrint() );
+ if( fp )
+ {
+ sal_uInt64 nBytesRead = 0;
+ do
+ {
+ osl_readFile( pFile, &buffer[0], buffer.size(), &nBytesRead );
+ if( nBytesRead > 0 )
+ fwrite( &buffer[0], 1, nBytesRead, fp );
+ } while( nBytesRead == buffer.size() );
+ rtl::OUStringBuffer aBuf( i_rJobName.Len() + 8 );
+ aBuf.append( i_rJobName );
+ if( i > 0 || nCurJob > 0 )
+ {
+ aBuf.append( sal_Unicode(' ') );
+ aBuf.append( sal_Int32( i + nCurJob * aPDFFiles.size() ) );
+ }
+ PrinterInfoManager::get().endSpool( pPrinter->GetName(), aBuf.makeStringAndClear(), fp, m_aJobData, bFirstJob );
+ bFirstJob = false;
+ }
+ }
+ osl_closeFile( pFile );
+ }
+ }
+ }
+
+ // job has been spooled
+ i_rController.setJobState( bAborted ? view::PrintableState_JOB_ABORTED : view::PrintableState_JOB_SPOOLED );
+
+ // clean up the temporary PDF files
+ if( ! i_pFileName || bAborted )
+ {
+ for( size_t i = 0; i < aPDFFiles.size(); i++ )
+ {
+ osl_removeFile( aPDFFiles[i].maTmpURL.pData );
+ OSL_TRACE( "removed print PDF file %s\n", rtl::OUStringToOString( aPDFFiles[i].maTmpURL, RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+
+ return sal_True;
+}
+
+
+namespace x11
+{
+ class PrinterUpdate
+ {
+ static Timer* pPrinterUpdateTimer;
+ static int nActiveJobs;
+
+ static void doUpdate();
+ DECL_STATIC_LINK( PrinterUpdate, UpdateTimerHdl, void* );
+ public:
+ static void update(X11SalInstance &rInstance);
+ static void jobStarted() { nActiveJobs++; }
+ static void jobEnded();
+ };
+}
+
+/*
+ * x11::PrinterUpdate
+ */
+
+Timer* x11::PrinterUpdate::pPrinterUpdateTimer = NULL;
+int x11::PrinterUpdate::nActiveJobs = 0;
+
+void x11::PrinterUpdate::doUpdate()
+{
+ ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() );
+ if( rManager.checkPrintersChanged( false ) )
+ {
+ SalDisplay* pDisp = GetX11SalData()->GetDisplay();
+ const std::list< SalFrame* >& rList = pDisp->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rList.begin();
+ it != rList.end(); ++it )
+ pDisp->SendInternalEvent( *it, NULL, SALEVENT_PRINTERCHANGED );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_STATIC_LINK_NOINSTANCE( x11::PrinterUpdate, UpdateTimerHdl, void*, EMPTYARG )
+{
+ if( nActiveJobs < 1 )
+ {
+ doUpdate();
+ delete pPrinterUpdateTimer;
+ pPrinterUpdateTimer = NULL;
+ }
+ else
+ pPrinterUpdateTimer->Start();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void x11::PrinterUpdate::update(X11SalInstance &rInstance)
+{
+ if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
+ return;
+
+ if( ! rInstance.isPrinterInit() )
+ {
+ // #i45389# start background printer detection
+ psp::PrinterInfoManager::get();
+ return;
+ }
+
+ if( nActiveJobs < 1 )
+ doUpdate();
+ else if( ! pPrinterUpdateTimer )
+ {
+ pPrinterUpdateTimer = new Timer();
+ pPrinterUpdateTimer->SetTimeout( 500 );
+ pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, x11::PrinterUpdate, UpdateTimerHdl ) );
+ pPrinterUpdateTimer->Start();
+ }
+}
+
+void X11SalInstance::updatePrinterUpdate()
+{
+ x11::PrinterUpdate::update(*this);
+}
+
+void X11SalInstance::jobStartedPrinterUpdate()
+{
+ x11::PrinterUpdate::jobStarted();
+}
+
+// -----------------------------------------------------------------------
+
+void x11::PrinterUpdate::jobEnded()
+{
+ nActiveJobs--;
+ if( nActiveJobs < 1 )
+ {
+ if( pPrinterUpdateTimer )
+ {
+ pPrinterUpdateTimer->Stop();
+ delete pPrinterUpdateTimer;
+ pPrinterUpdateTimer = NULL;
+ doUpdate();
+ }
+ }
+}
+
+void X11SalInstance::jobEndedPrinterUpdate()
+{
+ x11::PrinterUpdate::jobEnded();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/salvd.cxx b/vcl/unx/generic/gdi/salvd.cxx
new file mode 100644
index 000000000000..0bb34519bd8f
--- /dev/null
+++ b/vcl/unx/generic/gdi/salvd.cxx
@@ -0,0 +1,276 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <vcl/sysdata.hxx>
+
+#include <tools/prex.h>
+#include <X11/extensions/Xrender.h>
+#include <tools/postx.h>
+
+#include <unx/salunx.h>
+#include <unx/saldata.hxx>
+#include <unx/saldisp.hxx>
+#include <unx/salgdi.h>
+#include <unx/salvd.h>
+
+#include <salinst.hxx>
+
+// -=-= SalInstance =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalVirtualDevice* X11SalInstance::CreateVirtualDevice( SalGraphics* pGraphics,
+ long nDX, long nDY,
+ sal_uInt16 nBitCount, const SystemGraphicsData *pData )
+{
+ X11SalVirtualDevice *pVDev = new X11SalVirtualDevice();
+ if( !nBitCount && pGraphics )
+ nBitCount = pGraphics->GetBitCount();
+
+ if( pData && pData->hDrawable != None )
+ {
+ XLIB_Window aRoot;
+ int x, y;
+ unsigned int w = 0, h = 0, bw, d;
+ Display* pDisp = GetX11SalData()->GetDisplay()->GetDisplay();
+ XGetGeometry( pDisp, pData->hDrawable,
+ &aRoot, &x, &y, &w, &h, &bw, &d );
+ int nScreen = 0;
+ while( nScreen < ScreenCount( pDisp ) )
+ {
+ if( RootWindow( pDisp, nScreen ) == aRoot )
+ break;
+ nScreen++;
+ }
+ nDX = (long)w;
+ nDY = (long)h;
+ if( !pVDev->Init( GetX11SalData()->GetDisplay(), nDX, nDY, nBitCount, nScreen, pData->hDrawable,
+ static_cast< XRenderPictFormat* >( pData->pXRenderFormat )) )
+ {
+ delete pVDev;
+ return NULL;
+ }
+ }
+ else if( !pVDev->Init( GetX11SalData()->GetDisplay(), nDX, nDY, nBitCount,
+ pGraphics ? static_cast<X11SalGraphics*>(pGraphics)->GetScreenNumber() :
+ GetX11SalData()->GetDisplay()->GetDefaultScreenNumber() ) )
+ {
+ delete pVDev;
+ return NULL;
+ }
+
+ pVDev->InitGraphics( pVDev );
+ return pVDev;
+}
+
+void X11SalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
+{
+ delete pDevice;
+}
+
+// -=-= SalGraphicsData =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::Init( X11SalVirtualDevice *pDevice, SalColormap* pColormap, bool bDeleteColormap )
+{
+ SalColormap *pOrigDeleteColormap = m_pDeleteColormap;
+
+ SalDisplay *pDisplay = pDevice->GetDisplay();
+ m_nScreen = pDevice->GetScreenNumber();
+
+ int nVisualDepth = pDisplay->GetColormap( m_nScreen ).GetVisual().GetDepth();
+ int nDeviceDepth = pDevice->GetDepth();
+
+ if( pColormap )
+ {
+ m_pColormap = pColormap;
+ if( bDeleteColormap )
+ m_pDeleteColormap = pColormap;
+ }
+ else
+ if( nDeviceDepth == nVisualDepth )
+ m_pColormap = &pDisplay->GetColormap( m_nScreen );
+ else
+ if( nDeviceDepth == 1 )
+ m_pColormap = m_pDeleteColormap = new SalColormap();
+
+ if (m_pDeleteColormap != pOrigDeleteColormap)
+ delete pOrigDeleteColormap;
+
+ const Drawable aVdevDrawable = pDevice->GetDrawable();
+ SetDrawable( aVdevDrawable, m_nScreen );
+
+ m_pVDev = pDevice;
+ m_pFrame = NULL;
+
+ bWindow_ = pDisplay->IsDisplay();
+ bVirDev_ = sal_True;
+}
+
+// -=-= SalVirDevData / SalVirtualDevice -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+sal_Bool X11SalVirtualDevice::Init( SalDisplay *pDisplay,
+ long nDX, long nDY,
+ sal_uInt16 nBitCount,
+ int nScreen,
+ Pixmap hDrawable,
+ XRenderPictFormat* pXRenderFormat )
+{
+ SalColormap* pColormap = NULL;
+ bool bDeleteColormap = false;
+
+ pDisplay_ = pDisplay;
+ pGraphics_ = new X11SalGraphics();
+ m_nScreen = nScreen;
+ if( pXRenderFormat ) {
+ pGraphics_->SetXRenderFormat( pXRenderFormat );
+ if( pXRenderFormat->colormap )
+ pColormap = new SalColormap( pDisplay, pXRenderFormat->colormap, m_nScreen );
+ else
+ pColormap = new SalColormap( nBitCount );
+ bDeleteColormap = true;
+ }
+ else if( nBitCount != pDisplay->GetVisual( m_nScreen ).GetDepth() )
+ {
+ pColormap = new SalColormap( nBitCount );
+ bDeleteColormap = true;
+ }
+ pGraphics_->SetLayout( 0 ); // by default no! mirroring for VirtualDevices, can be enabled with EnableRTL()
+ nDX_ = nDX;
+ nDY_ = nDY;
+ nDepth_ = nBitCount;
+
+ if( hDrawable == None )
+ hDrawable_ = XCreatePixmap( GetXDisplay(),
+ pDisplay_->GetDrawable( m_nScreen ),
+ nDX_, nDY_,
+ GetDepth() );
+ else
+ {
+ hDrawable_ = hDrawable;
+ bExternPixmap_ = sal_True;
+ }
+
+ pGraphics_->Init( this, pColormap, bDeleteColormap );
+
+ return hDrawable_ != None ? sal_True : sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+X11SalVirtualDevice::X11SalVirtualDevice()
+{
+ pDisplay_ = (SalDisplay*)ILLEGAL_POINTER;
+ pGraphics_ = NULL;
+ hDrawable_ = None;
+ nDX_ = 0;
+ nDY_ = 0;
+ nDepth_ = 0;
+ bGraphics_ = sal_False;
+ bExternPixmap_ = sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+X11SalVirtualDevice::~X11SalVirtualDevice()
+{
+ if( pGraphics_ )
+ delete pGraphics_;
+ pGraphics_ = NULL;
+
+ if( GetDrawable() && !bExternPixmap_ )
+ XFreePixmap( GetXDisplay(), GetDrawable() );
+}
+
+SalGraphics* X11SalVirtualDevice::GetGraphics()
+{
+ if( bGraphics_ )
+ return NULL;
+
+ if( pGraphics_ )
+ bGraphics_ = sal_True;
+
+ return pGraphics_;
+}
+
+void X11SalVirtualDevice::ReleaseGraphics( SalGraphics* )
+{ bGraphics_ = sal_False; }
+
+sal_Bool X11SalVirtualDevice::SetSize( long nDX, long nDY )
+{
+ if( bExternPixmap_ )
+ return sal_False;
+
+ // #144688#
+ // the X protocol request CreatePixmap puts an upper bound
+ // of 16 bit to the size. Beyond that there may be implementation
+ // limits of the Xserver; which we should catch by a failed XCreatePixmap
+ // call. However extra large values should be caught here since we'd run into
+ // 16 bit truncation here without noticing.
+ if( nDX < 0 || nDX > 65535 ||
+ nDY < 0 || nDY > 65535 )
+ return sal_False;
+
+ if( !nDX ) nDX = 1;
+ if( !nDY ) nDY = 1;
+
+ Pixmap h = XCreatePixmap( GetXDisplay(),
+ pDisplay_->GetDrawable( m_nScreen ),
+ nDX, nDY, nDepth_ );
+
+ if( !h )
+ {
+ if( !GetDrawable() )
+ {
+ hDrawable_ = XCreatePixmap( GetXDisplay(),
+ pDisplay_->GetDrawable( m_nScreen ),
+ 1, 1, nDepth_ );
+ nDX_ = 1;
+ nDY_ = 1;
+ }
+ return sal_False;
+ }
+
+ if( GetDrawable() )
+ XFreePixmap( GetXDisplay(), GetDrawable() );
+ hDrawable_ = h;
+
+ nDX_ = nDX;
+ nDY_ = nDY;
+
+ if( pGraphics_ )
+ InitGraphics( this );
+
+ return sal_True;
+}
+
+void X11SalVirtualDevice::GetSize( long& rWidth, long& rHeight )
+{
+ rWidth = GetWidth();
+ rHeight = GetHeight();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/xrender_peer.cxx b/vcl/unx/generic/gdi/xrender_peer.cxx
new file mode 100644
index 000000000000..eda3254958f0
--- /dev/null
+++ b/vcl/unx/generic/gdi/xrender_peer.cxx
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <rtl/ustring.hxx>
+#include <osl/module.h>
+
+#include <unx/salunx.h>
+#include <unx/saldata.hxx>
+#include <unx/saldisp.hxx>
+
+using ::rtl::OUString;
+using ::rtl::OUStringToOString;
+#include <xrender_peer.hxx>
+
+using namespace rtl;
+
+// ---------------------------------------------------------------------------
+
+XRenderPeer::XRenderPeer()
+: mpDisplay( GetX11SalData()->GetDisplay()->GetDisplay() ),
+ mpStandardFormatA8( NULL ),
+ mnRenderVersion( 0 ),
+ mpRenderLib( NULL )
+#ifndef XRENDER_LINK
+, mpXRenderCompositeTrapezoids( NULL )
+, mpXRenderAddTraps( NULL )
+#endif // XRENDER_LINK
+{
+ InitRenderLib();
+}
+
+// ---------------------------------------------------------------------------
+
+XRenderPeer::~XRenderPeer()
+{
+ osl_unloadModule( mpRenderLib );
+}
+
+// ---------------------------------------------------------------------------
+
+XRenderPeer& XRenderPeer::GetInstance()
+{
+ static XRenderPeer aPeer;
+ return aPeer;
+}
+
+// ---------------------------------------------------------------------------
+
+void XRenderPeer::InitRenderLib()
+{
+ int nDummy;
+ if( !XQueryExtension( mpDisplay, "RENDER", &nDummy, &nDummy, &nDummy ) )
+ return;
+
+#ifndef XRENDER_LINK
+ // we don't know if we are running on a system with xrender library
+ // we don't want to install system libraries ourselves
+ // => load them dynamically when they are there
+ const OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libXrender.so.1" ));
+ mpRenderLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT );
+ if( !mpRenderLib ) {
+#ifdef DEBUG
+ fprintf( stderr, "Display can do XRender, but no %s installed.\n"
+ "Please install for improved display performance\n", OUStringToOString( aLibName.getStr(),
+ osl_getThreadTextEncoding() ).getStr() );
+#endif
+ return;
+ }
+
+ oslGenericFunction pFunc;
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderQueryExtension" );
+ if( !pFunc ) return;
+ mpXRenderQueryExtension = (Bool(*)(Display*,int*,int*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderQueryVersion" );
+ if( !pFunc ) return;
+ mpXRenderQueryVersion = (void(*)(Display*,int*,int*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFindVisualFormat" );
+ if( !pFunc ) return;
+ mpXRenderFindVisualFormat = (XRenderPictFormat*(*)(Display*,Visual*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFindStandardFormat" );
+ if( !pFunc ) return;
+ mpXRenderFindStandardFormat = (XRenderPictFormat*(*)(Display*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFindFormat" );
+ if( !pFunc ) return;
+ mpXRenderFindFormat = (XRenderPictFormat*(*)(Display*,unsigned long,
+ const XRenderPictFormat*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCreateGlyphSet" );
+ if( !pFunc ) return;
+ mpXRenderCreateGlyphSet = (GlyphSet(*)(Display*,const XRenderPictFormat*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFreeGlyphSet" );
+ if( !pFunc ) return;
+ mpXRenderFreeGlyphSet = (void(*)(Display*,GlyphSet))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderAddGlyphs" );
+ if( !pFunc ) return;
+ mpXRenderAddGlyphs = (void(*)(Display*,GlyphSet,Glyph*,const XGlyphInfo*,
+ int,const char*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFreeGlyphs" );
+ if( !pFunc ) return;
+ mpXRenderFreeGlyphs = (void(*)(Display*,GlyphSet,Glyph*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCompositeString32" );
+ if( !pFunc ) return;
+ mpXRenderCompositeString32 = (void(*)(Display*,int,Picture,Picture,
+ const XRenderPictFormat*,GlyphSet,int,int,int,int,const unsigned*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCreatePicture" );
+ if( !pFunc ) return;
+ mpXRenderCreatePicture = (Picture(*)(Display*,Drawable,const XRenderPictFormat*,
+ unsigned long,const XRenderPictureAttributes*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderChangePicture" );
+ if( !pFunc ) return;
+ mpXRenderChangePicture = (void(*)(Display*,Picture,unsigned long,const XRenderPictureAttributes*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderSetPictureClipRegion" );
+ if( !pFunc ) return;
+ mpXRenderSetPictureClipRegion = (void(*)(Display*,Picture,XLIB_Region))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFreePicture" );
+ if( !pFunc ) return;
+ mpXRenderFreePicture = (void(*)(Display*,Picture))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderComposite" );
+ if( !pFunc ) return;
+ mpXRenderComposite = (void(*)(Display*,int,Picture,Picture,Picture,
+ int,int,int,int,int,int,unsigned,unsigned))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFillRectangle" );
+ if( !pFunc ) return;
+ mpXRenderFillRectangle = (void(*)(Display*,int,Picture,const XRenderColor*,
+ int,int,unsigned int,unsigned int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCompositeTrapezoids" );
+ mpXRenderCompositeTrapezoids = (void(*)(Display*,int,Picture,Picture,
+ const XRenderPictFormat*,int,int,const XTrapezoid*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderAddTraps" );
+ mpXRenderAddTraps = (void(*)(Display*,Picture,int,int,const _XTrap*,int))pFunc;
+
+#endif // XRENDER_LINK
+
+ // needed to initialize libXrender internals, we already know its there
+#ifdef XRENDER_LINK
+ XRenderQueryExtension( mpDisplay, &nDummy, &nDummy );
+#else
+ (*mpXRenderQueryExtension)( mpDisplay, &nDummy, &nDummy );
+#endif
+
+ int nMajor, nMinor;
+#ifdef XRENDER_LINK
+ XRenderQueryVersion( mpDisplay, &nMajor, &nMinor );
+#else
+ (*mpXRenderQueryVersion)( mpDisplay, &nMajor, &nMinor );
+#endif
+ mnRenderVersion = 16*nMajor + nMinor;
+
+ // the 8bit alpha mask format must be there
+ XRenderPictFormat aPictFormat={0,0,8,{0,0,0,0,0,0,0,0xFF},0};
+ mpStandardFormatA8 = FindPictureFormat( PictFormatAlphaMask|PictFormatDepth, aPictFormat );
+}
+
+// ---------------------------------------------------------------------------
+
+// return mask of screens capable of XRENDER text
+sal_uInt32 XRenderPeer::InitRenderText()
+{
+ if( mnRenderVersion < 0x01 )
+ return 0;
+
+ // #93033# disable XRENDER for old RENDER versions if XINERAMA is present
+ int nDummy;
+ if( XQueryExtension( mpDisplay, "XINERAMA", &nDummy, &nDummy, &nDummy ) )
+ if( mnRenderVersion < 0x02 )
+ return 0;
+
+ if( !mpStandardFormatA8 )
+ return 0;
+
+ // and the visual must be supported too on at least one screen
+ sal_uInt32 nRetMask = 0;
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ const int nScreenCount = pSalDisp->GetScreenCount();
+ XRenderPictFormat* pVisualFormat = NULL;
+ int nMaxDepth = 0;
+ for( int nScreen = 0; nScreen < nScreenCount; ++nScreen )
+ {
+ Visual* pXVisual = pSalDisp->GetVisual( nScreen ).GetVisual();
+ pVisualFormat = FindVisualFormat( pXVisual );
+ if( pVisualFormat != NULL )
+ {
+ int nVDepth = pSalDisp->GetVisual( nScreen ).GetDepth();
+ if( nVDepth > nMaxDepth )
+ nMaxDepth = nVDepth;
+ nRetMask |= 1U << nScreen;
+ }
+ }
+
+ // #97763# disable XRENDER on <15bit displays for XFree<=4.2.0
+ if( mnRenderVersion <= 0x02 )
+ if( nMaxDepth < 15 )
+ nRetMask = 0;
+
+ return nRetMask;
+}
+
+// ---------------------------------------------------------------------------
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/gdi/xrender_peer.hxx b/vcl/unx/generic/gdi/xrender_peer.hxx
new file mode 100644
index 000000000000..f9417bb2be95
--- /dev/null
+++ b/vcl/unx/generic/gdi/xrender_peer.hxx
@@ -0,0 +1,380 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_XRENDER_PEER_HXX
+#define _SV_XRENDER_PEER_HXX
+
+#include <tools/prex.h>
+struct _XTrap; // on some older systems this is not declared within Xrender.h
+#include <X11/extensions/Xrender.h>
+#include <tools/postx.h>
+
+#include <vcl/salgtype.hxx>
+#include <osl/module.h>
+
+class XRenderPeer
+{
+public:
+ static XRenderPeer& GetInstance();
+ int GetVersion() const;
+
+ sal_uInt32 InitRenderText();
+
+protected:
+ XRenderPeer();
+ ~XRenderPeer();
+ void InitRenderLib();
+
+ Display* mpDisplay;
+ XRenderPictFormat* mpStandardFormatA8;
+ int mnRenderVersion;
+ oslModule mpRenderLib;
+
+public:
+ XRenderPictFormat* GetStandardFormatA8() const;
+ XRenderPictFormat* FindStandardFormat(int nFormat) const;
+
+ // the methods below are thin wrappers for the XRENDER API
+ XRenderPictFormat* FindVisualFormat( Visual* ) const;
+ XRenderPictFormat* FindPictureFormat( unsigned long nMask,
+ const XRenderPictFormat& ) const;
+ Picture CreatePicture( Drawable, const XRenderPictFormat*,
+ unsigned long nDrawable, const XRenderPictureAttributes* ) const;
+ void ChangePicture( Picture, unsigned long nValueMask,
+ const XRenderPictureAttributes* ) const;
+ void SetPictureClipRegion( Picture, XLIB_Region ) const;
+ void CompositePicture( int nOp, Picture aSrc, Picture aMask, Picture aDst,
+ int nXSrc, int nYSrc, int nXMask, int nYMask,
+ int nXDst, int nYDst, unsigned nWidth, unsigned nHeight ) const;
+ void FreePicture( Picture ) const;
+
+ GlyphSet CreateGlyphSet() const;
+ void FreeGlyphSet( GlyphSet ) const;
+ void AddGlyph( GlyphSet, Glyph nGlyphId, const XGlyphInfo&,
+ const char* pBuffer, int nBufSize ) const;
+ void FreeGlyph( GlyphSet, Glyph nGlyphId ) const;
+ void CompositeString32( Picture aSrc, Picture aDst, GlyphSet,
+ int nDstX, int nDstY, const unsigned* pText, int nTextLen ) const;
+ void FillRectangle( int nOp, Picture aDst, const XRenderColor*,
+ int nX, int nY, unsigned nW, unsigned nH ) const;
+ void CompositeTrapezoids( int nOp, Picture aSrc, Picture aDst,
+ const XRenderPictFormat*, int nXSrc, int nYSrc,
+ const XTrapezoid*, int nCount ) const;
+ bool AddTraps( Picture aDst, int nXOfs, int nYOfs,
+ const _XTrap*, int nCount ) const;
+
+ bool AreTrapezoidsSupported() const
+#ifdef XRENDER_LINK
+ { return true; }
+#else
+ { return mpXRenderCompositeTrapezoids!=NULL; }
+
+private:
+ XRenderPictFormat* (*mpXRenderFindFormat)(Display*,unsigned long,
+ const XRenderPictFormat*,int);
+ XRenderPictFormat* (*mpXRenderFindVisualFormat)(Display*,Visual*);
+ XRenderPictFormat* (*mpXRenderFindStandardFormat)(Display*,int);
+ Bool (*mpXRenderQueryExtension)(Display*,int*,int*);
+ void (*mpXRenderQueryVersion)(Display*,int*,int*);
+
+ Picture (*mpXRenderCreatePicture)(Display*,Drawable, const XRenderPictFormat*,
+ unsigned long,const XRenderPictureAttributes*);
+ void (*mpXRenderChangePicture)(Display*,Picture,
+ unsigned long,const XRenderPictureAttributes*);
+ void (*mpXRenderSetPictureClipRegion)(Display*,Picture,XLIB_Region);
+ void (*mpXRenderFreePicture)(Display*,Picture);
+ void (*mpXRenderComposite)(Display*,int,Picture,Picture,Picture,
+ int,int,int,int,int,int,unsigned,unsigned);
+
+ GlyphSet (*mpXRenderCreateGlyphSet)(Display*, const XRenderPictFormat*);
+ void (*mpXRenderFreeGlyphSet)(Display*,GlyphSet);
+ void (*mpXRenderAddGlyphs)(Display*,GlyphSet,Glyph*,
+ const XGlyphInfo*,int,const char*,int);
+ void (*mpXRenderFreeGlyphs)(Display*,GlyphSet,Glyph*,int);
+ void (*mpXRenderCompositeString32)(Display*,int,Picture,Picture,
+ const XRenderPictFormat*,GlyphSet,int,int,int,int,const unsigned*,int);
+ void (*mpXRenderFillRectangle)(Display*,int,Picture,
+ const XRenderColor*,int,int,unsigned int,unsigned int);
+ void (*mpXRenderCompositeTrapezoids)(Display*,int,Picture,Picture,
+ const XRenderPictFormat*,int,int,const XTrapezoid*,int);
+ void (*mpXRenderAddTraps)(Display*,Picture,int,int,const _XTrap*,int);
+#endif // XRENDER_LINK
+};
+
+//=====================================================================
+
+class ScopedPic
+{
+public:
+ ScopedPic( XRenderPeer& rPeer, Picture& rPic );
+ ~ScopedPic();
+ Picture& Get();
+
+private:
+ XRenderPeer& mrRenderPeer;
+ Picture maPicture;
+
+private: // prevent copy and assignmet
+ ScopedPic( const ScopedPic& );
+ void operator=( const ScopedPic& );
+};
+
+//=====================================================================
+
+inline int XRenderPeer::GetVersion() const
+{
+ return mnRenderVersion;
+}
+
+inline XRenderPictFormat* XRenderPeer::GetStandardFormatA8() const
+{
+ return mpStandardFormatA8;
+}
+
+inline XRenderPictFormat* XRenderPeer::FindStandardFormat(int nFormat) const
+{
+#ifdef XRENDER_LINK
+ return XRenderFindStandardFormat(mpDisplay, nFormat);
+#else
+ return (*mpXRenderFindStandardFormat)(mpDisplay, nFormat);
+#endif
+}
+
+inline XRenderPictFormat* XRenderPeer::FindVisualFormat( Visual* pVisual ) const
+{
+#ifdef XRENDER_LINK
+ return XRenderFindVisualFormat ( mpDisplay, pVisual );
+#else
+ return (*mpXRenderFindVisualFormat)( mpDisplay, pVisual );
+#endif
+}
+
+inline XRenderPictFormat* XRenderPeer::FindPictureFormat( unsigned long nFormatMask,
+ const XRenderPictFormat& rFormatAttr ) const
+{
+#ifdef XRENDER_LINK
+ return XRenderFindFormat( mpDisplay, nFormatMask, &rFormatAttr, 0 );
+#else
+ return (*mpXRenderFindFormat)( mpDisplay, nFormatMask, &rFormatAttr, 0 );
+#endif
+}
+
+inline Picture XRenderPeer::CreatePicture( Drawable aDrawable,
+ const XRenderPictFormat* pVisFormat, unsigned long nValueMask,
+ const XRenderPictureAttributes* pRenderAttr ) const
+{
+#ifdef XRENDER_LINK
+ return XRenderCreatePicture( mpDisplay, aDrawable, pVisFormat,
+ nValueMask, pRenderAttr );
+#else
+ return (*mpXRenderCreatePicture)( mpDisplay, aDrawable, pVisFormat,
+ nValueMask, pRenderAttr );
+#endif
+}
+
+inline void XRenderPeer::ChangePicture( Picture aPicture,
+ unsigned long nValueMask, const XRenderPictureAttributes* pRenderAttr ) const
+{
+#ifdef XRENDER_LINK
+ XRenderChangePicture( mpDisplay, aPicture, nValueMask, pRenderAttr );
+#else
+ (*mpXRenderChangePicture)( mpDisplay, aPicture, nValueMask, pRenderAttr );
+#endif
+}
+
+inline void XRenderPeer::SetPictureClipRegion( Picture aPicture,
+ XLIB_Region aXlibRegion ) const
+{
+#ifdef XRENDER_LINK
+ XRenderSetPictureClipRegion( mpDisplay, aPicture, aXlibRegion );
+#else
+ (*mpXRenderSetPictureClipRegion)( mpDisplay, aPicture, aXlibRegion );
+#endif
+}
+
+inline void XRenderPeer::CompositePicture( int nXRenderOp,
+ Picture aSrcPic, Picture aMaskPic, Picture aDstPic,
+ int nSrcX, int nSrcY, int nMaskX, int nMaskY, int nDstX, int nDstY,
+ unsigned nWidth, unsigned nHeight ) const
+{
+#ifdef XRENDER_LINK
+ XRenderComposite( mpDisplay, nXRenderOp, aSrcPic, aMaskPic, aDstPic,
+ nSrcX, nSrcY, nMaskX, nMaskY, nDstX, nDstY, nWidth, nHeight );
+#else
+ (*mpXRenderComposite)( mpDisplay, nXRenderOp, aSrcPic, aMaskPic, aDstPic,
+ nSrcX, nSrcY, nMaskX, nMaskY, nDstX, nDstY, nWidth, nHeight );
+#endif
+}
+
+inline void XRenderPeer::FreePicture( Picture aPicture ) const
+{
+#ifdef XRENDER_LINK
+ XRenderFreePicture( mpDisplay, aPicture );
+#else
+ (*mpXRenderFreePicture)( mpDisplay, aPicture );
+#endif
+}
+
+inline GlyphSet XRenderPeer::CreateGlyphSet() const
+{
+#ifdef XRENDER_LINK
+ return XRenderCreateGlyphSet( mpDisplay, mpStandardFormatA8 );
+#else
+ return (*mpXRenderCreateGlyphSet)( mpDisplay, mpStandardFormatA8 );
+#endif
+}
+
+inline void XRenderPeer::FreeGlyphSet( GlyphSet aGS ) const
+{
+#ifdef XRENDER_LINK
+ XRenderFreeGlyphSet( mpDisplay, aGS );
+#else
+ (*mpXRenderFreeGlyphSet)( mpDisplay, aGS );
+#endif
+}
+
+inline void XRenderPeer::AddGlyph( GlyphSet aGS, Glyph nGlyphId,
+ const XGlyphInfo& rGI, const char* pBuffer, int nBufSize ) const
+{
+#ifdef XRENDER_LINK
+ XRenderAddGlyphs( mpDisplay, aGS, &nGlyphId, &rGI, 1,
+ const_cast<char*>(pBuffer), nBufSize );
+#else
+ (*mpXRenderAddGlyphs)( mpDisplay, aGS, &nGlyphId, &rGI, 1,
+ const_cast<char*>(pBuffer), nBufSize );
+#endif
+}
+
+inline void XRenderPeer::FreeGlyph( GlyphSet aGS, Glyph nGlyphId ) const
+{
+ (void)aGS; (void)nGlyphId;
+
+ // XRenderFreeGlyphs not implemented yet for version<=0.2
+ // #108209# disabled because of crash potential,
+ // the glyph leak is not too bad because they will
+ // be cleaned up when the glyphset is released
+}
+
+inline void XRenderPeer::CompositeString32( Picture aSrc, Picture aDst,
+ GlyphSet aGlyphSet, int nDstX, int nDstY,
+ const unsigned* pText, int nTextLen ) const
+{
+#ifdef XRENDER_LINK
+ XRenderCompositeString32( mpDisplay, PictOpOver, aSrc, aDst, NULL,
+ aGlyphSet, 0, 0, nDstX, nDstY, pText, nTextLen );
+#else
+ (*mpXRenderCompositeString32)( mpDisplay, PictOpOver, aSrc, aDst, NULL,
+ aGlyphSet, 0, 0, nDstX, nDstY, pText, nTextLen );
+#endif
+}
+
+inline void XRenderPeer::FillRectangle( int a, Picture b, const XRenderColor* c,
+ int d, int e, unsigned int f, unsigned int g) const
+{
+#ifdef XRENDER_LINK
+ XRenderFillRectangle( mpDisplay, a, b, c, d, e, f, g );
+#else
+ (*mpXRenderFillRectangle)( mpDisplay, a, b, c, d, e, f, g );
+#endif
+}
+
+
+inline void XRenderPeer::CompositeTrapezoids( int nOp,
+ Picture aSrc, Picture aDst, const XRenderPictFormat* pXRPF,
+ int nXSrc, int nYSrc, const XTrapezoid* pXT, int nCount ) const
+{
+#ifdef XRENDER_LINK
+ XRenderCompositeTrapezoids( mpDisplay, nOp, aSrc, aDst, pXRPF,
+ nXSrc, nYSrc, pXT, nCount );
+#else
+ (*mpXRenderCompositeTrapezoids)( mpDisplay, nOp, aSrc, aDst, pXRPF,
+ nXSrc, nYSrc, pXT, nCount );
+#endif
+}
+
+inline bool XRenderPeer::AddTraps( Picture aDst, int nXOfs, int nYOfs,
+ const _XTrap* pTraps, int nCount ) const
+{
+#ifdef XRENDER_LINK
+ XRenderAddTraps( mpDisplay, aDst, nXOfs, nYOfs, pTraps, nCount );
+#else
+ if( !mpXRenderAddTraps )
+ return false;
+ (*mpXRenderAddTraps)( mpDisplay, aDst, nXOfs, nYOfs, pTraps, nCount );
+#endif
+ return true;
+}
+
+//=====================================================================
+
+inline ScopedPic::ScopedPic( XRenderPeer& rPeer, Picture& rPic )
+: mrRenderPeer( rPeer)
+, maPicture( rPic )
+{}
+
+inline ScopedPic::~ScopedPic()
+{
+ if( maPicture )
+ mrRenderPeer.FreePicture( maPicture );
+}
+
+inline Picture& ScopedPic::Get()
+{
+ return maPicture;
+}
+
+//=====================================================================
+
+inline XRenderColor GetXRenderColor( const SalColor& rSalColor, double fTransparency = 0.0 )
+{
+ XRenderColor aRetVal;
+ // convert the SalColor
+ aRetVal.red = SALCOLOR_RED( rSalColor ); aRetVal.red |= (aRetVal.red << 8);
+ aRetVal.green = SALCOLOR_GREEN( rSalColor ); aRetVal.green |= (aRetVal.green << 8);
+ aRetVal.blue = SALCOLOR_BLUE( rSalColor ); aRetVal.blue |= (aRetVal.blue << 8);
+
+ // handle transparency
+ aRetVal.alpha = 0xFFFF; // default to opaque
+ if( fTransparency != 0 )
+ {
+ const double fAlpha = 1.0 - fTransparency;
+ aRetVal.alpha = static_cast<sal_uInt16>(fAlpha * 0xFFFF + 0.5);
+ // xrender wants pre-multiplied colors
+ aRetVal.red = static_cast<sal_uInt16>(fAlpha * aRetVal.red + 0.5);
+ aRetVal.green = static_cast<sal_uInt16>(fAlpha * aRetVal.green + 0.5);
+ aRetVal.blue = static_cast<sal_uInt16>(fAlpha * aRetVal.blue + 0.5);
+ }
+
+ return aRetVal;
+}
+
+//=====================================================================
+
+#endif // _SV_XRENDER_PEER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/plugadapt/salplug.cxx b/vcl/unx/generic/plugadapt/salplug.cxx
new file mode 100644
index 000000000000..476ea135e570
--- /dev/null
+++ b/vcl/unx/generic/plugadapt/salplug.cxx
@@ -0,0 +1,309 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 "osl/module.h"
+#include "osl/process.h"
+
+#include "rtl/ustrbuf.hxx"
+
+#include "salinst.hxx"
+#include "unx/saldata.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include <cstdio>
+#include <unistd.h>
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+extern "C" {
+typedef SalInstance*(*salFactoryProc)( oslModule pModule);
+}
+
+static oslModule pCloseModule = NULL;
+
+enum {
+ DESKTOP_NONE = 0,
+ DESKTOP_UNKNOWN,
+ DESKTOP_GNOME,
+ DESKTOP_KDE,
+ DESKTOP_KDE4,
+ DESKTOP_CDE
+};
+
+static const char * desktop_strings[] = { "none", "unknown", "GNOME", "KDE", "KDE4", "CDE" };
+
+static SalInstance* tryInstance( const OUString& rModuleBase )
+{
+ SalInstance* pInst = NULL;
+
+ OUStringBuffer aModName( 128 );
+ aModName.appendAscii( SAL_DLLPREFIX"vclplug_" );
+ aModName.append( rModuleBase );
+ aModName.appendAscii( SAL_DLLPOSTFIX );
+ OUString aModule = aModName.makeStringAndClear();
+
+ oslModule aMod = osl_loadModuleRelative(
+ reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData,
+ SAL_LOADMODULE_DEFAULT );
+ if( aMod )
+ {
+ salFactoryProc aProc = (salFactoryProc)osl_getAsciiFunctionSymbol( aMod, "create_SalInstance" );
+ if( aProc )
+ {
+ pInst = aProc( aMod );
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "sal plugin %s produced instance %p\n",
+ OUStringToOString( aModule, RTL_TEXTENCODING_ASCII_US ).getStr(),
+ pInst );
+#endif
+ if( pInst )
+ {
+ pCloseModule = aMod;
+
+ /*
+ * Recent GTK+ versions load their modules with RTLD_LOCAL, so we can
+ * not access the 'gnome_accessibility_module_shutdown' anymore.
+ * So make sure libgtk+ & co are still mapped into memory when
+ * atk-bridge's atexit handler gets called.
+ */
+ if( rModuleBase.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("gtk")) )
+ {
+ pCloseModule = NULL;
+ }
+ /*
+ * #i109007# KDE3 seems to have the same problem; an atexit cleanup
+ * handler, which cannot be resolved anymore if the plugin is already unloaded.
+ */
+ else if( rModuleBase.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("kde")) )
+ {
+ pCloseModule = NULL;
+ }
+
+ GetSalData()->m_pPlugin = aMod;
+ }
+ else
+ osl_unloadModule( aMod );
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "could not load symbol %s from shared object %s\n",
+ "create_SalInstance",
+ OUStringToOString( aModule, RTL_TEXTENCODING_ASCII_US ).getStr() );
+#endif
+ osl_unloadModule( aMod );
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ std::fprintf( stderr, "could not load shared object %s\n",
+ OUStringToOString( aModule, RTL_TEXTENCODING_ASCII_US ).getStr() );
+#endif
+
+ return pInst;
+}
+
+static const rtl::OUString& get_desktop_environment()
+{
+ static rtl::OUString aRet;
+ if( ! aRet.getLength() )
+ {
+ OUStringBuffer aModName( 128 );
+ aModName.appendAscii( SAL_DLLPREFIX"desktop_detector" );
+ aModName.appendAscii( SAL_DLLPOSTFIX );
+ aModName.appendAscii( SAL_DLLEXTENSION );
+ OUString aModule = aModName.makeStringAndClear();
+
+ oslModule aMod = osl_loadModuleRelative(
+ reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData,
+ SAL_LOADMODULE_DEFAULT );
+ if( aMod )
+ {
+ rtl::OUString (*pSym)() = (rtl::OUString(*)())
+ osl_getAsciiFunctionSymbol( aMod, "get_desktop_environment" );
+ if( pSym )
+ aRet = pSym();
+ }
+ osl_unloadModule( aMod );
+ }
+ return aRet;
+}
+
+static SalInstance* autodetect_plugin()
+{
+ static const char* pKDEFallbackList[] =
+ {
+ "kde4", "kde", "gtk", "gen", 0
+ };
+
+ static const char* pStandardFallbackList[] =
+ {
+ "gtk", "gen", 0
+ };
+
+ static const char* pHeadlessFallbackList[] =
+ {
+ "svp", 0
+ };
+
+ const rtl::OUString& desktop( get_desktop_environment() );
+ const char ** pList = pStandardFallbackList;
+ int nListEntry = 0;
+
+ // no server at all: dummy plugin
+ if ( desktop.equalsAscii( desktop_strings[DESKTOP_NONE] ) )
+ pList = pHeadlessFallbackList;
+ else if ( desktop.equalsAscii( desktop_strings[DESKTOP_GNOME] ) )
+ pList = pStandardFallbackList;
+ else if( desktop.equalsAscii( desktop_strings[DESKTOP_KDE] ) )
+ {
+ pList = pKDEFallbackList;
+ nListEntry = 1;
+ }
+ else if( desktop.equalsAscii( desktop_strings[DESKTOP_KDE4] ) )
+ pList = pKDEFallbackList;
+
+ SalInstance* pInst = NULL;
+ while( pList[nListEntry] && pInst == NULL )
+ {
+ rtl::OUString aTry( rtl::OUString::createFromAscii( pList[nListEntry] ) );
+ pInst = tryInstance( aTry );
+ #if OSL_DEBUG_LEVEL > 1
+ if( pInst )
+ std::fprintf( stderr, "plugin autodetection: %s\n", pList[nListEntry] );
+ #endif
+ nListEntry++;
+ }
+
+ return pInst;
+}
+
+static SalInstance* check_headless_plugin()
+{
+ int nParams = osl_getCommandArgCount();
+ OUString aParam;
+ for( int i = 0; i < nParams; i++ )
+ {
+ osl_getCommandArg( i, &aParam.pData );
+ if( aParam.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("-headless")) ||
+ aParam.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("--headless")) )
+ {
+ return tryInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "svp" ) ) );
+ }
+ }
+ return NULL;
+}
+
+SalInstance *CreateSalInstance()
+{
+ SalInstance* pInst = NULL;
+
+ static const char* pUsePlugin = getenv( "SAL_USE_VCLPLUGIN" );
+
+ if( !(pUsePlugin && *pUsePlugin) )
+ pInst = check_headless_plugin();
+ else
+ pInst = tryInstance( OUString::createFromAscii( pUsePlugin ) );
+
+ if( ! pInst )
+ pInst = autodetect_plugin();
+
+ // fallback, try everything
+ const char* pPlugin[] = { "gtk", "kde", "gen", 0 };
+
+ for ( int i = 0; !pInst && pPlugin[ i ]; ++i )
+ pInst = tryInstance( OUString::createFromAscii( pPlugin[ i ] ) );
+
+ if( ! pInst )
+ {
+ std::fprintf( stderr, "no suitable windowing system found, exiting.\n" );
+ _exit( 1 );
+ }
+
+ // acquire SolarMutex
+ pInst->AcquireYieldMutex( 1 );
+
+ return pInst;
+}
+
+void DestroySalInstance( SalInstance *pInst )
+{
+ // release SolarMutex
+ pInst->ReleaseYieldMutex();
+
+ delete pInst;
+ if( pCloseModule )
+ osl_unloadModule( pCloseModule );
+}
+
+void InitSalData()
+{
+}
+
+void DeInitSalData()
+{
+}
+
+void InitSalMain()
+{
+}
+
+void DeInitSalMain()
+{
+}
+
+void SalAbort( const XubString& rErrorText )
+{
+ if( !rErrorText.Len() )
+ std::fprintf( stderr, "Application Error" );
+ else
+ std::fprintf( stderr, "%s", ByteString( rErrorText, gsl_getSystemTextEncoding() ).GetBuffer() );
+ exit(-1);
+}
+
+const OUString& SalGetDesktopEnvironment()
+{
+ return get_desktop_environment();
+}
+
+SalData::SalData() :
+ m_pInstance(NULL),
+ m_pPlugin(NULL),
+ m_pPIManager(NULL)
+{
+}
+
+SalData::~SalData()
+{
+ psp::PrinterInfoManager::release();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/printer/cupsmgr.cxx b/vcl/unx/generic/printer/cupsmgr.cxx
new file mode 100644
index 000000000000..a850ec14bb28
--- /dev/null
+++ b/vcl/unx/generic/printer/cupsmgr.cxx
@@ -0,0 +1,1181 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 ENABLE_CUPS
+#include <cups/cups.h>
+#include <cups/ppd.h>
+
+#else // !ENABLE_CUPS
+typedef void ppd_file_t;
+typedef void cups_dest_t;
+typedef void cups_option_t;
+#endif
+
+#include <unistd.h>
+
+#include "cupsmgr.hxx"
+
+#include "osl/thread.h"
+#include "osl/diagnose.h"
+#include "osl/conditn.hxx"
+
+#include "rtl/ustrbuf.hxx"
+
+#include <algorithm>
+#include <setjmp.h>
+#include <signal.h>
+
+#define CUPS_LIB_NAME "libcups.so.2"
+
+namespace psp
+{
+class CUPSWrapper
+{
+ oslModule m_pLib;
+ osl::Mutex m_aGetPPDMutex;
+ bool m_bPPDThreadRunning;
+
+ int (*m_pcupsPrintFile)(const char*, const char*, const char*, int, cups_option_t*);
+ int (*m_pcupsGetDests)(cups_dest_t**);
+ void (*m_pcupsSetDests)(int,cups_dest_t*);
+ void (*m_pcupsFreeDests)(int,cups_dest_t*);
+ const char* (*m_pcupsGetPPD)(const char*);
+ int (*m_pcupsMarkOptions)(ppd_file_t*,int,cups_option_t*);
+ int (*m_pcupsAddOption)(const char*,const char*,int,cups_option_t**);
+ void (*m_pcupsFreeOptions)(int,cups_option_t*);
+ ppd_file_t* (*m_pppdOpenFile)(const char* pFile);
+ void (*m_pppdClose)(ppd_file_t*);
+ const char* (*m_pcupsServer)();
+ void (*m_pcupsSetPasswordCB)(const char*(cb)(const char*));
+ const char* (*m_pcupsUser)();
+ void (*m_pcupsSetUser)(const char*);
+ const char* (*m_pcupsGetOption)(const char*,int,cups_option_t*);
+
+ oslGenericFunction loadSymbol( const char* );
+public:
+ CUPSWrapper();
+ ~CUPSWrapper();
+
+ bool isValid();
+
+ int cupsGetDests(cups_dest_t** pDests)
+ { return m_pcupsGetDests(pDests); }
+
+ void cupsSetDests( int nDests, cups_dest_t* pDests )
+ { m_pcupsSetDests( nDests, pDests ); }
+
+ void cupsFreeDests(int nDests, cups_dest_t* pDests)
+ { m_pcupsFreeDests(nDests, pDests); }
+
+ int cupsPrintFile( const char* pPrinter,
+ const char* pFileName,
+ const char* pTitle,
+ int nOptions,
+ cups_option_t* pOptions )
+ { return m_pcupsPrintFile( pPrinter, pFileName, pTitle, nOptions, pOptions ); }
+
+ rtl::OString cupsGetPPD( const char* pPrinter );
+
+ int cupsMarkOptions(ppd_file_t* pPPD, int nOptions, cups_option_t* pOptions )
+ { return m_pcupsMarkOptions(pPPD, nOptions, pOptions); }
+
+ int cupsAddOption( const char* pName, const char* pValue, int nOptions, cups_option_t** pOptions )
+ { return m_pcupsAddOption( pName, pValue, nOptions, pOptions ); }
+
+ void cupsFreeOptions( int nOptions, cups_option_t* pOptions )
+ { m_pcupsFreeOptions( nOptions, pOptions ); }
+
+ ppd_file_t* ppdOpenFile( const char* pFileName )
+ { return m_pppdOpenFile( pFileName ); }
+
+ void ppdClose( ppd_file_t* pPPD )
+ { m_pppdClose( pPPD ); }
+
+ const char *cupsServer(void)
+ { return m_pcupsServer(); }
+
+ const char *cupsUser(void)
+ { return m_pcupsUser(); }
+
+ void cupsSetPasswordCB(const char *(*cb)(const char *))
+ { m_pcupsSetPasswordCB( cb ); }
+
+ void cupsSetUser(const char *user)
+ { m_pcupsSetUser( user ); }
+
+ const char* cupsGetOption(const char* name, int num_options, cups_option_t* options)
+ { return m_pcupsGetOption( name, num_options, options ); }
+
+};
+}
+
+using namespace psp;
+using namespace osl;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::rtl::OUStringToOString;
+using ::rtl::OStringToOUString;
+using ::rtl::OUStringHash;
+using ::rtl::OString;
+
+/*
+ * CUPSWrapper class
+ */
+
+oslGenericFunction CUPSWrapper::loadSymbol( const char* pSymbol )
+{
+ OUString aSym( OUString::createFromAscii( pSymbol ) );
+ oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" );
+#endif
+ return pSym;
+}
+
+CUPSWrapper::CUPSWrapper()
+ : m_pLib( NULL ),
+ m_bPPDThreadRunning( false )
+{
+#ifdef ENABLE_CUPS
+ OUString aLib( RTL_CONSTASCII_USTRINGPARAM( CUPS_LIB_NAME ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ if( ! m_pLib )
+ {
+ aLib = OUString( RTL_CONSTASCII_USTRINGPARAM( SAL_MODULENAME( "cups" ) ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ }
+#endif
+
+ if( ! m_pLib )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "no cups library found\n" );
+#endif
+ return;
+ }
+
+ m_pcupsPrintFile = (int(*)(const char*,const char*,const char*,int,cups_option_t*))
+ loadSymbol( "cupsPrintFile" );
+ m_pcupsGetDests = (int(*)(cups_dest_t**))
+ loadSymbol( "cupsGetDests" );
+ m_pcupsSetDests = (void(*)(int,cups_dest_t*))
+ loadSymbol( "cupsSetDests" );
+ m_pcupsFreeDests = (void(*)(int,cups_dest_t*))
+ loadSymbol( "cupsFreeDests" );
+ m_pcupsGetPPD = (const char*(*)(const char*))
+ loadSymbol( "cupsGetPPD" );
+ m_pcupsMarkOptions = (int(*)(ppd_file_t*,int,cups_option_t*))
+ loadSymbol( "cupsMarkOptions" );
+ m_pcupsAddOption = (int(*)(const char*,const char*,int,cups_option_t**))
+ loadSymbol( "cupsAddOption" );
+ m_pcupsFreeOptions = (void(*)(int,cups_option_t*))
+ loadSymbol( "cupsFreeOptions" );
+ m_pppdOpenFile = (ppd_file_t*(*)(const char*))
+ loadSymbol( "ppdOpenFile" );
+ m_pppdClose = (void(*)(ppd_file_t*))
+ loadSymbol( "ppdClose" );
+ m_pcupsServer = (const char*(*)())
+ loadSymbol( "cupsServer" );
+ m_pcupsUser = (const char*(*)())
+ loadSymbol( "cupsUser" );
+ m_pcupsSetPasswordCB = (void(*)(const char*(*)(const char*)))
+ loadSymbol( "cupsSetPasswordCB" );
+ m_pcupsSetUser = (void(*)(const char*))
+ loadSymbol( "cupsSetUser" );
+ m_pcupsGetOption = (const char*(*)(const char*,int,cups_option_t*))
+ loadSymbol( "cupsGetOption" );
+
+ if( ! (
+ m_pcupsPrintFile &&
+ m_pcupsGetDests &&
+ m_pcupsSetDests &&
+ m_pcupsFreeDests &&
+ m_pcupsGetPPD &&
+ m_pcupsMarkOptions &&
+ m_pcupsAddOption &&
+ m_pcupsServer &&
+ m_pcupsUser &&
+ m_pcupsSetPasswordCB &&
+ m_pcupsSetUser &&
+ m_pcupsFreeOptions &&
+ m_pppdOpenFile &&
+ m_pppdClose &&
+ m_pcupsGetOption
+ ) )
+ {
+ osl_unloadModule( m_pLib );
+ m_pLib = NULL;
+ }
+}
+
+CUPSWrapper::~CUPSWrapper()
+{
+ if( m_pLib )
+ osl_unloadModule( m_pLib );
+}
+
+bool CUPSWrapper::isValid()
+{
+ return m_pLib != NULL;
+}
+
+typedef const char*(*PPDFunction)(const char*);
+struct GetPPDAttribs
+{
+ PPDFunction m_pFunction;
+ osl::Condition m_aCondition;
+ OString m_aParameter;
+ OString m_aResult;
+ oslThread m_aThread;
+ int m_nRefs;
+ bool* m_pResetRunning;
+ osl::Mutex* m_pSyncMutex;
+
+ GetPPDAttribs( PPDFunction pFn, const char * m_pParameter,
+ bool* pResetRunning, osl::Mutex* pSyncMutex )
+ : m_pFunction( pFn ),
+ m_aParameter( m_pParameter ),
+ m_pResetRunning( pResetRunning ),
+ m_pSyncMutex( pSyncMutex )
+ {
+ m_nRefs = 2;
+ m_aCondition.reset();
+ }
+
+ ~GetPPDAttribs()
+ {
+ if( m_aResult.getLength() )
+ unlink( m_aResult.getStr() );
+ }
+
+ void unref()
+ {
+ if( --m_nRefs == 0 )
+ {
+ *m_pResetRunning = false;
+ delete this;
+ }
+ }
+
+ void executeCall()
+ {
+ // This CUPS method is not at all thread-safe we need
+ // to dup the pointer to a static buffer it returns ASAP
+ OString aResult = m_pFunction( m_aParameter );
+ MutexGuard aGuard( *m_pSyncMutex );
+ m_aResult = aResult;
+ m_aCondition.set();
+ unref();
+ }
+
+ OString waitResult( TimeValue *pDelay )
+ {
+ m_pSyncMutex->release();
+
+ if (m_aCondition.wait( pDelay ) != Condition::result_ok
+ )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "cupsGetPPD %s timed out\n",
+ (const sal_Char *) m_aParameter
+ );
+ #endif
+ }
+ m_pSyncMutex->acquire();
+
+ OString aRetval = m_aResult;
+ m_aResult = OString();
+ unref();
+
+ return aRetval;
+ }
+};
+
+extern "C" {
+ static void getPPDWorker(void* pData)
+ {
+ GetPPDAttribs* pAttribs = (GetPPDAttribs*)pData;
+ pAttribs->executeCall();
+ }
+}
+
+OString CUPSWrapper::cupsGetPPD( const char* pPrinter )
+{
+ OString aResult;
+
+ m_aGetPPDMutex.acquire();
+ // if one thread hangs in cupsGetPPD already, don't start another
+ if( ! m_bPPDThreadRunning )
+ {
+ m_bPPDThreadRunning = true;
+ GetPPDAttribs* pAttribs = new GetPPDAttribs( m_pcupsGetPPD,
+ pPrinter,
+ &m_bPPDThreadRunning,
+ &m_aGetPPDMutex );
+
+ oslThread aThread = osl_createThread( getPPDWorker, pAttribs );
+
+ TimeValue aValue;
+ aValue.Seconds = 5;
+ aValue.Nanosec = 0;
+
+ // NOTE: waitResult release and acquires the GetPPD mutex
+ aResult = pAttribs->waitResult( &aValue );
+ osl_destroyThread( aThread );
+ }
+ m_aGetPPDMutex.release();
+
+ return aResult;
+}
+
+#ifdef ENABLE_CUPS
+static const char* setPasswordCallback( const char* pIn )
+{
+ const char* pRet = NULL;
+
+ PrinterInfoManager& rMgr = PrinterInfoManager::get();
+ if( rMgr.getType() == PrinterInfoManager::CUPS ) // sanity check
+ pRet = static_cast<CUPSManager&>(rMgr).authenticateUser( pIn );
+ return pRet;
+}
+#endif
+
+/*
+ * CUPSManager class
+ */
+
+CUPSManager* CUPSManager::tryLoadCUPS()
+{
+ CUPSManager* pManager = NULL;
+#ifdef ENABLE_CUPS
+ static const char* pEnv = getenv( "SAL_DISABLE_CUPS" );
+
+ if( ! pEnv || ! *pEnv )
+ {
+ // try to load CUPS
+ CUPSWrapper* pWrapper = new CUPSWrapper();
+ if( pWrapper->isValid() )
+ pManager = new CUPSManager( pWrapper );
+ else
+ delete pWrapper;
+ }
+#endif
+ return pManager;
+}
+
+extern "C"
+{
+static void run_dest_thread_stub( void* pThis )
+{
+ CUPSManager::runDestThread( pThis );
+}
+}
+
+CUPSManager::CUPSManager( CUPSWrapper* pWrapper ) :
+ PrinterInfoManager( CUPS ),
+ m_pCUPSWrapper( pWrapper ),
+ m_nDests( 0 ),
+ m_pDests( NULL ),
+ m_bNewDests( false )
+{
+ m_aDestThread = osl_createThread( run_dest_thread_stub, this );
+}
+
+CUPSManager::~CUPSManager()
+{
+ if( m_aDestThread )
+ {
+ // if the thread is still running here, then
+ // cupsGetDests is hung; terminate the thread instead of joining
+ osl_terminateThread( m_aDestThread );
+ osl_destroyThread( m_aDestThread );
+ }
+
+ if( m_nDests && m_pDests )
+ m_pCUPSWrapper->cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests );
+ delete m_pCUPSWrapper;
+}
+
+void CUPSManager::runDestThread( void* pThis )
+{
+ ((CUPSManager*)pThis)->runDests();
+}
+
+static sigjmp_buf aViolationBuffer;
+
+extern "C"
+{
+ static void lcl_signal_action(int nSignal)
+ {
+ fprintf( stderr, "Signal %d during fontconfig initialization called, ignoring fontconfig\n", nSignal );
+ siglongjmp( aViolationBuffer, 1 );
+ }
+}
+
+void CUPSManager::runDests()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "starting cupsGetDests\n" );
+#endif
+ cups_dest_t* pDests = NULL;
+
+ // #i86306# prepare against really broken CUPS installations / missing servers
+
+ // install signal handler for SEGV, BUS and ABRT
+ struct sigaction act;
+ struct sigaction oact[3];
+
+ act.sa_handler = lcl_signal_action;
+ act.sa_flags = 0;
+ sigemptyset(&(act.sa_mask));
+
+ int nSegvSignalInstalled = sigaction(SIGSEGV, &act, &oact[0]);
+ int nBusSignalInstalled = sigaction(SIGBUS, &act, &oact[1]);
+ int nAbortSignalInstalled = sigaction(SIGABRT, &act, &oact[2]);
+
+ // prepare against a signal during FcInit or FcConfigGetCurrent
+ if( sigsetjmp( aViolationBuffer, ~0 ) == 0 )
+ {
+ int nDests = m_pCUPSWrapper->cupsGetDests( &pDests );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "came out of cupsGetDests\n" );
+ #endif
+
+ osl::MutexGuard aGuard( m_aCUPSMutex );
+ m_nDests = nDests;
+ m_pDests = pDests;
+ m_bNewDests = true;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "finished cupsGetDests\n" );
+ #endif
+ }
+ else
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "cupsGetDests crashed, not using CUPS\n" );
+ #endif
+ }
+
+ // restore old signal handlers
+ if( nSegvSignalInstalled == 0 )
+ sigaction( SIGSEGV, &oact[0], NULL );
+ if( nBusSignalInstalled == 0 )
+ sigaction( SIGBUS, &oact[1], NULL );
+ if( nAbortSignalInstalled == 0 )
+ sigaction( SIGABRT, &oact[2], NULL );
+}
+
+void CUPSManager::initialize()
+{
+ // get normal printers, clear printer list
+ PrinterInfoManager::initialize();
+
+#ifdef ENABLE_CUPS
+ // check whether thread has completed
+ // if not behave like old printing system
+ osl::MutexGuard aGuard( m_aCUPSMutex );
+
+ if( ! m_bNewDests )
+ return;
+
+ // dest thread has run, clean up
+ if( m_aDestThread )
+ {
+ osl_joinWithThread( m_aDestThread );
+ osl_destroyThread( m_aDestThread );
+ m_aDestThread = NULL;
+ }
+ m_bNewDests = false;
+
+ // clear old stuff
+ m_aCUPSDestMap.clear();
+
+ if( ! (m_nDests && m_pDests ) )
+ return;
+
+ if( isCUPSDisabled() )
+ return;
+
+ // check for CUPS server(?) > 1.2
+ // since there is no API to query, check for options that were
+ // introduced in dests with 1.2
+ // this is needed to check for %%IncludeFeature support
+ // (#i65684#, #i65491#)
+ bool bUsePDF = false;
+ cups_dest_t* pDest = ((cups_dest_t*)m_pDests);
+ const char* pOpt = m_pCUPSWrapper->cupsGetOption( "printer-info",
+ pDest->num_options,
+ pDest->options );
+ if( pOpt )
+ {
+ m_bUseIncludeFeature = true;
+ bUsePDF = true;
+ if( m_aGlobalDefaults.m_nPSLevel == 0 && m_aGlobalDefaults.m_nPDFDevice == 0 )
+ m_aGlobalDefaults.m_nPDFDevice = 1;
+ }
+ // do not send include JobPatch; CUPS will insert that itself
+ // TODO: currently unknwon which versions of CUPS insert JobPatches
+ // so currently it is assumed CUPS = don't insert JobPatch files
+ m_bUseJobPatch = false;
+
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ int nPrinter = m_nDests;
+
+ // reset global default PPD options; these are queried on demand from CUPS
+ m_aGlobalDefaults.m_pParser = NULL;
+ m_aGlobalDefaults.m_aContext = PPDContext();
+
+ // add CUPS printers, should there be a printer
+ // with the same name as a CUPS printer, overwrite it
+ while( nPrinter-- )
+ {
+ pDest = ((cups_dest_t*)m_pDests)+nPrinter;
+ OUString aPrinterName = OStringToOUString( pDest->name, aEncoding );
+ if( pDest->instance && *pDest->instance )
+ {
+ OUStringBuffer aBuf( 256 );
+ aBuf.append( aPrinterName );
+ aBuf.append( sal_Unicode( '/' ) );
+ aBuf.append( OStringToOUString( pDest->instance, aEncoding ) );
+ aPrinterName = aBuf.makeStringAndClear();
+ }
+
+ // initialize printer with possible configuration from psprint.conf
+ bool bSetToGlobalDefaults = m_aPrinters.find( aPrinterName ) == m_aPrinters.end();
+ Printer aPrinter = m_aPrinters[ aPrinterName ];
+ if( bSetToGlobalDefaults )
+ aPrinter.m_aInfo = m_aGlobalDefaults;
+ aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
+ if( pDest->is_default )
+ m_aDefaultPrinter = aPrinterName;
+
+ for( int k = 0; k < pDest->num_options; k++ )
+ {
+ if(!strcmp(pDest->options[k].name, "printer-info"))
+ aPrinter.m_aInfo.m_aComment=OStringToOUString(pDest->options[k].value, aEncoding);
+ if(!strcmp(pDest->options[k].name, "printer-location"))
+ aPrinter.m_aInfo.m_aLocation=OStringToOUString(pDest->options[k].value, aEncoding);
+ }
+
+
+ OUStringBuffer aBuf( 256 );
+ aBuf.appendAscii( "CUPS:" );
+ aBuf.append( aPrinterName );
+ // note: the parser that goes with the PrinterInfo
+ // is created implicitly by the JobData::operator=()
+ // when it detects the NULL ptr m_pParser.
+ // if we wanted to fill in the parser here this
+ // would mean we'd have to download PPDs for each and
+ // every printer - which would be really bad runtime
+ // behaviour
+ aPrinter.m_aInfo.m_pParser = NULL;
+ aPrinter.m_aInfo.m_aContext.setParser( NULL );
+ boost::unordered_map< OUString, PPDContext, OUStringHash >::const_iterator c_it = m_aDefaultContexts.find( aPrinterName );
+ if( c_it != m_aDefaultContexts.end() )
+ {
+ aPrinter.m_aInfo.m_pParser = c_it->second.getParser();
+ aPrinter.m_aInfo.m_aContext = c_it->second;
+ }
+ if( bUsePDF && aPrinter.m_aInfo.m_nPSLevel == 0 && aPrinter.m_aInfo.m_nPDFDevice == 0 )
+ aPrinter.m_aInfo.m_nPDFDevice = 1;
+ aPrinter.m_aInfo.m_aDriverName = aBuf.makeStringAndClear();
+ aPrinter.m_bModified = false;
+
+ m_aPrinters[ aPrinter.m_aInfo.m_aPrinterName ] = aPrinter;
+ m_aCUPSDestMap[ aPrinter.m_aInfo.m_aPrinterName ] = nPrinter;
+ }
+
+ // remove everything that is not a CUPS printer and not
+ // a special purpose printer (PDF, Fax)
+ std::list< OUString > aRemovePrinters;
+ for( boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.begin();
+ it != m_aPrinters.end(); ++it )
+ {
+ if( m_aCUPSDestMap.find( it->first ) != m_aCUPSDestMap.end() )
+ continue;
+
+ if( it->second.m_aInfo.m_aFeatures.getLength() > 0 )
+ continue;
+ aRemovePrinters.push_back( it->first );
+ }
+ while( aRemovePrinters.begin() != aRemovePrinters.end() )
+ {
+ m_aPrinters.erase( aRemovePrinters.front() );
+ aRemovePrinters.pop_front();
+ }
+
+ m_pCUPSWrapper->cupsSetPasswordCB( setPasswordCallback );
+#endif // ENABLE_CUPS
+}
+
+#ifdef ENABLE_CUPS
+static void updatePrinterContextInfo( ppd_group_t* pPPDGroup, PPDContext& rContext )
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ for( int i = 0; i < pPPDGroup->num_options; i++ )
+ {
+ ppd_option_t* pOption = pPPDGroup->options + i;
+ for( int n = 0; n < pOption->num_choices; n++ )
+ {
+ ppd_choice_t* pChoice = pOption->choices + n;
+ if( pChoice->marked )
+ {
+ const PPDKey* pKey = rContext.getParser()->getKey( OStringToOUString( pOption->keyword, aEncoding ) );
+ if( pKey )
+ {
+ const PPDValue* pValue = pKey->getValue( OStringToOUString( pChoice->choice, aEncoding ) );
+ if( pValue )
+ {
+ if( pValue != pKey->getDefaultValue() )
+ {
+ rContext.setValue( pKey, pValue, true );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "key %s is set to %s\n", pOption->keyword, pChoice->choice );
+#endif
+
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "key %s is defaulted to %s\n", pOption->keyword, pChoice->choice );
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "caution: value %s not found in key %s\n", pChoice->choice, pOption->keyword );
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "caution: key %s not found in parser\n", pOption->keyword );
+#endif
+ }
+ }
+ }
+
+ // recurse through subgroups
+ for( int g = 0; g < pPPDGroup->num_subgroups; g++ )
+ {
+ updatePrinterContextInfo( pPPDGroup->subgroups + g, rContext );
+ }
+}
+#endif // ENABLE_CUPS
+
+const PPDParser* CUPSManager::createCUPSParser( const OUString& rPrinter )
+{
+ const PPDParser* pNewParser = NULL;
+ OUString aPrinter;
+
+ if( rPrinter.compareToAscii( "CUPS:", 5 ) == 0 )
+ aPrinter = rPrinter.copy( 5 );
+ else
+ aPrinter = rPrinter;
+
+#ifdef ENABLE_CUPS
+ if( m_aCUPSMutex.tryToAcquire() )
+ {
+ if( m_nDests && m_pDests && ! isCUPSDisabled() )
+ {
+ boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it =
+ m_aCUPSDestMap.find( aPrinter );
+ if( dest_it != m_aCUPSDestMap.end() )
+ {
+ cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
+ OString aPPDFile = m_pCUPSWrapper->cupsGetPPD( pDest->name );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PPD for %s is %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr(), aPPDFile.getStr() );
+ #endif
+ if( aPPDFile.getLength() )
+ {
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ OUString aFileName( OStringToOUString( aPPDFile, aEncoding ) );
+ // update the printer info with context information
+ ppd_file_t* pPPD = m_pCUPSWrapper->ppdOpenFile( aPPDFile.getStr() );
+ if( pPPD )
+ {
+ // create the new parser
+ PPDParser* pCUPSParser = new PPDParser( aFileName );
+ pCUPSParser->m_aFile = rPrinter;
+ pNewParser = pCUPSParser;
+
+ /*int nConflicts =*/ m_pCUPSWrapper->cupsMarkOptions( pPPD, pDest->num_options, pDest->options );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "processing the following options for printer %s (instance %s):\n",
+ pDest->name, pDest->instance );
+ for( int k = 0; k < pDest->num_options; k++ )
+ fprintf( stderr, " \"%s\" = \"%s\"\n",
+ pDest->options[k].name,
+ pDest->options[k].value );
+ #endif
+ PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo;
+
+ // remember the default context for later use
+ PPDContext& rContext = m_aDefaultContexts[ aPrinter ];
+ rContext.setParser( pNewParser );
+ // set system default paper; printer CUPS PPD options
+ // may overwrite it
+ setDefaultPaper( rContext );
+ for( int i = 0; i < pPPD->num_groups; i++ )
+ updatePrinterContextInfo( pPPD->groups + i, rContext );
+
+ rInfo.m_pParser = pNewParser;
+ rInfo.m_aContext = rContext;
+
+ // clean up the mess
+ m_pCUPSWrapper->ppdClose( pPPD );
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "ppdOpenFile failed, falling back to generic driver\n" );
+ #endif
+
+ // remove temporary PPD file
+ unlink( aPPDFile.getStr() );
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "cupsGetPPD failed, falling back to generic driver\n" );
+ #endif
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "no dest found for printer %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr() );
+ #endif
+ }
+ m_aCUPSMutex.release();
+ }
+ #if OSL_DEBUG_LEVEL >1
+ else
+ fprintf( stderr, "could not acquire CUPS mutex !!!\n" );
+ #endif
+ #endif // ENABLE_CUPS
+
+ if( ! pNewParser )
+ {
+ // get the default PPD
+ pNewParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) );
+
+ PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo;
+
+ rInfo.m_pParser = pNewParser;
+ rInfo.m_aContext.setParser( pNewParser );
+ }
+
+ return pNewParser;
+}
+
+void CUPSManager::setupJobContextData(
+ JobData&
+#ifdef ENABLE_CUPS
+ rData
+#endif
+)
+{
+#ifdef ENABLE_CUPS
+ boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it =
+ m_aCUPSDestMap.find( rData.m_aPrinterName );
+
+ if( dest_it == m_aCUPSDestMap.end() )
+ return PrinterInfoManager::setupJobContextData( rData );
+
+ boost::unordered_map< OUString, Printer, OUStringHash >::iterator p_it =
+ m_aPrinters.find( rData.m_aPrinterName );
+ if( p_it == m_aPrinters.end() ) // huh ?
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "CUPS printer list in disorder, no dest for printer %s !\n", OUStringToOString( rData.m_aPrinterName, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ return;
+ }
+
+ if( p_it->second.m_aInfo.m_pParser == NULL )
+ {
+ // in turn calls createCUPSParser
+ // which updates the printer info
+ p_it->second.m_aInfo.m_pParser = PPDParser::getParser( p_it->second.m_aInfo.m_aDriverName );
+ }
+ if( p_it->second.m_aInfo.m_aContext.getParser() == NULL )
+ {
+ OUString aPrinter;
+ if( p_it->second.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) == 0 )
+ aPrinter = p_it->second.m_aInfo.m_aDriverName.copy( 5 );
+ else
+ aPrinter = p_it->second.m_aInfo.m_aDriverName;
+
+ p_it->second.m_aInfo.m_aContext = m_aDefaultContexts[ aPrinter ];
+ }
+
+ rData.m_pParser = p_it->second.m_aInfo.m_pParser;
+ rData.m_aContext = p_it->second.m_aInfo.m_aContext;
+#endif
+}
+
+FILE* CUPSManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
+{
+ OSL_TRACE( "endSpool: %s, %s",
+ rtl::OUStringToOString( rPrintername, RTL_TEXTENCODING_UTF8 ).getStr(),
+ bQuickCommand ? "true" : "false" );
+
+ if( m_aCUPSDestMap.find( rPrintername ) == m_aCUPSDestMap.end() )
+ {
+ OSL_TRACE( "defer to PrinterInfoManager::startSpool" );
+ return PrinterInfoManager::startSpool( rPrintername, bQuickCommand );
+ }
+
+#ifdef ENABLE_CUPS
+ OUString aTmpURL, aTmpFile;
+ osl_createTempFile( NULL, NULL, &aTmpURL.pData );
+ osl_getSystemPathFromFileURL( aTmpURL.pData, &aTmpFile.pData );
+ OString aSysFile = OUStringToOString( aTmpFile, osl_getThreadTextEncoding() );
+ FILE* fp = fopen( aSysFile.getStr(), "w" );
+ if( fp )
+ m_aSpoolFiles[fp] = aSysFile;
+
+ return fp;
+#else
+ return NULL;
+#endif
+}
+
+struct less_ppd_key : public ::std::binary_function<double, double, bool>
+{
+ bool operator()(const PPDKey* left, const PPDKey* right)
+ { return left->getOrderDependency() < right->getOrderDependency(); }
+};
+
+void CUPSManager::getOptionsFromDocumentSetup( const JobData& rJob, bool bBanner, int& rNumOptions, void** rOptions ) const
+{
+ rNumOptions = 0;
+ *rOptions = NULL;
+
+ // emit features ordered to OrderDependency
+ // ignore features that are set to default
+
+ // sanity check
+ if( rJob.m_pParser == rJob.m_aContext.getParser() && rJob.m_pParser )
+ {
+ int i;
+ int nKeys = rJob.m_aContext.countValuesModified();
+ ::std::vector< const PPDKey* > aKeys( nKeys );
+ for( i = 0; i < nKeys; i++ )
+ aKeys[i] = rJob.m_aContext.getModifiedKey( i );
+ ::std::sort( aKeys.begin(), aKeys.end(), less_ppd_key() );
+
+ for( i = 0; i < nKeys; i++ )
+ {
+ const PPDKey* pKey = aKeys[i];
+ const PPDValue* pValue = rJob.m_aContext.getValue( pKey );
+ if(pValue && pValue->m_eType == eInvocation && pValue->m_aValue.Len() )
+ {
+ OString aKey = OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US );
+ OString aValue = OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US );
+ rNumOptions = m_pCUPSWrapper->cupsAddOption( aKey.getStr(), aValue.getStr(), rNumOptions, (cups_option_t**)rOptions );
+ }
+ }
+ }
+
+ if( rJob.m_nPDFDevice > 0 && rJob.m_nCopies > 1 )
+ {
+ rtl::OString aVal( rtl::OString::valueOf( sal_Int32( rJob.m_nCopies ) ) );
+ rNumOptions = m_pCUPSWrapper->cupsAddOption( "copies", aVal.getStr(), rNumOptions, (cups_option_t**)rOptions );
+ }
+ if( ! bBanner )
+ {
+ rNumOptions = m_pCUPSWrapper->cupsAddOption( "job-sheets", "none", rNumOptions, (cups_option_t**)rOptions );
+ }
+}
+
+int CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData, bool bBanner )
+{
+ OSL_TRACE( "endSpool: %s, %s, copy count = %d",
+ rtl::OUStringToOString( rPrintername, RTL_TEXTENCODING_UTF8 ).getStr(),
+ rtl::OUStringToOString( rJobTitle, RTL_TEXTENCODING_UTF8 ).getStr(),
+ rDocumentJobData.m_nCopies
+ );
+
+ int nJobID = 0;
+
+ osl::MutexGuard aGuard( m_aCUPSMutex );
+
+ boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it =
+ m_aCUPSDestMap.find( rPrintername );
+ if( dest_it == m_aCUPSDestMap.end() )
+ {
+ OSL_TRACE( "defer to PrinterInfoManager::endSpool" );
+ return PrinterInfoManager::endSpool( rPrintername, rJobTitle, pFile, rDocumentJobData, bBanner );
+ }
+
+ #ifdef ENABLE_CUPS
+ boost::unordered_map< FILE*, OString, FPtrHash >::const_iterator it = m_aSpoolFiles.find( pFile );
+ if( it != m_aSpoolFiles.end() )
+ {
+ fclose( pFile );
+ rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
+
+ // setup cups options
+ int nNumOptions = 0;
+ cups_option_t* pOptions = NULL;
+ getOptionsFromDocumentSetup( rDocumentJobData, bBanner, nNumOptions, (void**)&pOptions );
+
+ cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
+ nJobID = m_pCUPSWrapper->cupsPrintFile( pDest->name,
+ it->second.getStr(),
+ OUStringToOString( rJobTitle, aEnc ).getStr(),
+ nNumOptions, pOptions );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "cupsPrintFile( %s, %s, %s, %d, %p ) returns %d\n",
+ pDest->name,
+ it->second.getStr(),
+ OUStringToOString( rJobTitle, aEnc ).getStr(),
+ nNumOptions,
+ pOptions,
+ nJobID
+ );
+ for( int n = 0; n < nNumOptions; n++ )
+ fprintf( stderr, " option %s=%s\n", pOptions[n].name, pOptions[n].value );
+ OString aCmd( "cp " );
+ aCmd = aCmd + it->second;
+ aCmd = aCmd + OString( " $HOME/cupsprint.ps" );
+ system( aCmd.getStr() );
+#endif
+
+ unlink( it->second.getStr() );
+ m_aSpoolFiles.erase( pFile );
+ if( pOptions )
+ m_pCUPSWrapper->cupsFreeOptions( nNumOptions, pOptions );
+ }
+#endif // ENABLE_CUPS
+
+ return nJobID;
+}
+
+
+void CUPSManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo )
+{
+ PrinterInfoManager::changePrinterInfo( rPrinter, rNewInfo );
+}
+
+bool CUPSManager::checkPrintersChanged( bool bWait )
+{
+ bool bChanged = false;
+ if( bWait )
+ {
+ if( m_aDestThread )
+ {
+ // initial asynchronous detection still running
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "syncing cups discovery thread\n" );
+ #endif
+ osl_joinWithThread( m_aDestThread );
+ osl_destroyThread( m_aDestThread );
+ m_aDestThread = NULL;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "done: syncing cups discovery thread\n" );
+ #endif
+ }
+ else
+ {
+ // #i82321# check for cups printer updates
+ // with this change the whole asynchronous detection in a thread is
+ // almost useless. The only relevance left is for some stalled systems
+ // where the user can set SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION
+ // (see vcl/unx/source/gdi/salprnpsp.cxx)
+ // so that checkPrintersChanged( true ) will never be called
+
+ // there is no way to query CUPS whether the printer list has changed
+ // so get the dest list anew
+ if( m_nDests && m_pDests )
+ m_pCUPSWrapper->cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests );
+ m_nDests = 0;
+ m_pDests = NULL;
+ runDests();
+ }
+ }
+ if( m_aCUPSMutex.tryToAcquire() )
+ {
+ bChanged = m_bNewDests;
+ m_aCUPSMutex.release();
+ }
+
+ if( ! bChanged )
+ {
+ bChanged = PrinterInfoManager::checkPrintersChanged( bWait );
+ // #i54375# ensure new merging with CUPS list in :initialize
+ if( bChanged )
+ m_bNewDests = true;
+ }
+
+ if( bChanged )
+ initialize();
+
+ return bChanged;
+}
+
+bool CUPSManager::addPrinter( const OUString& rName, const OUString& rDriver )
+{
+ // don't touch the CUPS printers
+ if( m_aCUPSDestMap.find( rName ) != m_aCUPSDestMap.end() ||
+ rDriver.compareToAscii( "CUPS:", 5 ) == 0
+ )
+ return false;
+ return PrinterInfoManager::addPrinter( rName, rDriver );
+}
+
+bool CUPSManager::removePrinter( const OUString& rName, bool bCheck )
+{
+ // don't touch the CUPS printers
+ if( m_aCUPSDestMap.find( rName ) != m_aCUPSDestMap.end() )
+ return false;
+ return PrinterInfoManager::removePrinter( rName, bCheck );
+}
+
+bool CUPSManager::setDefaultPrinter( const OUString& rName )
+{
+ bool bSuccess = false;
+#ifdef ENABLE_CUPS
+ boost::unordered_map< OUString, int, OUStringHash >::iterator nit =
+ m_aCUPSDestMap.find( rName );
+ if( nit != m_aCUPSDestMap.end() && m_aCUPSMutex.tryToAcquire() )
+ {
+ cups_dest_t* pDests = (cups_dest_t*)m_pDests;
+ for( int i = 0; i < m_nDests; i++ )
+ pDests[i].is_default = 0;
+ pDests[ nit->second ].is_default = 1;
+ m_pCUPSWrapper->cupsSetDests( m_nDests, (cups_dest_t*)m_pDests );
+ m_aDefaultPrinter = rName;
+ m_aCUPSMutex.release();
+ bSuccess = true;
+ }
+ else
+#endif
+ bSuccess = PrinterInfoManager::setDefaultPrinter( rName );
+
+ return bSuccess;
+}
+
+bool CUPSManager::writePrinterConfig()
+{
+#ifdef ENABLE_CUPS
+ bool bDestModified = false;
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+
+ for( boost::unordered_map< OUString, Printer, OUStringHash >::iterator prt =
+ m_aPrinters.begin(); prt != m_aPrinters.end(); ++prt )
+ {
+ boost::unordered_map< OUString, int, OUStringHash >::iterator nit =
+ m_aCUPSDestMap.find( prt->first );
+ if( nit == m_aCUPSDestMap.end() )
+ continue;
+
+ if( ! prt->second.m_bModified )
+ continue;
+
+ if( m_aCUPSMutex.tryToAcquire() )
+ {
+ bDestModified = true;
+ cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + nit->second;
+ PrinterInfo& rInfo = prt->second.m_aInfo;
+
+ // create new option list
+ int nNewOptions = 0;
+ cups_option_t* pNewOptions = NULL;
+ int nValues = rInfo.m_aContext.countValuesModified();
+ for( int i = 0; i < nValues; i++ )
+ {
+ const PPDKey* pKey = rInfo.m_aContext.getModifiedKey( i );
+ const PPDValue* pValue = rInfo.m_aContext.getValue( pKey );
+ if( pKey && pValue ) // sanity check
+ {
+ OString aName = OUStringToOString( pKey->getKey(), aEncoding );
+ OString aValue = OUStringToOString( pValue->m_aOption, aEncoding );
+ nNewOptions = m_pCUPSWrapper->cupsAddOption( aName.getStr(), aValue.getStr(), nNewOptions, &pNewOptions );
+ }
+ }
+ // set PPD options on CUPS dest
+ m_pCUPSWrapper->cupsFreeOptions( pDest->num_options, pDest->options );
+ pDest->num_options = nNewOptions;
+ pDest->options = pNewOptions;
+ m_aCUPSMutex.release();
+ }
+ }
+ if( bDestModified && m_aCUPSMutex.tryToAcquire() )
+ {
+ m_pCUPSWrapper->cupsSetDests( m_nDests, (cups_dest_t*)m_pDests );
+ m_aCUPSMutex.release();
+ }
+#endif // ENABLE_CUPS
+
+ return PrinterInfoManager::writePrinterConfig();
+}
+
+bool CUPSManager::addOrRemovePossible() const
+{
+ return (m_nDests && m_pDests && ! isCUPSDisabled())? false : PrinterInfoManager::addOrRemovePossible();
+}
+
+const char* CUPSManager::authenticateUser( const char* /*pIn*/ )
+{
+ const char* pRet = NULL;
+
+#ifdef ENABLE_CUPS
+ OUString aLib(RTL_CONSTASCII_USTRINGPARAM( _XSALSET_LIBNAME ));
+ oslModule pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ if( pLib )
+ {
+ OUString aSym( RTL_CONSTASCII_USTRINGPARAM( "Sal_authenticateQuery" ) );
+ bool (*getpw)( const OString& rServer, OString& rUser, OString& rPw) =
+ (bool(*)(const OString&,OString&,OString&))osl_getFunctionSymbol( pLib, aSym.pData );
+ if( getpw )
+ {
+ osl::MutexGuard aGuard( m_aCUPSMutex );
+
+ OString aUser = m_pCUPSWrapper->cupsUser();
+ OString aServer = m_pCUPSWrapper->cupsServer();
+ OString aPassword;
+ if( getpw( aServer, aUser, aPassword ) )
+ {
+ m_aPassword = aPassword;
+ m_aUser = aUser;
+ m_pCUPSWrapper->cupsSetUser( m_aUser.getStr() );
+ pRet = m_aPassword.getStr();
+ }
+ }
+ osl_unloadModule( pLib );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else fprintf( stderr, "loading of module %s failed\n", OUStringToOString( aLib, osl_getThreadTextEncoding() ).getStr() );
+#endif
+#endif // ENABLE_CUPS
+
+ return pRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/printer/jobdata.cxx b/vcl/unx/generic/printer/jobdata.cxx
new file mode 100644
index 000000000000..0982b219bade
--- /dev/null
+++ b/vcl/unx/generic/printer/jobdata.cxx
@@ -0,0 +1,267 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 "vcl/jobdata.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include "tools/stream.hxx"
+
+#include "sal/alloca.h"
+
+using namespace psp;
+
+JobData& JobData::operator=(const JobData& rRight)
+{
+ m_nCopies = rRight.m_nCopies;
+ m_nLeftMarginAdjust = rRight.m_nLeftMarginAdjust;
+ m_nRightMarginAdjust = rRight.m_nRightMarginAdjust;
+ m_nTopMarginAdjust = rRight.m_nTopMarginAdjust;
+ m_nBottomMarginAdjust = rRight.m_nBottomMarginAdjust;
+ m_nColorDepth = rRight.m_nColorDepth;
+ m_eOrientation = rRight.m_eOrientation;
+ m_aPrinterName = rRight.m_aPrinterName;
+ m_pParser = rRight.m_pParser;
+ m_aContext = rRight.m_aContext;
+ m_nPSLevel = rRight.m_nPSLevel;
+ m_nPDFDevice = rRight.m_nPDFDevice;
+ m_nColorDevice = rRight.m_nColorDevice;
+
+ if( ! m_pParser && m_aPrinterName.getLength() )
+ {
+ PrinterInfoManager& rMgr = PrinterInfoManager::get();
+ rMgr.setupJobContextData( *this );
+ }
+ return *this;
+}
+
+void JobData::setCollate( bool bCollate )
+{
+ const PPDParser* pParser = m_aContext.getParser();
+ if( pParser )
+ {
+ const PPDKey* pKey = pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) );
+ if( pKey )
+ {
+ const PPDValue* pVal = NULL;
+ if( bCollate )
+ pVal = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) );
+ else
+ {
+ pVal = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "False" ) ) );
+ if( ! pVal )
+ pVal = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
+ }
+ m_aContext.setValue( pKey, pVal );
+ }
+ }
+}
+
+bool JobData::setPaper( int i_nWidth, int i_nHeight )
+{
+ bool bSuccess = false;
+ if( m_pParser )
+ {
+ rtl::OUString aPaper( m_pParser->matchPaper( i_nWidth, i_nHeight ) );
+
+ const PPDKey* pKey = m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ const PPDValue* pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : NULL;
+
+ bSuccess = pKey && pValue && m_aContext.setValue( pKey, pValue, false );
+ }
+ return bSuccess;
+}
+
+bool JobData::setPaperBin( int i_nPaperBin )
+{
+ bool bSuccess = false;
+ if( m_pParser )
+ {
+ const PPDKey* pKey = m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
+ const PPDValue* pValue = pKey ? pKey->getValue( i_nPaperBin ) : NULL;
+
+ bSuccess = pKey && pValue && m_aContext.setValue( pKey, pValue, false );
+ }
+ return bSuccess;
+}
+
+bool JobData::getStreamBuffer( void*& pData, int& bytes )
+{
+ // consistency checks
+ if( ! m_pParser )
+ m_pParser = m_aContext.getParser();
+ if( m_pParser != m_aContext.getParser() ||
+ ! m_pParser )
+ return false;
+
+ SvMemoryStream aStream;
+ ByteString aLine;
+
+ // write header job data
+ aStream.WriteLine( "JobData 1" );
+
+ aLine = "printer=";
+ aLine += ByteString( String( m_aPrinterName ), RTL_TEXTENCODING_UTF8 );
+ aStream.WriteLine( aLine );
+
+ aLine = "orientation=";
+ aLine += m_eOrientation == orientation::Landscape ? "Landscape" : "Portrait";
+ aStream.WriteLine( aLine );
+
+ aLine = "copies=";
+ aLine += ByteString::CreateFromInt32( m_nCopies );
+ aStream.WriteLine( aLine );
+
+ aLine = "margindajustment=";
+ aLine += ByteString::CreateFromInt32( m_nLeftMarginAdjust );
+ aLine += ',';
+ aLine += ByteString::CreateFromInt32( m_nRightMarginAdjust );
+ aLine += ',';
+ aLine += ByteString::CreateFromInt32( m_nTopMarginAdjust );
+ aLine += ',';
+ aLine += ByteString::CreateFromInt32( m_nBottomMarginAdjust );
+ aStream.WriteLine( aLine );
+
+ aLine = "colordepth=";
+ aLine += ByteString::CreateFromInt32( m_nColorDepth );
+ aStream.WriteLine( aLine );
+
+ aLine = "pslevel=";
+ aLine += ByteString::CreateFromInt32( m_nPSLevel );
+ aStream.WriteLine( aLine );
+
+ aLine = "pdfdevice=";
+ aLine += ByteString::CreateFromInt32( m_nPDFDevice );
+ aStream.WriteLine( aLine );
+
+ aLine = "colordevice=";
+ aLine += ByteString::CreateFromInt32( m_nColorDevice );
+ aStream.WriteLine( aLine );
+
+ // now append the PPDContext stream buffer
+ aStream.WriteLine( "PPDContexData" );
+ sal_uLong nBytes;
+ void* pContextBuffer = m_aContext.getStreamableBuffer( nBytes );
+ if( nBytes )
+ aStream.Write( pContextBuffer, nBytes );
+
+ // success
+ pData = rtl_allocateMemory( bytes = aStream.Tell() );
+ memcpy( pData, aStream.GetData(), bytes );
+ return true;
+}
+
+bool JobData::constructFromStreamBuffer( void* pData, int bytes, JobData& rJobData )
+{
+ SvMemoryStream aStream( pData, bytes, STREAM_READ );
+ ByteString aLine;
+ bool bVersion = false;
+ bool bPrinter = false;
+ bool bOrientation = false;
+ bool bCopies = false;
+ bool bContext = false;
+ bool bMargin = false;
+ bool bColorDepth = false;
+ bool bColorDevice = false;
+ bool bPSLevel = false;
+ bool bPDFDevice = false;
+ while( ! aStream.IsEof() )
+ {
+ aStream.ReadLine( aLine );
+ if( aLine.CompareTo( "JobData", 7 ) == COMPARE_EQUAL )
+ bVersion = true;
+ else if( aLine.CompareTo( "printer=", 8 ) == COMPARE_EQUAL )
+ {
+ bPrinter = true;
+ rJobData.m_aPrinterName = String( aLine.Copy( 8 ), RTL_TEXTENCODING_UTF8 );
+ }
+ else if( aLine.CompareTo( "orientation=", 12 ) == COMPARE_EQUAL )
+ {
+ bOrientation = true;
+ rJobData.m_eOrientation = aLine.Copy( 12 ).EqualsIgnoreCaseAscii( "landscape" ) ? orientation::Landscape : orientation::Portrait;
+ }
+ else if( aLine.CompareTo( "copies=", 7 ) == COMPARE_EQUAL )
+ {
+ bCopies = true;
+ rJobData.m_nCopies = aLine.Copy( 7 ).ToInt32();
+ }
+ else if( aLine.CompareTo( "margindajustment=",17 ) == COMPARE_EQUAL )
+ {
+ bMargin = true;
+ ByteString aValues( aLine.Copy( 17 ) );
+ rJobData.m_nLeftMarginAdjust = aValues.GetToken( 0, ',' ).ToInt32();
+ rJobData.m_nRightMarginAdjust = aValues.GetToken( 1, ',' ).ToInt32();
+ rJobData.m_nTopMarginAdjust = aValues.GetToken( 2, ',' ).ToInt32();
+ rJobData.m_nBottomMarginAdjust = aValues.GetToken( 3, ',' ).ToInt32();
+ }
+ else if( aLine.CompareTo( "colordepth=", 11 ) == COMPARE_EQUAL )
+ {
+ bColorDepth = true;
+ rJobData.m_nColorDepth = aLine.Copy( 11 ).ToInt32();
+ }
+ else if( aLine.CompareTo( "colordevice=", 12 ) == COMPARE_EQUAL )
+ {
+ bColorDevice = true;
+ rJobData.m_nColorDevice = aLine.Copy( 12 ).ToInt32();
+ }
+ else if( aLine.CompareTo( "pslevel=", 8 ) == COMPARE_EQUAL )
+ {
+ bPSLevel = true;
+ rJobData.m_nPSLevel = aLine.Copy( 8 ).ToInt32();
+ }
+ else if( aLine.CompareTo( "pdfdevice=", 10 ) == COMPARE_EQUAL )
+ {
+ bPDFDevice = true;
+ rJobData.m_nPDFDevice = aLine.Copy( 10 ).ToInt32();
+ }
+ else if( aLine.Equals( "PPDContexData" ) )
+ {
+ if( bPrinter )
+ {
+ PrinterInfoManager& rManager = PrinterInfoManager::get();
+ const PrinterInfo& rInfo = rManager.getPrinterInfo( rJobData.m_aPrinterName );
+ rJobData.m_pParser = PPDParser::getParser( rInfo.m_aDriverName );
+ if( rJobData.m_pParser )
+ {
+ rJobData.m_aContext.setParser( rJobData.m_pParser );
+ int nBytes = bytes - aStream.Tell();
+ void* pRemain = alloca( bytes - aStream.Tell() );
+ aStream.Read( pRemain, nBytes );
+ rJobData.m_aContext.rebuildFromStreamBuffer( pRemain, nBytes );
+ bContext = true;
+ }
+ }
+ }
+ }
+
+ return bVersion && bPrinter && bOrientation && bCopies && bContext && bMargin && bPSLevel && bPDFDevice && bColorDevice && bColorDepth;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/printer/ppdparser.cxx b/vcl/unx/generic/printer/ppdparser.cxx
new file mode 100644
index 000000000000..30d4598568d2
--- /dev/null
+++ b/vcl/unx/generic/printer/ppdparser.cxx
@@ -0,0 +1,2187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+
+#include <boost/unordered_map.hpp>
+
+#include "vcl/ppdparser.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/helper.hxx"
+#include "vcl/svapp.hxx"
+#include "cupsmgr.hxx"
+#include "tools/debug.hxx"
+#include "tools/urlobj.hxx"
+#include "tools/stream.hxx"
+#include "tools/zcodec.hxx"
+#include "osl/mutex.hxx"
+#include "osl/file.hxx"
+#include "osl/process.h"
+#include "osl/thread.h"
+#include "rtl/strbuf.hxx"
+#include "rtl/ustrbuf.hxx"
+#include "rtl/instance.hxx"
+#include <sal/macros.h>
+
+#include "com/sun/star/lang/Locale.hpp"
+
+namespace psp
+{
+ class PPDTranslator
+ {
+ struct LocaleEqual
+ {
+ bool operator()(const com::sun::star::lang::Locale& i_rLeft,
+ const com::sun::star::lang::Locale& i_rRight) const
+ {
+ return i_rLeft.Language.equals( i_rRight.Language ) &&
+ i_rLeft.Country.equals( i_rRight.Country ) &&
+ i_rLeft.Variant.equals( i_rRight.Variant );
+ }
+ };
+
+ struct LocaleHash
+ {
+ size_t operator()(const com::sun::star::lang::Locale& rLocale) const
+ { return
+ (size_t)rLocale.Language.hashCode()
+ ^ (size_t)rLocale.Country.hashCode()
+ ^ (size_t)rLocale.Variant.hashCode()
+ ;
+ }
+ };
+
+ typedef boost::unordered_map< com::sun::star::lang::Locale, rtl::OUString, LocaleHash, LocaleEqual > translation_map;
+ typedef boost::unordered_map< rtl::OUString, translation_map, rtl::OUStringHash > key_translation_map;
+
+ key_translation_map m_aTranslations;
+ public:
+ PPDTranslator() {}
+ ~PPDTranslator() {}
+
+
+ void insertValue(
+ const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rValue,
+ const rtl::OUString& i_rTranslation,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale()
+ );
+
+ void insertOption( const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rTranslation,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() )
+ {
+ insertValue( i_rKey, i_rOption, rtl::OUString(), i_rTranslation, i_rLocale );
+ }
+
+ void insertKey( const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rTranslation,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() )
+ {
+ insertValue( i_rKey, rtl::OUString(), rtl::OUString(), i_rTranslation, i_rLocale );
+ }
+
+ rtl::OUString translateValue(
+ const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rValue,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale()
+ ) const;
+
+ rtl::OUString translateOption( const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) const
+ {
+ return translateValue( i_rKey, i_rOption, rtl::OUString(), i_rLocale );
+ }
+
+ rtl::OUString translateKey( const rtl::OUString& i_rKey,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) const
+ {
+ return translateValue( i_rKey, rtl::OUString(), rtl::OUString(), i_rLocale );
+ }
+ };
+
+ static com::sun::star::lang::Locale normalizeInputLocale(
+ const com::sun::star::lang::Locale& i_rLocale,
+ bool bInsertDefault = false
+ )
+ {
+ com::sun::star::lang::Locale aLoc( i_rLocale );
+ if( bInsertDefault && aLoc.Language.getLength() == 0 )
+ {
+ // empty locale requested, fill in application UI locale
+ aLoc = Application::GetSettings().GetUILocale();
+
+ #if OSL_DEBUG_LEVEL > 1
+ static const char* pEnvLocale = getenv( "SAL_PPDPARSER_LOCALE" );
+ if( pEnvLocale && *pEnvLocale )
+ {
+ rtl::OString aStr( pEnvLocale );
+ sal_Int32 nLen = aStr.getLength();
+ aLoc.Language = rtl::OStringToOUString( aStr.copy( 0, nLen > 2 ? 2 : nLen ), RTL_TEXTENCODING_MS_1252 );
+ if( nLen >=5 && aStr.getStr()[2] == '_' )
+ aLoc.Country = rtl::OStringToOUString( aStr.copy( 3, 2 ), RTL_TEXTENCODING_MS_1252 );
+ else
+ aLoc.Country = rtl::OUString();
+ aLoc.Variant = rtl::OUString();
+ }
+ #endif
+ }
+ aLoc.Language = aLoc.Language.toAsciiLowerCase();
+ aLoc.Country = aLoc.Country.toAsciiUpperCase();
+ aLoc.Variant = aLoc.Variant.toAsciiUpperCase();
+
+ return aLoc;
+ }
+
+ void PPDTranslator::insertValue(
+ const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rValue,
+ const rtl::OUString& i_rTranslation,
+ const com::sun::star::lang::Locale& i_rLocale
+ )
+ {
+ rtl::OUStringBuffer aKey( i_rKey.getLength() + i_rOption.getLength() + i_rValue.getLength() + 2 );
+ aKey.append( i_rKey );
+ if( i_rOption.getLength() || i_rValue.getLength() )
+ {
+ aKey.append( sal_Unicode( ':' ) );
+ aKey.append( i_rOption );
+ }
+ if( i_rValue.getLength() )
+ {
+ aKey.append( sal_Unicode( ':' ) );
+ aKey.append( i_rValue );
+ }
+ if( aKey.getLength() && i_rTranslation.getLength() )
+ {
+ rtl::OUString aK( aKey.makeStringAndClear() );
+ com::sun::star::lang::Locale aLoc;
+ aLoc.Language = i_rLocale.Language.toAsciiLowerCase();
+ aLoc.Country = i_rLocale.Country.toAsciiUpperCase();
+ aLoc.Variant = i_rLocale.Variant.toAsciiUpperCase();
+ m_aTranslations[ aK ][ aLoc ] = i_rTranslation;
+ }
+ }
+
+ rtl::OUString PPDTranslator::translateValue(
+ const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rValue,
+ const com::sun::star::lang::Locale& i_rLocale
+ ) const
+ {
+ rtl::OUString aResult;
+
+ rtl::OUStringBuffer aKey( i_rKey.getLength() + i_rOption.getLength() + i_rValue.getLength() + 2 );
+ aKey.append( i_rKey );
+ if( i_rOption.getLength() || i_rValue.getLength() )
+ {
+ aKey.append( sal_Unicode( ':' ) );
+ aKey.append( i_rOption );
+ }
+ if( i_rValue.getLength() )
+ {
+ aKey.append( sal_Unicode( ':' ) );
+ aKey.append( i_rValue );
+ }
+ if( aKey.getLength() )
+ {
+ rtl::OUString aK( aKey.makeStringAndClear() );
+ key_translation_map::const_iterator it = m_aTranslations.find( aK );
+ if( it != m_aTranslations.end() )
+ {
+ const translation_map& rMap( it->second );
+
+ com::sun::star::lang::Locale aLoc( normalizeInputLocale( i_rLocale, true ) );
+ for( int nTry = 0; nTry < 4; nTry++ )
+ {
+ translation_map::const_iterator tr = rMap.find( aLoc );
+ if( tr != rMap.end() )
+ {
+ aResult = tr->second;
+ break;
+ }
+ switch( nTry )
+ {
+ case 0: aLoc.Variant = rtl::OUString();break;
+ case 1: aLoc.Country = rtl::OUString();break;
+ case 2: aLoc.Language = rtl::OUString();break;
+ }
+ }
+ }
+ }
+ return aResult;
+ }
+
+ class PPDCache
+ {
+ public:
+ std::list< PPDParser* > aAllParsers;
+ boost::unordered_map< rtl::OUString, rtl::OUString, rtl::OUStringHash >* pAllPPDFiles;
+ PPDCache()
+ : pAllPPDFiles(NULL)
+ {}
+ ~PPDCache()
+ {
+ while( aAllParsers.begin() != aAllParsers.end() )
+ {
+ delete aAllParsers.front();
+ aAllParsers.pop_front();
+ }
+ delete pAllPPDFiles;
+ pAllPPDFiles = NULL;
+ }
+ };
+}
+
+using namespace psp;
+
+using ::rtl::OUString;
+using ::rtl::OStringBuffer;
+using ::rtl::OUStringHash;
+
+
+#undef DBG_ASSERT
+#if defined DBG_UTIL || (OSL_DEBUG_LEVEL > 1)
+#define BSTRING(x) ByteString( x, osl_getThreadTextEncoding() )
+#define DBG_ASSERT( x, y ) { if( ! (x) ) fprintf( stderr, (y) ); }
+#else
+#define DBG_ASSERT( x, y )
+#endif
+
+namespace
+{
+ struct thePPDCache : public rtl::Static<PPDCache, thePPDCache> {};
+}
+
+class PPDDecompressStream
+{
+ SvFileStream* mpFileStream;
+ SvMemoryStream* mpMemStream;
+ rtl::OUString maFileName;
+
+ // forbid copying
+ PPDDecompressStream( const PPDDecompressStream& );
+ PPDDecompressStream& operator=(const PPDDecompressStream& );
+
+ public:
+ PPDDecompressStream( const rtl::OUString& rFile );
+ ~PPDDecompressStream();
+
+ bool IsOpen() const;
+ bool IsEof() const;
+ void ReadLine( ByteString& o_rLine);
+ void Open( const rtl::OUString& i_rFile );
+ void Close();
+ const rtl::OUString& GetFileName() const { return maFileName; }
+};
+
+PPDDecompressStream::PPDDecompressStream( const rtl::OUString& i_rFile ) :
+ mpFileStream( NULL ),
+ mpMemStream( NULL )
+{
+ Open( i_rFile );
+}
+
+PPDDecompressStream::~PPDDecompressStream()
+{
+ Close();
+}
+
+void PPDDecompressStream::Open( const rtl::OUString& i_rFile )
+{
+ Close();
+
+ mpFileStream = new SvFileStream( i_rFile, STREAM_READ );
+ maFileName = mpFileStream->GetFileName();
+
+ if( ! mpFileStream->IsOpen() )
+ {
+ Close();
+ return;
+ }
+
+ ByteString aLine;
+ mpFileStream->ReadLine( aLine );
+ mpFileStream->Seek( 0 );
+
+ // check for compress'ed or gzip'ed file
+ sal_uLong nCompressMethod = 0;
+ if( aLine.Len() > 1 && static_cast<unsigned char>(aLine.GetChar( 0 )) == 0x1f )
+ {
+ if( static_cast<unsigned char>(aLine.GetChar( 1 )) == 0x8b ) // check for gzip
+ nCompressMethod = ZCODEC_DEFAULT | ZCODEC_GZ_LIB;
+ }
+
+ if( nCompressMethod != 0 )
+ {
+ // so let's try to decompress the stream
+ mpMemStream = new SvMemoryStream( 4096, 4096 );
+ ZCodec aCodec;
+ aCodec.BeginCompression( nCompressMethod );
+ long nComp = aCodec.Decompress( *mpFileStream, *mpMemStream );
+ aCodec.EndCompression();
+ if( nComp < 0 )
+ {
+ // decompression failed, must be an uncompressed stream after all
+ delete mpMemStream, mpMemStream = NULL;
+ mpFileStream->Seek( 0 );
+ }
+ else
+ {
+ // compression successfull, can get rid of file stream
+ delete mpFileStream, mpFileStream = NULL;
+ mpMemStream->Seek( 0 );
+ }
+ }
+}
+
+void PPDDecompressStream::Close()
+{
+ delete mpMemStream, mpMemStream = NULL;
+ delete mpFileStream, mpFileStream = NULL;
+}
+
+bool PPDDecompressStream::IsOpen() const
+{
+ return (mpMemStream || (mpFileStream && mpFileStream->IsOpen()));
+}
+
+bool PPDDecompressStream::IsEof() const
+{
+ return ( mpMemStream ? mpMemStream->IsEof() : ( mpFileStream ? mpFileStream->IsEof() : true ) );
+}
+
+void PPDDecompressStream::ReadLine( ByteString& o_rLine )
+{
+ if( mpMemStream )
+ mpMemStream->ReadLine( o_rLine );
+ else if( mpFileStream )
+ mpFileStream->ReadLine( o_rLine );
+}
+
+static osl::FileBase::RC resolveLink( const rtl::OUString& i_rURL, rtl::OUString& o_rResolvedURL, rtl::OUString& o_rBaseName, osl::FileStatus::Type& o_rType, int nLinkLevel = 10 )
+{
+ osl::DirectoryItem aLinkItem;
+ osl::FileBase::RC aRet = osl::FileBase::E_None;
+
+ if( ( aRet = osl::DirectoryItem::get( i_rURL, aLinkItem ) ) == osl::FileBase::E_None )
+ {
+ osl::FileStatus aStatus( FileStatusMask_FileName | FileStatusMask_Type | FileStatusMask_LinkTargetURL );
+ if( ( aRet = aLinkItem.getFileStatus( aStatus ) ) == osl::FileBase::E_None )
+ {
+ if( aStatus.getFileType() == osl::FileStatus::Link )
+ {
+ if( nLinkLevel > 0 )
+ aRet = resolveLink( aStatus.getLinkTargetURL(), o_rResolvedURL, o_rBaseName, o_rType, nLinkLevel-1 );
+ else
+ aRet = osl::FileBase::E_MULTIHOP;
+ }
+ else
+ {
+ o_rResolvedURL = i_rURL;
+ o_rBaseName = aStatus.getFileName();
+ o_rType = aStatus.getFileType();
+ }
+ }
+ }
+ return aRet;
+}
+
+void PPDParser::scanPPDDir( const String& rDir )
+{
+ static struct suffix_t
+ {
+ const sal_Char* pSuffix;
+ const sal_Int32 nSuffixLen;
+ } const pSuffixes[] =
+ { { ".PS", 3 }, { ".PPD", 4 }, { ".PS.GZ", 6 }, { ".PPD.GZ", 7 } };
+
+ const int nSuffixes = SAL_N_ELEMENTS(pSuffixes);
+
+ PPDCache &rPPDCache = thePPDCache::get();
+
+ osl::Directory aDir( rDir );
+ if ( aDir.open() == osl::FileBase::E_None )
+ {
+ osl::DirectoryItem aItem;
+
+ INetURLObject aPPDDir(rDir);
+ while( aDir.getNextItem( aItem ) == osl::FileBase::E_None )
+ {
+ osl::FileStatus aStatus( FileStatusMask_FileName );
+ if( aItem.getFileStatus( aStatus ) == osl::FileBase::E_None )
+ {
+ rtl::OUStringBuffer aURLBuf( rDir.Len() + 64 );
+ aURLBuf.append( rDir );
+ aURLBuf.append( sal_Unicode( '/' ) );
+ aURLBuf.append( aStatus.getFileName() );
+
+ rtl::OUString aFileURL, aFileName;
+ osl::FileStatus::Type eType = osl::FileStatus::Unknown;
+
+ if( resolveLink( aURLBuf.makeStringAndClear(), aFileURL, aFileName, eType ) == osl::FileBase::E_None )
+ {
+ if( eType == osl::FileStatus::Regular )
+ {
+ INetURLObject aPPDFile = aPPDDir;
+ aPPDFile.Append( aFileName );
+
+ // match extension
+ for( int nSuffix = 0; nSuffix < nSuffixes; nSuffix++ )
+ {
+ if( aFileName.getLength() > pSuffixes[nSuffix].nSuffixLen )
+ {
+ if( aFileName.endsWithIgnoreAsciiCaseAsciiL( pSuffixes[nSuffix].pSuffix, pSuffixes[nSuffix].nSuffixLen ) )
+ {
+ (*rPPDCache.pAllPPDFiles)[ aFileName.copy( 0, aFileName.getLength() - pSuffixes[nSuffix].nSuffixLen ) ] = aPPDFile.PathToFileName();
+ break;
+ }
+ }
+ }
+ }
+ else if( eType == osl::FileStatus::Directory )
+ {
+ scanPPDDir( aFileURL );
+ }
+ }
+ }
+ }
+ aDir.close();
+ }
+}
+
+void PPDParser::initPPDFiles()
+{
+ PPDCache &rPPDCache = thePPDCache::get();
+ if( rPPDCache.pAllPPDFiles )
+ return;
+
+ rPPDCache.pAllPPDFiles = new boost::unordered_map< OUString, OUString, OUStringHash >();
+
+ // check installation directories
+ std::list< OUString > aPathList;
+ psp::getPrinterPathList( aPathList, PRINTER_PPDDIR );
+ for( std::list< OUString >::const_iterator ppd_it = aPathList.begin(); ppd_it != aPathList.end(); ++ppd_it )
+ {
+ INetURLObject aPPDDir( *ppd_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ scanPPDDir( aPPDDir.GetMainURL( INetURLObject::NO_DECODE ) );
+ }
+ if( rPPDCache.pAllPPDFiles->find( OUString( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ) == rPPDCache.pAllPPDFiles->end() )
+ {
+ // last try: search in directory of executable (mainly for setup)
+ OUString aExe;
+ if( osl_getExecutableFile( &aExe.pData ) == osl_Process_E_None )
+ {
+ INetURLObject aDir( aExe );
+ aDir.removeSegment();
+#ifdef DEBUG
+ fprintf( stderr, "scanning last chance dir: %s\n", OUStringToOString( aDir.GetMainURL( INetURLObject::NO_DECODE ), osl_getThreadTextEncoding() ).getStr() );
+#endif
+ scanPPDDir( aDir.GetMainURL( INetURLObject::NO_DECODE ) );
+#ifdef DEBUG
+ fprintf( stderr, "SGENPRT %s\n", rPPDCache.pAllPPDFiles->find( OUString( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ) == rPPDCache.pAllPPDFiles->end() ? "not found" : "found" );
+#endif
+ }
+ }
+}
+
+void PPDParser::getKnownPPDDrivers( std::list< rtl::OUString >& o_rDrivers, bool bRefresh )
+{
+ PPDCache &rPPDCache = thePPDCache::get();
+
+ if( bRefresh )
+ {
+ delete rPPDCache.pAllPPDFiles;
+ rPPDCache.pAllPPDFiles = NULL;
+ }
+
+ initPPDFiles();
+ o_rDrivers.clear();
+
+ boost::unordered_map< OUString, OUString, OUStringHash >::const_iterator it;
+ for( it = rPPDCache.pAllPPDFiles->begin(); it != rPPDCache.pAllPPDFiles->end(); ++it )
+ o_rDrivers.push_back( it->first );
+}
+
+String PPDParser::getPPDFile( const String& rFile )
+{
+ INetURLObject aPPD( rFile, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ // someone might enter a full qualified name here
+ PPDDecompressStream aStream( aPPD.PathToFileName() );
+ if( ! aStream.IsOpen() )
+ {
+ boost::unordered_map< OUString, OUString, OUStringHash >::const_iterator it;
+ PPDCache &rPPDCache = thePPDCache::get();
+
+ bool bRetry = true;
+ do
+ {
+ initPPDFiles();
+ // some PPD files contain dots beside the extension, so try name first
+ // and cut of points after that
+ rtl::OUString aBase( rFile );
+ sal_Int32 nLastIndex = aBase.lastIndexOf( sal_Unicode( '/' ) );
+ if( nLastIndex >= 0 )
+ aBase = aBase.copy( nLastIndex+1 );
+ do
+ {
+ it = rPPDCache.pAllPPDFiles->find( aBase );
+ nLastIndex = aBase.lastIndexOf( sal_Unicode( '.' ) );
+ if( nLastIndex > 0 )
+ aBase = aBase.copy( 0, nLastIndex );
+ } while( it == rPPDCache.pAllPPDFiles->end() && nLastIndex > 0 );
+
+ if( it == rPPDCache.pAllPPDFiles->end() && bRetry )
+ {
+ // a new file ? rehash
+ delete rPPDCache.pAllPPDFiles; rPPDCache.pAllPPDFiles = NULL;
+ bRetry = false;
+ // note this is optimized for office start where
+ // no new files occur and initPPDFiles is called only once
+ }
+ } while( ! rPPDCache.pAllPPDFiles );
+
+ if( it != rPPDCache.pAllPPDFiles->end() )
+ aStream.Open( it->second );
+ }
+
+ String aRet;
+ if( aStream.IsOpen() )
+ {
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+ if( aLine.Search( "*PPD-Adobe" ) == 0 )
+ aRet = aStream.GetFileName();
+ else
+ {
+ // our *Include hack does usually not begin
+ // with *PPD-Adobe, so try some lines for *Include
+ int nLines = 10;
+ while( aLine.Search( "*Include" ) != 0 && --nLines )
+ aStream.ReadLine( aLine );
+ if( nLines )
+ aRet = aStream.GetFileName();
+ }
+ }
+
+ return aRet;
+}
+
+String PPDParser::getPPDPrinterName( const String& rFile )
+{
+ String aPath = getPPDFile( rFile );
+ String aName;
+
+ // read in the file
+ PPDDecompressStream aStream( aPath );
+ if( aStream.IsOpen() )
+ {
+ String aCurLine;
+ while( ! aStream.IsEof() && aStream.IsOpen() )
+ {
+ ByteString aByteLine;
+ aStream.ReadLine( aByteLine );
+ aCurLine = String( aByteLine, RTL_TEXTENCODING_MS_1252 );
+ if( aCurLine.CompareIgnoreCaseToAscii( "*include:", 9 ) == COMPARE_EQUAL )
+ {
+ aCurLine.Erase( 0, 9 );
+ aCurLine.EraseLeadingChars( ' ' );
+ aCurLine.EraseTrailingChars( ' ' );
+ aCurLine.EraseLeadingChars( '\t' );
+ aCurLine.EraseTrailingChars( '\t' );
+ aCurLine.EraseTrailingChars( '\r' );
+ aCurLine.EraseTrailingChars( '\n' );
+ aCurLine.EraseLeadingChars( '"' );
+ aCurLine.EraseTrailingChars( '"' );
+ aStream.Close();
+ aStream.Open( getPPDFile( aCurLine ) );
+ continue;
+ }
+ if( aCurLine.CompareToAscii( "*ModelName:", 11 ) == COMPARE_EQUAL )
+ {
+ aName = aCurLine.GetToken( 1, '"' );
+ break;
+ }
+ else if( aCurLine.CompareToAscii( "*NickName:", 10 ) == COMPARE_EQUAL )
+ aName = aCurLine.GetToken( 1, '"' );
+ }
+ }
+ return aName;
+}
+
+const PPDParser* PPDParser::getParser( const String& rFile )
+{
+ static ::osl::Mutex aMutex;
+ ::osl::Guard< ::osl::Mutex > aGuard( aMutex );
+
+ String aFile = rFile;
+ if( rFile.CompareToAscii( "CUPS:", 5 ) != COMPARE_EQUAL )
+ aFile = getPPDFile( rFile );
+ if( ! aFile.Len() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Could not get printer PPD file \"%s\" !\n", OUStringToOString( rFile, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ return NULL;
+ }
+
+ PPDCache &rPPDCache = thePPDCache::get();
+ for( ::std::list< PPDParser* >::const_iterator it = rPPDCache.aAllParsers.begin(); it != rPPDCache.aAllParsers.end(); ++it )
+ if( (*it)->m_aFile == aFile )
+ return *it;
+
+ PPDParser* pNewParser = NULL;
+ if( aFile.CompareToAscii( "CUPS:", 5 ) != COMPARE_EQUAL )
+ pNewParser = new PPDParser( aFile );
+ else
+ {
+ PrinterInfoManager& rMgr = PrinterInfoManager::get();
+ if( rMgr.getType() == PrinterInfoManager::CUPS )
+ {
+ pNewParser = const_cast<PPDParser*>(static_cast<CUPSManager&>(rMgr).createCUPSParser( aFile ));
+ }
+ }
+ if( pNewParser )
+ {
+ // this may actually be the SGENPRT parser,
+ // so ensure uniquness here
+ rPPDCache.aAllParsers.remove( pNewParser );
+ // insert new parser to list
+ rPPDCache.aAllParsers.push_front( pNewParser );
+ }
+ return pNewParser;
+}
+
+PPDParser::PPDParser( const String& rFile ) :
+ m_aFile( rFile ),
+ m_bType42Capable( false ),
+ m_aFileEncoding( RTL_TEXTENCODING_MS_1252 ),
+ m_pDefaultImageableArea( NULL ),
+ m_pImageableAreas( NULL ),
+ m_pDefaultPaperDimension( NULL ),
+ m_pPaperDimensions( NULL ),
+ m_pDefaultInputSlot( NULL ),
+ m_pInputSlots( NULL ),
+ m_pDefaultResolution( NULL ),
+ m_pResolutions( NULL ),
+ m_pDefaultDuplexType( NULL ),
+ m_pDuplexTypes( NULL ),
+ m_pFontList( NULL ),
+ m_pTranslator( new PPDTranslator() )
+{
+ // read in the file
+ std::list< ByteString > aLines;
+ PPDDecompressStream aStream( m_aFile );
+ bool bLanguageEncoding = false;
+ if( aStream.IsOpen() )
+ {
+ ByteString aCurLine;
+ while( ! aStream.IsEof() )
+ {
+ aStream.ReadLine( aCurLine );
+ if( aCurLine.GetChar( 0 ) == '*' )
+ {
+ if( aCurLine.CompareIgnoreCaseToAscii( "*include:", 9 ) == COMPARE_EQUAL )
+ {
+ aCurLine.Erase( 0, 9 );
+ aCurLine.EraseLeadingChars( ' ' );
+ aCurLine.EraseTrailingChars( ' ' );
+ aCurLine.EraseLeadingChars( '\t' );
+ aCurLine.EraseTrailingChars( '\t' );
+ aCurLine.EraseTrailingChars( '\r' );
+ aCurLine.EraseTrailingChars( '\n' );
+ aCurLine.EraseLeadingChars( '"' );
+ aCurLine.EraseTrailingChars( '"' );
+ aStream.Close();
+ aStream.Open( getPPDFile( String( aCurLine, m_aFileEncoding ) ) );
+ continue;
+ }
+ else if( ! bLanguageEncoding &&
+ aCurLine.CompareIgnoreCaseToAscii( "*languageencoding", 17 ) == COMPARE_EQUAL )
+ {
+ bLanguageEncoding = true; // generally only the first one counts
+ ByteString aLower = aCurLine;
+ aLower.ToLowerAscii();
+ if( aLower.Search( "isolatin1", 17 ) != STRING_NOTFOUND ||
+ aLower.Search( "windowsansi", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_MS_1252;
+ else if( aLower.Search( "isolatin2", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_ISO_8859_2;
+ else if( aLower.Search( "isolatin5", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_ISO_8859_5;
+ else if( aLower.Search( "jis83-rksj", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_SHIFT_JIS;
+ else if( aLower.Search( "macstandard", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
+ else if( aLower.Search( "utf-8", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_UTF8;
+ }
+ }
+ aLines.push_back( aCurLine );
+ }
+ }
+ aStream.Close();
+
+ // now get the Values
+ parse( aLines );
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "acquired %d Keys from PPD %s:\n", m_aKeys.size(), BSTRING( m_aFile ).GetBuffer() );
+ for( PPDParser::hash_type::const_iterator it = m_aKeys.begin(); it != m_aKeys.end(); ++it )
+ {
+ const PPDKey* pKey = it->second;
+ char* pSetupType = "<unknown>";
+ switch( pKey->m_eSetupType )
+ {
+ case PPDKey::ExitServer: pSetupType = "ExitServer";break;
+ case PPDKey::Prolog: pSetupType = "Prolog";break;
+ case PPDKey::DocumentSetup: pSetupType = "DocumentSetup";break;
+ case PPDKey::PageSetup: pSetupType = "PageSetup";break;
+ case PPDKey::JCLSetup: pSetupType = "JCLSetup";break;
+ case PPDKey::AnySetup: pSetupType = "AnySetup";break;
+ default: break;
+ };
+ fprintf( stderr, "\t\"%s\" (%d values) OrderDependency: %d %s\n",
+ BSTRING( pKey->getKey() ).GetBuffer(),
+ pKey->countValues(),
+ pKey->m_nOrderDependency,
+ pSetupType );
+ for( int j = 0; j < pKey->countValues(); j++ )
+ {
+ fprintf( stderr, "\t\t" );
+ const PPDValue* pValue = pKey->getValue( j );
+ if( pValue == pKey->m_pDefaultValue )
+ fprintf( stderr, "(Default:) " );
+ char* pVType = "<unknown>";
+ switch( pValue->m_eType )
+ {
+ case eInvocation: pVType = "invocation";break;
+ case eQuoted: pVType = "quoted";break;
+ case eString: pVType = "string";break;
+ case eSymbol: pVType = "symbol";break;
+ case eNo: pVType = "no";break;
+ default: break;
+ };
+ fprintf( stderr, "option: \"%s\", value: type %s \"%s\"\n",
+ BSTRING( pValue->m_aOption ).GetBuffer(),
+ pVType,
+ BSTRING( pValue->m_aValue ).GetBuffer() );
+ }
+ }
+ fprintf( stderr, "constraints: (%d found)\n", m_aConstraints.size() );
+ for( std::list< PPDConstraint >::const_iterator cit = m_aConstraints.begin(); cit != m_aConstraints.end(); ++cit )
+ {
+ fprintf( stderr, "*\"%s\" \"%s\" *\"%s\" \"%s\"\n",
+ BSTRING( cit->m_pKey1->getKey() ).GetBuffer(),
+ cit->m_pOption1 ? BSTRING( cit->m_pOption1->m_aOption ).GetBuffer() : "<nil>",
+ BSTRING( cit->m_pKey2->getKey() ).GetBuffer(),
+ cit->m_pOption2 ? BSTRING( cit->m_pOption2->m_aOption ).GetBuffer() : "<nil>"
+ );
+ }
+#endif
+
+ // fill in shortcuts
+ const PPDKey* pKey;
+
+ m_pImageableAreas = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ImageableArea" ) ) );
+ if( m_pImageableAreas )
+ m_pDefaultImageableArea = m_pImageableAreas->getDefaultValue();
+ DBG_ASSERT( m_pImageableAreas, "Warning: no ImageableArea in PPD\n" );
+ DBG_ASSERT( m_pDefaultImageableArea, "Warning: no DefaultImageableArea in PPD\n" );
+
+ m_pPaperDimensions = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PaperDimension" ) ) );
+ if( m_pPaperDimensions )
+ m_pDefaultPaperDimension = m_pPaperDimensions->getDefaultValue();
+ DBG_ASSERT( m_pPaperDimensions, "Warning: no PaperDimension in PPD\n" );
+ DBG_ASSERT( m_pDefaultPaperDimension, "Warning: no DefaultPaperDimension in PPD\n" );
+
+ m_pResolutions = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ) );
+ if( m_pResolutions )
+ m_pDefaultResolution = m_pResolutions->getDefaultValue();
+ DBG_ASSERT( m_pResolutions, "Warning: no Resolution in PPD\n" );
+ DBG_ASSERT( m_pDefaultResolution, "Warning: no DefaultResolution in PPD\n" );
+
+ m_pInputSlots = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
+ if( m_pInputSlots )
+ m_pDefaultInputSlot = m_pInputSlots->getDefaultValue();
+ DBG_ASSERT( m_pPaperDimensions, "Warning: no InputSlot in PPD\n" );
+ DBG_ASSERT( m_pDefaultPaperDimension, "Warning: no DefaultInputSlot in PPD\n" );
+
+ m_pDuplexTypes = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
+ if( m_pDuplexTypes )
+ m_pDefaultDuplexType = m_pDuplexTypes->getDefaultValue();
+
+ m_pFontList = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Font" ) ) );
+ DBG_ASSERT( m_pFontList, "Warning: no Font in PPD\n" );
+
+ // fill in direct values
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ModelName" ) ) )) )
+ m_aPrinterName = pKey->getValue( 0 )->m_aValue;
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "NickName" ) ) )) )
+ m_aNickName = pKey->getValue( 0 )->m_aValue;
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ColorDevice" ) ) )) )
+ m_bColorDevice = pKey->getValue( 0 )->m_aValue.CompareIgnoreCaseToAscii( "true", 4 ) == COMPARE_EQUAL ? true : false;
+
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "LanguageLevel" ) ) )) )
+ m_nLanguageLevel = pKey->getValue( 0 )->m_aValue.ToInt32();
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "TTRasterizer" ) ) )) )
+ m_bType42Capable = pKey->getValue( 0 )->m_aValue.EqualsIgnoreCaseAscii( "Type42" ) ? true : false;
+}
+
+PPDParser::~PPDParser()
+{
+ for( PPDParser::hash_type::iterator it = m_aKeys.begin(); it != m_aKeys.end(); ++it )
+ delete it->second;
+ delete m_pTranslator;
+}
+
+void PPDParser::insertKey( const String& rKey, PPDKey* pKey )
+{
+ m_aKeys[ rKey ] = pKey;
+ m_aOrderedKeys.push_back( pKey );
+}
+
+const PPDKey* PPDParser::getKey( int n ) const
+{
+ return ((unsigned int)n < m_aOrderedKeys.size() && n >= 0) ? m_aOrderedKeys[n] : NULL;
+}
+
+const PPDKey* PPDParser::getKey( const String& rKey ) const
+{
+ PPDParser::hash_type::const_iterator it = m_aKeys.find( rKey );
+ return it != m_aKeys.end() ? it->second : NULL;
+}
+
+bool PPDParser::hasKey( const PPDKey* pKey ) const
+{
+ return
+ pKey ?
+ ( m_aKeys.find( pKey->getKey() ) != m_aKeys.end() ? true : false ) :
+ false;
+}
+
+static sal_uInt8 getNibble( sal_Char cChar )
+{
+ sal_uInt8 nRet = 0;
+ if( cChar >= '0' && cChar <= '9' )
+ nRet = sal_uInt8( cChar - '0' );
+ else if( cChar >= 'A' && cChar <= 'F' )
+ nRet = 10 + sal_uInt8( cChar - 'A' );
+ else if( cChar >= 'a' && cChar <= 'f' )
+ nRet = 10 + sal_uInt8( cChar - 'a' );
+ return nRet;
+}
+
+String PPDParser::handleTranslation( const ByteString& i_rString, bool bIsGlobalized )
+{
+ int nOrigLen = i_rString.Len();
+ OStringBuffer aTrans( nOrigLen );
+ const sal_Char* pStr = i_rString.GetBuffer();
+ const sal_Char* pEnd = pStr + nOrigLen;
+ while( pStr < pEnd )
+ {
+ if( *pStr == '<' )
+ {
+ pStr++;
+ sal_Char cChar;
+ while( *pStr != '>' && pStr < pEnd-1 )
+ {
+ cChar = getNibble( *pStr++ ) << 4;
+ cChar |= getNibble( *pStr++ );
+ aTrans.append( cChar );
+ }
+ pStr++;
+ }
+ else
+ aTrans.append( *pStr++ );
+ }
+ return OStringToOUString( aTrans.makeStringAndClear(), bIsGlobalized ? RTL_TEXTENCODING_UTF8 : m_aFileEncoding );
+}
+
+void PPDParser::parse( ::std::list< ByteString >& rLines )
+{
+ std::list< ByteString >::iterator line = rLines.begin();
+ PPDParser::hash_type::const_iterator keyit;
+ while( line != rLines.end() )
+ {
+ ByteString aCurrentLine( *line );
+ ++line;
+ if( aCurrentLine.GetChar(0) != '*' )
+ continue;
+ if( aCurrentLine.GetChar(1) == '%' )
+ continue;
+
+ ByteString aKey = GetCommandLineToken( 0, aCurrentLine.GetToken( 0, ':' ) );
+ int nPos = aKey.Search( '/' );
+ if( nPos != STRING_NOTFOUND )
+ aKey.Erase( nPos );
+ aKey.Erase( 0, 1 ); // remove the '*'
+
+ if( aKey.Equals( "CloseUI" ) || aKey.Equals( "OpenGroup" ) || aKey.Equals( "CloseGroup" ) || aKey.Equals( "End" ) || aKey.Equals( "OpenSubGroup" ) || aKey.Equals( "CloseSubGroup" ) )
+ continue;
+
+ if( aKey.Equals( "OpenUI" ) )
+ {
+ parseOpenUI( aCurrentLine );
+ continue;
+ }
+ else if( aKey.Equals( "OrderDependency" ) )
+ {
+ parseOrderDependency( aCurrentLine );
+ continue;
+ }
+ else if( aKey.Equals( "UIConstraints" ) || aKey.Equals( "NonUIConstraints" ) )
+ continue; // parsed in pass 2
+ else if( aKey.Equals( "CustomPageSize" ) ) // currently not handled
+ continue;
+
+ // default values are parsed in pass 2
+ if( aKey.CompareTo( "Default", 7 ) == COMPARE_EQUAL )
+ continue;
+
+ bool bQuery = false;
+ if( aKey.GetChar( 0 ) == '?' )
+ {
+ aKey.Erase( 0, 1 );
+ bQuery = true;
+ }
+
+ String aUniKey( aKey, RTL_TEXTENCODING_MS_1252 );
+ // handle CUPS extension for globalized PPDs
+ bool bIsGlobalizedLine = false;
+ com::sun::star::lang::Locale aTransLocale;
+ if( ( aUniKey.Len() > 3 && aUniKey.GetChar( 2 ) == '.' ) ||
+ ( aUniKey.Len() > 5 && aUniKey.GetChar( 2 ) == '_' && aUniKey.GetChar( 5 ) == '.' ) )
+ {
+ if( aUniKey.GetChar( 2 ) == '.' )
+ {
+ aTransLocale.Language = aUniKey.Copy( 0, 2 );
+ aUniKey = aUniKey.Copy( 3 );
+ }
+ else
+ {
+ aTransLocale.Language = aUniKey.Copy( 0, 2 );
+ aTransLocale.Country = aUniKey.Copy( 3, 2 );
+ aUniKey = aUniKey.Copy( 6 );
+ }
+ bIsGlobalizedLine = true;
+ }
+
+ String aOption;
+ nPos = aCurrentLine.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ {
+ aOption = String( aCurrentLine.Copy( 1, nPos-1 ), RTL_TEXTENCODING_MS_1252 );
+ aOption = GetCommandLineToken( 1, aOption );
+ int nTransPos = aOption.Search( '/' );
+ if( nTransPos != STRING_NOTFOUND )
+ aOption.Erase( nTransPos );
+ }
+
+ PPDValueType eType = eNo;
+ String aValue;
+ rtl::OUString aOptionTranslation;
+ rtl::OUString aValueTranslation;
+ if( nPos != STRING_NOTFOUND )
+ {
+ // found a colon, there may be an option
+ ByteString aLine = aCurrentLine.Copy( 1, nPos-1 );
+ aLine = WhitespaceToSpace( aLine );
+ int nTransPos = aLine.Search( '/' );
+ if( nTransPos != STRING_NOTFOUND )
+ aOptionTranslation = handleTranslation( aLine.Copy( nTransPos+1 ), bIsGlobalizedLine );
+
+ // read in more lines if necessary for multiline values
+ aLine = aCurrentLine.Copy( nPos+1 );
+ if( aLine.Len() )
+ {
+ while( ! ( aLine.GetTokenCount( '"' ) & 1 ) &&
+ line != rLines.end() )
+ // while there is an even number of tokens; that means
+ // an odd number of doubleqoutes
+ {
+ // copy the newlines also
+ aLine += '\n';
+ aLine += *line;
+ ++line;
+ }
+ }
+ aLine = WhitespaceToSpace( aLine );
+
+ // #i100644# handle a missing value (actually a broken PPD)
+ if( ! aLine.Len() )
+ {
+ if( aOption.Len() &&
+ aUniKey.CompareToAscii( "JCL", 3 ) != COMPARE_EQUAL )
+ eType = eInvocation;
+ else
+ eType = eQuoted;
+ }
+ // check for invocation or quoted value
+ else if( aLine.GetChar(0) == '"' )
+ {
+ aLine.Erase( 0, 1 );
+ nTransPos = aLine.Search( '"' );
+ aValue = String( aLine.Copy( 0, nTransPos ), RTL_TEXTENCODING_MS_1252 );
+ // after the second doublequote can follow a / and a translation
+ aValueTranslation = handleTranslation( aLine.Copy( nTransPos+2 ), bIsGlobalizedLine );
+ // check for quoted value
+ if( aOption.Len() &&
+ aUniKey.CompareToAscii( "JCL", 3 ) != COMPARE_EQUAL )
+ eType = eInvocation;
+ else
+ eType = eQuoted;
+ }
+ // check for symbol value
+ else if( aLine.GetChar(0) == '^' )
+ {
+ aLine.Erase( 0, 1 );
+ aValue = String( aLine, RTL_TEXTENCODING_MS_1252 );
+ eType = eSymbol;
+ }
+ else
+ {
+ // must be a string value then
+ // strictly this is false because string values
+ // can contain any whitespace which is reduced
+ // to one space by now
+ // who cares ...
+ nTransPos = aLine.Search( '/' );
+ if( nTransPos == STRING_NOTFOUND )
+ nTransPos = aLine.Len();
+ aValue = String( aLine.Copy( 0, nTransPos ), RTL_TEXTENCODING_MS_1252 );
+ aValueTranslation = handleTranslation( aLine.Copy( nTransPos+1 ), bIsGlobalizedLine );
+ eType = eString;
+ }
+ }
+
+ // handle globalized PPD entries
+ if( bIsGlobalizedLine )
+ {
+ // handle main key translations of form:
+ // *ll_CC.Translation MainKeyword/translated text: ""
+ if( aUniKey.EqualsAscii( "Translation" ) )
+ {
+ m_pTranslator->insertKey( aOption, aOptionTranslation, aTransLocale );
+ }
+ // handle options translations of for:
+ // *ll_CC.MainKeyword OptionKeyword/translated text: ""
+ else
+ {
+ m_pTranslator->insertOption( aUniKey, aOption, aOptionTranslation, aTransLocale );
+ }
+ continue;
+ }
+
+ PPDKey* pKey = NULL;
+ keyit = m_aKeys.find( aUniKey );
+ if( keyit == m_aKeys.end() )
+ {
+ pKey = new PPDKey( aUniKey );
+ insertKey( aUniKey, pKey );
+ }
+ else
+ pKey = keyit->second;
+
+ if( eType == eNo && bQuery )
+ continue;
+
+ PPDValue* pValue = pKey->insertValue( aOption );
+ if( ! pValue )
+ continue;
+ pValue->m_eType = eType;
+ pValue->m_aValue = aValue;
+
+ if( aOptionTranslation.getLength() )
+ m_pTranslator->insertOption( aUniKey, aOption, aOptionTranslation, aTransLocale );
+ if( aValueTranslation.getLength() )
+ m_pTranslator->insertValue( aUniKey, aOption, aValue, aValueTranslation, aTransLocale );
+
+ // eventually update query and remove from option list
+ if( bQuery && pKey->m_bQueryValue == sal_False )
+ {
+ pKey->m_aQueryValue = *pValue;
+ pKey->m_bQueryValue = true;
+ pKey->eraseValue( pValue->m_aOption );
+ }
+ }
+
+ // second pass: fill in defaults
+ for( line = rLines.begin(); line != rLines.end(); ++line )
+ {
+ ByteString aLine( *line );
+ if( aLine.CompareTo( "*Default", 8 ) == COMPARE_EQUAL )
+ {
+ String aKey( aLine.Copy( 8 ), RTL_TEXTENCODING_MS_1252 );
+ sal_uInt16 nPos = aKey.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ {
+ aKey.Erase( nPos );
+ String aOption( WhitespaceToSpace( aLine.Copy( nPos+9 ) ), RTL_TEXTENCODING_MS_1252 );
+ keyit = m_aKeys.find( aKey );
+ if( keyit != m_aKeys.end() )
+ {
+ PPDKey* pKey = keyit->second;
+ const PPDValue* pDefValue = pKey->getValue( aOption );
+ if( pKey->m_pDefaultValue == NULL )
+ pKey->m_pDefaultValue = pDefValue;
+ }
+ else
+ {
+ // some PPDs contain defaults for keys that
+ // do not exist otherwise
+ // (example: DefaultResolution)
+ // so invent that key here and have a default value
+ PPDKey* pKey = new PPDKey( aKey );
+ PPDValue* pNewValue = pKey->insertValue( aOption );
+ pNewValue->m_eType = eInvocation; // or what ?
+ insertKey( aKey, pKey );
+ }
+ }
+ }
+ else if( aLine.CompareTo( "*UIConstraints", 14 ) == COMPARE_EQUAL ||
+ aLine.CompareTo( "*NonUIConstraints", 17 ) == COMPARE_EQUAL )
+ parseConstraint( aLine );
+
+ }
+}
+
+void PPDParser::parseOpenUI( const ByteString& rLine )
+{
+ String aTranslation;
+ ByteString aKey = rLine;
+
+ int nPos = aKey.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ aKey.Erase( nPos );
+ nPos = aKey.Search( '/' );
+ if( nPos != STRING_NOTFOUND )
+ {
+ aTranslation = handleTranslation( aKey.Copy( nPos + 1 ), false );
+ aKey.Erase( nPos );
+ }
+ aKey = GetCommandLineToken( 1, aKey );
+ aKey.Erase( 0, 1 );
+
+ String aUniKey( aKey, RTL_TEXTENCODING_MS_1252 );
+ PPDParser::hash_type::const_iterator keyit = m_aKeys.find( aUniKey );
+ PPDKey* pKey;
+ if( keyit == m_aKeys.end() )
+ {
+ pKey = new PPDKey( aUniKey );
+ insertKey( aUniKey, pKey );
+ }
+ else
+ pKey = keyit->second;
+
+ pKey->m_bUIOption = true;
+ m_pTranslator->insertKey( pKey->getKey(), aTranslation );
+
+ ByteString aValue = WhitespaceToSpace( rLine.GetToken( 1, ':' ) );
+ if( aValue.CompareIgnoreCaseToAscii( "boolean" ) == COMPARE_EQUAL )
+ pKey->m_eUIType = PPDKey::Boolean;
+ else if( aValue.CompareIgnoreCaseToAscii( "pickmany" ) == COMPARE_EQUAL )
+ pKey->m_eUIType = PPDKey::PickMany;
+ else
+ pKey->m_eUIType = PPDKey::PickOne;
+}
+
+void PPDParser::parseOrderDependency( const ByteString& rLine )
+{
+ ByteString aLine( rLine );
+ int nPos = aLine.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ aLine.Erase( 0, nPos+1 );
+
+ int nOrder = GetCommandLineToken( 0, aLine ).ToInt32();
+ ByteString aSetup = GetCommandLineToken( 1, aLine );
+ String aKey( GetCommandLineToken( 2, aLine ), RTL_TEXTENCODING_MS_1252 );
+ if( aKey.GetChar( 0 ) != '*' )
+ return; // invalid order depency
+ aKey.Erase( 0, 1 );
+
+ PPDKey* pKey;
+ PPDParser::hash_type::const_iterator keyit = m_aKeys.find( aKey );
+ if( keyit == m_aKeys.end() )
+ {
+ pKey = new PPDKey( aKey );
+ insertKey( aKey, pKey );
+ }
+ else
+ pKey = keyit->second;
+
+ pKey->m_nOrderDependency = nOrder;
+ if( aSetup.Equals( "ExitServer" ) )
+ pKey->m_eSetupType = PPDKey::ExitServer;
+ else if( aSetup.Equals( "Prolog" ) )
+ pKey->m_eSetupType = PPDKey::Prolog;
+ else if( aSetup.Equals( "DocumentSetup" ) )
+ pKey->m_eSetupType = PPDKey::DocumentSetup;
+ else if( aSetup.Equals( "PageSetup" ) )
+ pKey->m_eSetupType = PPDKey::PageSetup;
+ else if( aSetup.Equals( "JCLSetup" ) )
+ pKey->m_eSetupType = PPDKey::JCLSetup;
+ else
+ pKey->m_eSetupType = PPDKey::AnySetup;
+}
+
+void PPDParser::parseConstraint( const ByteString& rLine )
+{
+ bool bFailed = false;
+
+ String aLine( rLine, RTL_TEXTENCODING_MS_1252 );
+ aLine.Erase( 0, rLine.Search( ':' )+1 );
+ PPDConstraint aConstraint;
+ int nTokens = GetCommandLineTokenCount( aLine );
+ for( int i = 0; i < nTokens; i++ )
+ {
+ String aToken = GetCommandLineToken( i, aLine );
+ if( aToken.GetChar( 0 ) == '*' )
+ {
+ aToken.Erase( 0, 1 );
+ if( aConstraint.m_pKey1 )
+ aConstraint.m_pKey2 = getKey( aToken );
+ else
+ aConstraint.m_pKey1 = getKey( aToken );
+ }
+ else
+ {
+ if( aConstraint.m_pKey2 )
+ {
+ if( ! ( aConstraint.m_pOption2 = aConstraint.m_pKey2->getValue( aToken ) ) )
+ bFailed = true;
+ }
+ else if( aConstraint.m_pKey1 )
+ {
+ if( ! ( aConstraint.m_pOption1 = aConstraint.m_pKey1->getValue( aToken ) ) )
+ bFailed = true;
+ }
+ else
+ // constraint for nonexistent keys; this happens
+ // e.g. in HP4PLUS3
+ bFailed = true;
+ }
+ }
+ // there must be two keywords
+ if( ! aConstraint.m_pKey1 || ! aConstraint.m_pKey2 || bFailed )
+ {
+#ifdef __DEBUG
+ fprintf( stderr, "Warning: constraint \"%s\" is invalid\n", rLine.GetStr() );
+#endif
+ }
+ else
+ m_aConstraints.push_back( aConstraint );
+}
+
+String PPDParser::getDefaultPaperDimension() const
+{
+ if( m_pDefaultPaperDimension )
+ return m_pDefaultPaperDimension->m_aOption;
+
+ return String();
+}
+
+bool PPDParser::getMargins(
+ const String& rPaperName,
+ int& rLeft, int& rRight,
+ int& rUpper, int& rLower ) const
+{
+ if( ! m_pImageableAreas || ! m_pPaperDimensions )
+ return false;
+
+ int nPDim=-1, nImArea=-1, i;
+ for( i = 0; i < m_pImageableAreas->countValues(); i++ )
+ if( rPaperName == m_pImageableAreas->getValue( i )->m_aOption )
+ nImArea = i;
+ for( i = 0; i < m_pPaperDimensions->countValues(); i++ )
+ if( rPaperName == m_pPaperDimensions->getValue( i )->m_aOption )
+ nPDim = i;
+ if( nPDim == -1 || nImArea == -1 )
+ return false;
+
+ double ImLLx, ImLLy, ImURx, ImURy;
+ double PDWidth, PDHeight;
+ String aArea = m_pImageableAreas->getValue( nImArea )->m_aValue;
+ ImLLx = StringToDouble( GetCommandLineToken( 0, aArea ) );
+ ImLLy = StringToDouble( GetCommandLineToken( 1, aArea ) );
+ ImURx = StringToDouble( GetCommandLineToken( 2, aArea ) );
+ ImURy = StringToDouble( GetCommandLineToken( 3, aArea ) );
+ aArea = m_pPaperDimensions->getValue( nPDim )->m_aValue;
+ PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) );
+ PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) );
+ rLeft = (int)(ImLLx + 0.5);
+ rLower = (int)(ImLLy + 0.5);
+ rUpper = (int)(PDHeight - ImURy + 0.5);
+ rRight = (int)(PDWidth - ImURx + 0.5);
+
+ return true;
+}
+
+bool PPDParser::getPaperDimension(
+ const String& rPaperName,
+ int& rWidth, int& rHeight ) const
+{
+ if( ! m_pPaperDimensions )
+ return false;
+
+ int nPDim=-1;
+ for( int i = 0; i < m_pPaperDimensions->countValues(); i++ )
+ if( rPaperName == m_pPaperDimensions->getValue( i )->m_aOption )
+ nPDim = i;
+ if( nPDim == -1 )
+ return false;
+
+ double PDWidth, PDHeight;
+ String aArea = m_pPaperDimensions->getValue( nPDim )->m_aValue;
+ PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) );
+ PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) );
+ rHeight = (int)(PDHeight + 0.5);
+ rWidth = (int)(PDWidth + 0.5);
+
+ return true;
+}
+
+String PPDParser::matchPaper( int nWidth, int nHeight ) const
+{
+ if( ! m_pPaperDimensions )
+ return String();
+
+ int nPDim = -1;
+ double PDWidth, PDHeight;
+ double fSort = 2e36, fNewSort;
+
+ for( int i = 0; i < m_pPaperDimensions->countValues(); i++ )
+ {
+ String aArea = m_pPaperDimensions->getValue( i )->m_aValue;
+ PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) );
+ PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) );
+ PDWidth /= (double)nWidth;
+ PDHeight /= (double)nHeight;
+ if( PDWidth >= 0.9 && PDWidth <= 1.1 &&
+ PDHeight >= 0.9 && PDHeight <= 1.1 )
+ {
+ fNewSort =
+ (1.0-PDWidth)*(1.0-PDWidth) + (1.0-PDHeight)*(1.0-PDHeight);
+ if( fNewSort == 0.0 ) // perfect match
+ return m_pPaperDimensions->getValue( i )->m_aOption;
+
+ if( fNewSort < fSort )
+ {
+ fSort = fNewSort;
+ nPDim = i;
+ }
+ }
+ }
+
+ static bool bDontSwap = false;
+ if( nPDim == -1 && ! bDontSwap )
+ {
+ // swap portrait/landscape and try again
+ bDontSwap = true;
+ String rRet = matchPaper( nHeight, nWidth );
+ bDontSwap = false;
+ return rRet;
+ }
+
+ return nPDim != -1 ? m_pPaperDimensions->getValue( nPDim )->m_aOption : String();
+}
+
+String PPDParser::getDefaultInputSlot() const
+{
+ if( m_pDefaultInputSlot )
+ return m_pDefaultInputSlot->m_aValue;
+ return String();
+}
+
+String PPDParser::getSlot( int nSlot ) const
+{
+ if( ! m_pInputSlots )
+ return String();
+
+ if( nSlot > 0 && nSlot < m_pInputSlots->countValues() )
+ return m_pInputSlots->getValue( nSlot )->m_aOption;
+ else if( m_pInputSlots->countValues() > 0 )
+ return m_pInputSlots->getValue( (sal_uLong)0 )->m_aOption;
+
+ return String();
+}
+
+String PPDParser::getSlotCommand( int nSlot ) const
+{
+ if( ! m_pInputSlots )
+ return String();
+
+ if( nSlot > 0 && nSlot < m_pInputSlots->countValues() )
+ return m_pInputSlots->getValue( nSlot )->m_aValue;
+ else if( m_pInputSlots->countValues() > 0 )
+ return m_pInputSlots->getValue( (sal_uLong)0 )->m_aValue;
+
+ return String();
+}
+
+String PPDParser::getSlotCommand( const String& rSlot ) const
+{
+ if( ! m_pInputSlots )
+ return String();
+
+ for( int i=0; i < m_pInputSlots->countValues(); i++ )
+ {
+ const PPDValue* pValue = m_pInputSlots->getValue( i );
+ if( pValue->m_aOption == rSlot )
+ return pValue->m_aValue;
+ }
+ return String();
+}
+
+String PPDParser::getPaperDimension( int nPaperDimension ) const
+{
+ if( ! m_pPaperDimensions )
+ return String();
+
+ if( nPaperDimension > 0 && nPaperDimension < m_pPaperDimensions->countValues() )
+ return m_pPaperDimensions->getValue( nPaperDimension )->m_aOption;
+ else if( m_pPaperDimensions->countValues() > 0 )
+ return m_pPaperDimensions->getValue( (sal_uLong)0 )->m_aOption;
+
+ return String();
+}
+
+String PPDParser::getPaperDimensionCommand( int nPaperDimension ) const
+{
+ if( ! m_pPaperDimensions )
+ return String();
+
+ if( nPaperDimension > 0 && nPaperDimension < m_pPaperDimensions->countValues() )
+ return m_pPaperDimensions->getValue( nPaperDimension )->m_aValue;
+ else if( m_pPaperDimensions->countValues() > 0 )
+ return m_pPaperDimensions->getValue( (sal_uLong)0 )->m_aValue;
+
+ return String();
+}
+
+String PPDParser::getPaperDimensionCommand( const String& rPaperDimension ) const
+{
+ if( ! m_pPaperDimensions )
+ return String();
+
+ for( int i=0; i < m_pPaperDimensions->countValues(); i++ )
+ {
+ const PPDValue* pValue = m_pPaperDimensions->getValue( i );
+ if( pValue->m_aOption == rPaperDimension )
+ return pValue->m_aValue;
+ }
+ return String();
+}
+
+void PPDParser::getResolutionFromString(
+ const String& rString,
+ int& rXRes, int& rYRes ) const
+{
+ int nDPIPos;
+
+ rXRes = rYRes = 300;
+
+ nDPIPos = rString.SearchAscii( "dpi" );
+ if( nDPIPos != STRING_NOTFOUND )
+ {
+ int nPos = 0;
+ if( ( nPos = rString.Search( 'x' ) ) != STRING_NOTFOUND )
+ {
+ rXRes = rString.Copy( 0, nPos ).ToInt32();
+ rYRes = rString.GetToken( 1, 'x' ).Erase( nDPIPos - nPos - 1 ).ToInt32();
+ }
+ else
+ rXRes = rYRes = rString.Copy( 0, nDPIPos ).ToInt32();
+ }
+}
+
+void PPDParser::getDefaultResolution( int& rXRes, int& rYRes ) const
+{
+ if( m_pDefaultResolution )
+ {
+ getResolutionFromString( m_pDefaultResolution->m_aValue, rXRes, rYRes );
+ return;
+ }
+
+ rXRes = 300;
+ rYRes = 300;
+}
+
+int PPDParser::getResolutions() const
+{
+ if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) &&
+ m_pDefaultResolution )
+ return 1;
+ return m_pResolutions ? m_pResolutions->countValues() : 0;
+}
+
+void PPDParser::getResolution( int nNr, int& rXRes, int& rYRes ) const
+{
+ if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) && m_pDefaultResolution && nNr == 0 )
+ {
+ getDefaultResolution( rXRes, rYRes );
+ return;
+ }
+ if( ! m_pResolutions )
+ return;
+
+ getResolutionFromString( m_pResolutions->getValue( nNr )->m_aOption,
+ rXRes, rYRes );
+}
+
+String PPDParser::getResolutionCommand( int nXRes, int nYRes ) const
+{
+ if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) && m_pDefaultResolution )
+ return m_pDefaultResolution->m_aValue;
+
+ if( ! m_pResolutions )
+ return String();
+
+ int nX, nY;
+ for( int i = 0; i < m_pResolutions->countValues(); i++ )
+ {
+ getResolutionFromString( m_pResolutions->getValue( i )->m_aOption,
+ nX, nY );
+ if( nX == nXRes && nY == nYRes )
+ return m_pResolutions->getValue( i )->m_aValue;
+ }
+ return String();
+}
+
+String PPDParser::getDefaultDuplexType() const
+{
+ if( m_pDefaultDuplexType )
+ return m_pDefaultDuplexType->m_aValue;
+ return String();
+}
+
+String PPDParser::getDuplex( int nDuplex ) const
+{
+ if( ! m_pDuplexTypes )
+ return String();
+
+ if( nDuplex > 0 && nDuplex < m_pDuplexTypes->countValues() )
+ return m_pDuplexTypes->getValue( nDuplex )->m_aOption;
+ else if( m_pDuplexTypes->countValues() > 0 )
+ return m_pDuplexTypes->getValue( (sal_uLong)0 )->m_aOption;
+
+ return String();
+}
+
+String PPDParser::getDuplexCommand( int nDuplex ) const
+{
+ if( ! m_pDuplexTypes )
+ return String();
+
+ if( nDuplex > 0 && nDuplex < m_pDuplexTypes->countValues() )
+ return m_pDuplexTypes->getValue( nDuplex )->m_aValue;
+ else if( m_pDuplexTypes->countValues() > 0 )
+ return m_pDuplexTypes->getValue( (sal_uLong)0 )->m_aValue;
+
+ return String();
+}
+
+String PPDParser::getDuplexCommand( const String& rDuplex ) const
+{
+ if( ! m_pDuplexTypes )
+ return String();
+
+ for( int i=0; i < m_pDuplexTypes->countValues(); i++ )
+ {
+ const PPDValue* pValue = m_pDuplexTypes->getValue( i );
+ if( pValue->m_aOption == rDuplex )
+ return pValue->m_aValue;
+ }
+ return String();
+}
+
+void PPDParser::getFontAttributes(
+ int nFont,
+ String& rEncoding,
+ String& rCharset ) const
+{
+ if( m_pFontList && nFont >= 0 && nFont < m_pFontList->countValues() )
+ {
+ String aAttribs =
+ WhitespaceToSpace( m_pFontList->getValue( nFont )->m_aValue );
+ rEncoding = GetCommandLineToken( 0, aAttribs );
+ rCharset = GetCommandLineToken( 2, aAttribs );
+ }
+}
+
+void PPDParser::getFontAttributes(
+ const String& rFont,
+ String& rEncoding,
+ String& rCharset ) const
+{
+ if( m_pFontList )
+ {
+ for( int i = 0; i < m_pFontList->countValues(); i++ )
+ if( m_pFontList->getValue( i )->m_aOption == rFont )
+ getFontAttributes( i, rEncoding, rCharset );
+ }
+}
+
+String PPDParser::getFont( int nFont ) const
+{
+ if( ! m_pFontList )
+ return String();
+
+ if( nFont >=0 && nFont < m_pFontList->countValues() )
+ return m_pFontList->getValue( nFont )->m_aOption;
+ return String();
+}
+
+rtl::OUString PPDParser::translateKey( const rtl::OUString& i_rKey,
+ const com::sun::star::lang::Locale& i_rLocale ) const
+{
+ rtl::OUString aResult( m_pTranslator->translateKey( i_rKey, i_rLocale ) );
+ if( aResult.getLength() == 0 )
+ aResult = i_rKey;
+ return aResult;
+}
+
+rtl::OUString PPDParser::translateOption( const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const com::sun::star::lang::Locale& i_rLocale ) const
+{
+ rtl::OUString aResult( m_pTranslator->translateOption( i_rKey, i_rOption, i_rLocale ) );
+ if( aResult.getLength() == 0 )
+ aResult = i_rOption;
+ return aResult;
+}
+
+rtl::OUString PPDParser::translateValue( const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rValue,
+ const com::sun::star::lang::Locale& i_rLocale ) const
+{
+ rtl::OUString aResult( m_pTranslator->translateValue( i_rKey, i_rOption, i_rValue, i_rLocale ) );
+ if( aResult.getLength() == 0 )
+ aResult = i_rValue;
+ return aResult;
+}
+
+/*
+ * PPDKey
+ */
+
+PPDKey::PPDKey( const String& rKey ) :
+ m_aKey( rKey ),
+ m_pDefaultValue( NULL ),
+ m_bQueryValue( false ),
+ m_bUIOption( false ),
+ m_eUIType( PickOne ),
+ m_nOrderDependency( 100 ),
+ m_eSetupType( AnySetup )
+{
+}
+
+// -------------------------------------------------------------------
+
+PPDKey::~PPDKey()
+{
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDKey::getValue( int n ) const
+{
+ return ((unsigned int)n < m_aOrderedValues.size() && n >= 0) ? m_aOrderedValues[n] : NULL;
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDKey::getValue( const String& rOption ) const
+{
+ PPDKey::hash_type::const_iterator it = m_aValues.find( rOption );
+ return it != m_aValues.end() ? &it->second : NULL;
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDKey::getValueCaseInsensitive( const String& rOption ) const
+{
+ const PPDValue* pValue = getValue( rOption );
+ if( ! pValue )
+ {
+ for( size_t n = 0; n < m_aOrderedValues.size() && ! pValue; n++ )
+ if( m_aOrderedValues[n]->m_aOption.EqualsIgnoreCaseAscii( rOption ) )
+ pValue = m_aOrderedValues[n];
+ }
+
+ return pValue;
+}
+
+// -------------------------------------------------------------------
+
+void PPDKey::eraseValue( const String& rOption )
+{
+ PPDKey::hash_type::iterator it = m_aValues.find( rOption );
+ if( it == m_aValues.end() )
+ return;
+
+ for( PPDKey::value_type::iterator vit = m_aOrderedValues.begin(); vit != m_aOrderedValues.end(); ++vit )
+ {
+ if( *vit == &(it->second ) )
+ {
+ m_aOrderedValues.erase( vit );
+ break;
+ }
+ }
+ m_aValues.erase( it );
+}
+
+// -------------------------------------------------------------------
+
+PPDValue* PPDKey::insertValue( const String& rOption )
+{
+ if( m_aValues.find( rOption ) != m_aValues.end() )
+ return NULL;
+
+ PPDValue aValue;
+ aValue.m_aOption = rOption;
+ m_aValues[ rOption ] = aValue;
+ PPDValue* pValue = &m_aValues[rOption];
+ m_aOrderedValues.push_back( pValue );
+ return pValue;
+}
+
+// -------------------------------------------------------------------
+
+/*
+ * PPDContext
+ */
+
+PPDContext::PPDContext( const PPDParser* pParser ) :
+ m_pParser( pParser )
+{
+}
+
+// -------------------------------------------------------------------
+
+PPDContext& PPDContext::operator=( const PPDContext& rCopy )
+{
+ m_pParser = rCopy.m_pParser;
+ m_aCurrentValues = rCopy.m_aCurrentValues;
+ return *this;
+}
+
+// -------------------------------------------------------------------
+
+PPDContext::~PPDContext()
+{
+}
+
+// -------------------------------------------------------------------
+
+const PPDKey* PPDContext::getModifiedKey( int n ) const
+{
+ hash_type::const_iterator it;
+ for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end() && n--; ++it )
+ ;
+ return it != m_aCurrentValues.end() ? it->first : NULL;
+}
+
+// -------------------------------------------------------------------
+
+void PPDContext::setParser( const PPDParser* pParser )
+{
+ if( pParser != m_pParser )
+ {
+ m_aCurrentValues.clear();
+ m_pParser = pParser;
+ }
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDContext::getValue( const PPDKey* pKey ) const
+{
+ if( ! m_pParser )
+ return NULL;
+
+ hash_type::const_iterator it;
+ it = m_aCurrentValues.find( pKey );
+ if( it != m_aCurrentValues.end() )
+ return it->second;
+
+ if( ! m_pParser->hasKey( pKey ) )
+ return NULL;
+
+ const PPDValue* pValue = pKey->getDefaultValue();
+ if( ! pValue )
+ pValue = pKey->getValue( 0 );
+
+ return pValue;
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDContext::setValue( const PPDKey* pKey, const PPDValue* pValue, bool bDontCareForConstraints )
+{
+ if( ! m_pParser || ! pKey )
+ return NULL;
+
+ // pValue can be NULL - it means ignore this option
+
+ if( ! m_pParser->hasKey( pKey ) )
+ return NULL;
+
+ // check constraints
+ if( pValue )
+ {
+ if( bDontCareForConstraints )
+ {
+ m_aCurrentValues[ pKey ] = pValue;
+ }
+ else if( checkConstraints( pKey, pValue, true ) )
+ {
+ m_aCurrentValues[ pKey ] = pValue;
+
+ // after setting this value, check all constraints !
+ hash_type::iterator it = m_aCurrentValues.begin();
+ while( it != m_aCurrentValues.end() )
+ {
+ if( it->first != pKey &&
+ ! checkConstraints( it->first, it->second, false ) )
+ {
+#ifdef __DEBUG
+ fprintf( stderr, "PPDContext::setValue: option %s (%s) is constrained after setting %s to %s\n",
+ it->first->getKey().GetStr(),
+ it->second->m_aOption.GetStr(),
+ pKey->getKey().GetStr(),
+ pValue->m_aOption.GetStr() );
+#endif
+ resetValue( it->first, true );
+ it = m_aCurrentValues.begin();
+ }
+ else
+ ++it;
+ }
+ }
+ }
+ else
+ m_aCurrentValues[ pKey ] = NULL;
+
+ return pValue;
+}
+
+// -------------------------------------------------------------------
+
+bool PPDContext::checkConstraints( const PPDKey* pKey, const PPDValue* pValue )
+{
+ if( ! m_pParser || ! pKey || ! pValue )
+ return false;
+
+ // ensure that this key is already in the list if it exists at all
+ if( m_aCurrentValues.find( pKey ) != m_aCurrentValues.end() )
+ return checkConstraints( pKey, pValue, false );
+
+ // it is not in the list, insert it temporarily
+ bool bRet = false;
+ if( m_pParser->hasKey( pKey ) )
+ {
+ const PPDValue* pDefValue = pKey->getDefaultValue();
+ m_aCurrentValues[ pKey ] = pDefValue;
+ bRet = checkConstraints( pKey, pValue, false );
+ m_aCurrentValues.erase( pKey );
+ }
+
+ return bRet;
+}
+
+// -------------------------------------------------------------------
+
+bool PPDContext::resetValue( const PPDKey* pKey, bool bDefaultable )
+{
+ if( ! pKey || ! m_pParser || ! m_pParser->hasKey( pKey ) )
+ return false;
+
+ const PPDValue* pResetValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
+ if( ! pResetValue )
+ pResetValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "False" ) ) );
+ if( ! pResetValue && bDefaultable )
+ pResetValue = pKey->getDefaultValue();
+
+ bool bRet = pResetValue ? ( setValue( pKey, pResetValue ) == pResetValue ? true : false ) : false;
+
+ return bRet;
+}
+
+// -------------------------------------------------------------------
+
+bool PPDContext::checkConstraints( const PPDKey* pKey, const PPDValue* pNewValue, bool bDoReset )
+{
+ if( ! pNewValue )
+ return true;
+
+ // sanity checks
+ if( ! m_pParser )
+ return false;
+
+ if( pKey->getValue( pNewValue->m_aOption ) != pNewValue )
+ return false;
+
+ // None / False and the default can always be set, but be careful !
+ // setting them might influence constrained values
+ if( pNewValue->m_aOption.EqualsAscii( "None" ) || pNewValue->m_aOption.EqualsAscii( "False" ) ||
+ pNewValue == pKey->getDefaultValue() )
+ return true;
+
+ const ::std::list< PPDParser::PPDConstraint >& rConstraints( m_pParser->getConstraints() );
+ for( ::std::list< PPDParser::PPDConstraint >::const_iterator it = rConstraints.begin(); it != rConstraints.end(); ++it )
+ {
+ const PPDKey* pLeft = it->m_pKey1;
+ const PPDKey* pRight = it->m_pKey2;
+ if( ! pLeft || ! pRight || ( pKey != pLeft && pKey != pRight ) )
+ continue;
+
+ const PPDKey* pOtherKey = pKey == pLeft ? pRight : pLeft;
+ const PPDValue* pOtherKeyOption = pKey == pLeft ? it->m_pOption2 : it->m_pOption1;
+ const PPDValue* pKeyOption = pKey == pLeft ? it->m_pOption1 : it->m_pOption2;
+
+ // syntax *Key1 option1 *Key2 option2
+ if( pKeyOption && pOtherKeyOption )
+ {
+ if( pNewValue != pKeyOption )
+ continue;
+ if( pOtherKeyOption == getValue( pOtherKey ) )
+ {
+ return false;
+ }
+ }
+ // syntax *Key1 option *Key2 or *Key1 *Key2 option
+ else if( pOtherKeyOption || pKeyOption )
+ {
+ if( pKeyOption )
+ {
+ if( ! ( pOtherKeyOption = getValue( pOtherKey ) ) )
+ continue; // this should not happen, PPD broken
+
+ if( pKeyOption == pNewValue &&
+ ! pOtherKeyOption->m_aOption.EqualsAscii( "None" ) &&
+ ! pOtherKeyOption->m_aOption.EqualsAscii( "False" ) )
+ {
+ // check if the other value can be reset and
+ // do so if possible
+ if( bDoReset && resetValue( pOtherKey ) )
+ continue;
+
+ return false;
+ }
+ }
+ else if( pOtherKeyOption )
+ {
+ if( getValue( pOtherKey ) == pOtherKeyOption &&
+ ! pNewValue->m_aOption.EqualsAscii( "None" ) &&
+ ! pNewValue->m_aOption.EqualsAscii( "False" ) )
+ return false;
+ }
+ else
+ {
+ // this should not happen, PPD is broken
+ }
+ }
+ // syntax *Key1 *Key2
+ else
+ {
+ const PPDValue* pOtherValue = getValue( pOtherKey );
+ if( ! pOtherValue->m_aOption.EqualsAscii( "None" ) &&
+ ! pOtherValue->m_aOption.EqualsAscii( "False" ) &&
+ ! pNewValue->m_aOption.EqualsAscii( "None" ) &&
+ ! pNewValue->m_aOption.EqualsAscii( "False" ) )
+ return false;
+ }
+ }
+ return true;
+}
+
+// -------------------------------------------------------------------
+
+void PPDContext::getUnconstrainedValues( const PPDKey* pKey, ::std::list< const PPDValue* >& rValues )
+{
+ rValues.clear();
+
+ if( ! m_pParser || ! pKey || ! m_pParser->hasKey( pKey ) )
+ return;
+
+ int nValues = pKey->countValues();
+ for( int i = 0; i < nValues; i++ )
+ {
+ const PPDValue* pValue = pKey->getValue( i );
+ if( checkConstraints( pKey, pValue ) )
+ rValues.push_back( pValue );
+ }
+}
+
+
+// -------------------------------------------------------------------
+
+void* PPDContext::getStreamableBuffer( sal_uLong& rBytes ) const
+{
+ rBytes = 0;
+ if( ! m_aCurrentValues.size() )
+ return NULL;
+ hash_type::const_iterator it;
+ for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end(); ++it )
+ {
+ ByteString aCopy( it->first->getKey(), RTL_TEXTENCODING_MS_1252 );
+ rBytes += aCopy.Len();
+ rBytes += 1; // for ':'
+ if( it->second )
+ {
+ aCopy = ByteString( it->second->m_aOption, RTL_TEXTENCODING_MS_1252 );
+ rBytes += aCopy.Len();
+ }
+ else
+ rBytes += 4;
+ rBytes += 1; // for '\0'
+ }
+ rBytes += 1;
+ void* pBuffer = new char[ rBytes ];
+ memset( pBuffer, 0, rBytes );
+ char* pRun = (char*)pBuffer;
+ for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end(); ++it )
+ {
+ ByteString aCopy( it->first->getKey(), RTL_TEXTENCODING_MS_1252 );
+ int nBytes = aCopy.Len();
+ memcpy( pRun, aCopy.GetBuffer(), nBytes );
+ pRun += nBytes;
+ *pRun++ = ':';
+ if( it->second )
+ aCopy = ByteString( it->second->m_aOption, RTL_TEXTENCODING_MS_1252 );
+ else
+ aCopy = "*nil";
+ nBytes = aCopy.Len();
+ memcpy( pRun, aCopy.GetBuffer(), nBytes );
+ pRun += nBytes;
+
+ *pRun++ = 0;
+ }
+ return pBuffer;
+}
+
+// -------------------------------------------------------------------
+
+void PPDContext::rebuildFromStreamBuffer( void* pBuffer, sal_uLong nBytes )
+{
+ if( ! m_pParser )
+ return;
+
+ m_aCurrentValues.clear();
+
+ char* pRun = (char*)pBuffer;
+ while( nBytes && *pRun )
+ {
+ ByteString aLine( pRun );
+ int nPos = aLine.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ {
+ const PPDKey* pKey = m_pParser->getKey( String( aLine.Copy( 0, nPos ), RTL_TEXTENCODING_MS_1252 ) );
+ if( pKey )
+ {
+ const PPDValue* pValue = NULL;
+ String aOption( aLine.Copy( nPos+1 ), RTL_TEXTENCODING_MS_1252 );
+ if( ! aOption.EqualsAscii( "*nil" ) )
+ pValue = pKey->getValue( aOption );
+ m_aCurrentValues[ pKey ] = pValue;
+#ifdef __DEBUG
+ fprintf( stderr, "PPDContext::rebuildFromStreamBuffer: read PPDKeyValue { %s, %s }\n", pKV->m_pKey->getKey().GetStr(), pKV->m_pCurrentValue ? pKV->m_pCurrentValue->m_aOption.GetStr() : "<nil>" );
+#endif
+ }
+ }
+ nBytes -= aLine.Len()+1;
+ pRun += aLine.Len()+1;
+ }
+}
+
+// -------------------------------------------------------------------
+
+int PPDContext::getRenderResolution() const
+{
+ // initialize to reasonable default, if parser is not set
+ int nDPI = 300;
+ if( m_pParser )
+ {
+ int nDPIx = 300, nDPIy = 300;
+ const PPDKey* pKey = m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ) );
+ if( pKey )
+ {
+ const PPDValue* pValue = getValue( pKey );
+ if( pValue )
+ m_pParser->getResolutionFromString( pValue->m_aOption, nDPIx, nDPIy );
+ else
+ m_pParser->getDefaultResolution( nDPIx, nDPIy );
+ }
+ else
+ m_pParser->getDefaultResolution( nDPIx, nDPIy );
+
+ nDPI = (nDPIx > nDPIy) ? nDPIx : nDPIy;
+ }
+ return nDPI;
+}
+
+// -------------------------------------------------------------------
+
+void PPDContext::getPageSize( String& rPaper, int& rWidth, int& rHeight ) const
+{
+ // initialize to reasonable default, if parser is not set
+ rPaper = String( RTL_CONSTASCII_USTRINGPARAM( "A4" ) );
+ rWidth = 595;
+ rHeight = 842;
+ if( m_pParser )
+ {
+ const PPDKey* pKey = m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ if( pKey )
+ {
+ const PPDValue* pValue = getValue( pKey );
+ if( pValue )
+ {
+ rPaper = pValue->m_aOption;
+ m_pParser->getPaperDimension( rPaper, rWidth, rHeight );
+ }
+ else
+ {
+ rPaper = m_pParser->getDefaultPaperDimension();
+ m_pParser->getDefaultPaperDimension( rWidth, rHeight );
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/printer/printerinfomanager.cxx b/vcl/unx/generic/printer/printerinfomanager.cxx
new file mode 100644
index 000000000000..4a7374c41b7b
--- /dev/null
+++ b/vcl/unx/generic/printer/printerinfomanager.cxx
@@ -0,0 +1,1438 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <unistd.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include "cupsmgr.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/strhelper.hxx"
+
+#include "unx/saldata.hxx"
+
+#include "tools/urlobj.hxx"
+#include "tools/stream.hxx"
+#include "tools/debug.hxx"
+#include "tools/config.hxx"
+
+#include "i18npool/paper.hxx"
+
+#include "rtl/strbuf.hxx"
+#include <sal/macros.h>
+
+#include "osl/thread.hxx"
+#include "osl/mutex.hxx"
+#include "osl/process.h"
+
+#include <boost/scoped_ptr.hpp>
+
+// filename of configuration files
+#define PRINT_FILENAME "psprint.conf"
+// the group of the global defaults
+#define GLOBAL_DEFAULTS_GROUP "__Global_Printer_Defaults__"
+
+#include <boost/unordered_set.hpp>
+
+using namespace psp;
+using namespace osl;
+
+using ::rtl::OUString;
+using ::rtl::OString;
+using ::rtl::OStringToOUString;
+using ::rtl::OUStringHash;
+
+namespace psp
+{
+ class SystemQueueInfo : public Thread
+ {
+ mutable Mutex m_aMutex;
+ bool m_bChanged;
+ std::list< PrinterInfoManager::SystemPrintQueue >
+ m_aQueues;
+ OUString m_aCommand;
+
+ virtual void run();
+
+ public:
+ SystemQueueInfo();
+ ~SystemQueueInfo();
+
+ bool hasChanged() const;
+ OUString getCommand() const;
+
+ // sets changed status to false; therefore not const
+ void getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues );
+ };
+} // namespace
+
+/*
+* class PrinterInfoManager
+*/
+
+// -----------------------------------------------------------------
+
+PrinterInfoManager& PrinterInfoManager::get()
+{
+ SalData* pSalData = GetSalData();
+
+ if( ! pSalData->m_pPIManager )
+ {
+ pSalData->m_pPIManager = CUPSManager::tryLoadCUPS();
+ if( ! pSalData->m_pPIManager )
+ pSalData->m_pPIManager = new PrinterInfoManager();
+
+ pSalData->m_pPIManager->initialize();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PrinterInfoManager::get create Manager of type %d\n", pSalData->m_pPIManager->getType() );
+#endif
+ }
+
+ return *pSalData->m_pPIManager;
+}
+
+void PrinterInfoManager::release()
+{
+ SalData* pSalData = GetSalData();
+ delete pSalData->m_pPIManager;
+ pSalData->m_pPIManager = NULL;
+}
+
+// -----------------------------------------------------------------
+
+PrinterInfoManager::PrinterInfoManager( Type eType ) :
+ m_pQueueInfo( NULL ),
+ m_eType( eType ),
+ m_bUseIncludeFeature( false ),
+ m_bUseJobPatch( true ),
+ m_aSystemDefaultPaper( RTL_CONSTASCII_USTRINGPARAM( "A4" ) ),
+ m_bDisableCUPS( false )
+{
+ if( eType == Default )
+ m_pQueueInfo = new SystemQueueInfo();
+ initSystemDefaultPaper();
+}
+
+// -----------------------------------------------------------------
+
+PrinterInfoManager::~PrinterInfoManager()
+{
+ delete m_pQueueInfo;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PrinterInfoManager: destroyed Manager of type %d\n", getType() );
+ #endif
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::isCUPSDisabled() const
+{
+ return m_bDisableCUPS;
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::setCUPSDisabled( bool bDisable )
+{
+ m_bDisableCUPS = bDisable;
+ writePrinterConfig();
+ // actually we know the printers changed
+ // however this triggers reinitialization the right way
+ checkPrintersChanged( true );
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::initSystemDefaultPaper()
+{
+ m_aSystemDefaultPaper = rtl::OStringToOUString(
+ PaperInfo::toPSName(PaperInfo::getSystemDefaultPaper().getPaper()),
+ RTL_TEXTENCODING_UTF8);
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::checkPrintersChanged( bool bWait )
+{
+ // check if files were created, deleted or modified since initialize()
+ ::std::list< WatchFile >::const_iterator it;
+ bool bChanged = false;
+ for( it = m_aWatchFiles.begin(); it != m_aWatchFiles.end() && ! bChanged; ++it )
+ {
+ DirectoryItem aItem;
+ if( DirectoryItem::get( it->m_aFilePath, aItem ) )
+ {
+ if( it->m_aModified.Seconds != 0 )
+ bChanged = true; // file probably has vanished
+ }
+ else
+ {
+ FileStatus aStatus( FileStatusMask_ModifyTime );
+ if( aItem.getFileStatus( aStatus ) )
+ bChanged = true; // unlikely but not impossible
+ else
+ {
+ TimeValue aModified = aStatus.getModifyTime();
+ if( aModified.Seconds != it->m_aModified.Seconds )
+ bChanged = true;
+ }
+ }
+ }
+
+ if( bWait && m_pQueueInfo )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "syncing printer discovery thread\n" );
+ #endif
+ m_pQueueInfo->join();
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "done: syncing printer discovery thread\n" );
+ #endif
+ }
+
+ if( ! bChanged && m_pQueueInfo )
+ bChanged = m_pQueueInfo->hasChanged();
+ if( bChanged )
+ {
+ initialize();
+ }
+
+ return bChanged;
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::initialize()
+{
+ m_bUseIncludeFeature = false;
+ rtl_TextEncoding aEncoding = gsl_getSystemTextEncoding();
+ m_aPrinters.clear();
+ m_aWatchFiles.clear();
+ OUString aDefaultPrinter;
+
+ // first initialize the global defaults
+ // have to iterate over all possible files
+ // there should be only one global setup section in all
+ // available config files
+ m_aGlobalDefaults = PrinterInfo();
+
+ // need a parser for the PPDContext. generic printer should do.
+ m_aGlobalDefaults.m_pParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) );
+ m_aGlobalDefaults.m_aContext.setParser( m_aGlobalDefaults.m_pParser );
+ m_aGlobalDefaults.m_bPerformFontSubstitution = true;
+ m_bDisableCUPS = false;
+
+ if( ! m_aGlobalDefaults.m_pParser )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Error: no default PPD file SGENPRT available, shutting down psprint...\n" );
+ #endif
+ return;
+ }
+
+ std::list< OUString > aDirList;
+ psp::getPrinterPathList( aDirList, NULL );
+ std::list< OUString >::const_iterator print_dir_it;
+ for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
+ {
+ INetURLObject aFile( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ aFile.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME ) ) );
+ Config aConfig( aFile.PathToFileName() );
+ if( aConfig.HasGroup( GLOBAL_DEFAULTS_GROUP ) )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found global defaults in %s\n", OUStringToOString( aFile.PathToFileName(), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ #endif
+ aConfig.SetGroup( GLOBAL_DEFAULTS_GROUP );
+
+ ByteString aValue( aConfig.ReadKey( "Copies" ) );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nCopies = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "Orientation" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait;
+
+ aValue = aConfig.ReadKey( "MarginAdjust" );
+ if( aValue.Len() )
+ {
+ m_aGlobalDefaults.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32();
+ m_aGlobalDefaults.m_nRightMarginAdjust = aValue.GetToken( 1, ',' ).ToInt32();
+ m_aGlobalDefaults.m_nTopMarginAdjust = aValue.GetToken( 2, ',' ).ToInt32();
+ m_aGlobalDefaults.m_nBottomMarginAdjust = aValue.GetToken( 3, ',' ).ToInt32();
+ }
+
+ aValue = aConfig.ReadKey( "ColorDepth", "24" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nColorDepth = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "ColorDevice" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nColorDevice = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PSLevel" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nPSLevel = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PDFDevice" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nPDFDevice = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PerformFontSubstitution" );
+ if( aValue.Len() )
+ {
+ if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) )
+ m_aGlobalDefaults.m_bPerformFontSubstitution = true;
+ else
+ m_aGlobalDefaults.m_bPerformFontSubstitution = false;
+ }
+
+ aValue = aConfig.ReadKey( "DisableCUPS" );
+ if( aValue.Len() )
+ {
+ if( aValue.Equals( "1" ) || aValue.EqualsIgnoreCaseAscii( "true" ) )
+ m_bDisableCUPS = true;
+ else
+ m_bDisableCUPS = false;
+ }
+
+ // get the PPDContext of global JobData
+ for( int nKey = 0; nKey < aConfig.GetKeyCount(); nKey++ )
+ {
+ ByteString aKey( aConfig.GetKeyName( nKey ) );
+ if( aKey.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL )
+ {
+ aValue = aConfig.ReadKey( aKey );
+ const PPDKey* pKey = m_aGlobalDefaults.m_pParser->getKey( String( aKey.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( pKey )
+ {
+ m_aGlobalDefaults.m_aContext.
+ setValue( pKey,
+ aValue.Equals( "*nil" ) ? NULL : pKey->getValue( String( aValue, RTL_TEXTENCODING_ISO_8859_1 ) ),
+ sal_True );
+ }
+ }
+ else if( aKey.Len() > 10 && aKey.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL )
+ {
+ aValue = aConfig.ReadKey( aKey );
+ m_aGlobalDefaults.m_aFontSubstitutes[ OStringToOUString( aKey.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1 ) ] = OStringToOUString( aValue, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "global settings: fontsubst = %s, %" SAL_PRI_SIZET "u substitutes\n", m_aGlobalDefaults.m_bPerformFontSubstitution ? "true" : "false", m_aGlobalDefaults.m_aFontSubstitutes.size() );
+ #endif
+ }
+ }
+ setDefaultPaper( m_aGlobalDefaults.m_aContext );
+ fillFontSubstitutions( m_aGlobalDefaults );
+
+ // now collect all available printers
+ for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
+ {
+ INetURLObject aDir( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ INetURLObject aFile( aDir );
+ aFile.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME ) ) );
+
+ // check directory validity
+ OUString aUniPath;
+ FileBase::getFileURLFromSystemPath( aDir.PathToFileName(), aUniPath );
+ Directory aDirectory( aUniPath );
+ if( aDirectory.open() )
+ continue;
+ aDirectory.close();
+
+
+ FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aUniPath );
+ FileStatus aStatus( FileStatusMask_ModifyTime );
+ DirectoryItem aItem;
+
+ // setup WatchFile list
+ WatchFile aWatchFile;
+ aWatchFile.m_aFilePath = aUniPath;
+ if( ! DirectoryItem::get( aUniPath, aItem ) &&
+ ! aItem.getFileStatus( aStatus ) )
+ {
+ aWatchFile.m_aModified = aStatus.getModifyTime();
+ }
+ else
+ {
+ aWatchFile.m_aModified.Seconds = 0;
+ aWatchFile.m_aModified.Nanosec = 0;
+ }
+ m_aWatchFiles.push_back( aWatchFile );
+
+ Config aConfig( aFile.PathToFileName() );
+ for( int nGroup = 0; nGroup < aConfig.GetGroupCount(); nGroup++ )
+ {
+ aConfig.SetGroup( aConfig.GetGroupName( nGroup ) );
+ ByteString aValue = aConfig.ReadKey( "Printer" );
+ if( aValue.Len() )
+ {
+ OUString aPrinterName;
+
+ int nNamePos = aValue.Search( '/' );
+ // check for valid value of "Printer"
+ if( nNamePos == STRING_NOTFOUND )
+ continue;
+
+ Printer aPrinter;
+ // initialize to global defaults
+ aPrinter.m_aInfo = m_aGlobalDefaults;
+ // global settings do not default the printer substitution
+ // list ! the substitution list in there is only used for
+ // newly created printers
+ aPrinter.m_aInfo.m_aFontSubstitutes.clear();
+ aPrinter.m_aInfo.m_aFontSubstitutions.clear();
+
+ aPrinterName = String( aValue.Copy( nNamePos+1 ), RTL_TEXTENCODING_UTF8 );
+ aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
+ aPrinter.m_aInfo.m_aDriverName = String( aValue.Copy( 0, nNamePos ), RTL_TEXTENCODING_UTF8 );
+
+ // set parser, merge settings
+ // don't do this for CUPS printers as this is done
+ // by the CUPS system itself
+ if( aPrinter.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) != 0 )
+ {
+ aPrinter.m_aInfo.m_pParser = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName );
+ aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser );
+ // note: setParser also purges the context
+
+ // ignore this printer if its driver is not found
+ if( ! aPrinter.m_aInfo.m_pParser )
+ continue;
+
+ // merge the ppd context keys if the printer has the same keys and values
+ // this is a bit tricky, since it involves mixing two PPDs
+ // without constraints which might end up badly
+ // this feature should be use with caution
+ // it is mainly to select default paper sizes for new printers
+ for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
+ {
+ const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
+ const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
+ const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
+ if( pDefKey && pPrinterKey )
+ // at least the options exist in both PPDs
+ {
+ if( pDefValue )
+ {
+ const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
+ if( pPrinterValue )
+ // the printer has a corresponding option for the key
+ aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
+ }
+ else
+ aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
+ }
+ }
+
+ aValue = aConfig.ReadKey( "Command" );
+ // no printer without a command
+ if( ! aValue.Len() )
+ {
+ /* TODO:
+ * porters: please append your platform to the Solaris
+ * case if your platform has SystemV printing per default.
+ */
+ #if defined SOLARIS
+ aValue = "lp";
+ #else
+ aValue = "lpr";
+ #endif
+ }
+ aPrinter.m_aInfo.m_aCommand = String( aValue, RTL_TEXTENCODING_UTF8 );
+ }
+
+ aValue = aConfig.ReadKey( "QuickCommand" );
+ aPrinter.m_aInfo.m_aQuickCommand = String( aValue, RTL_TEXTENCODING_UTF8 );
+
+ aValue = aConfig.ReadKey( "Features" );
+ aPrinter.m_aInfo.m_aFeatures = String( aValue, RTL_TEXTENCODING_UTF8 );
+
+ // override the settings in m_aGlobalDefaults if keys exist
+ aValue = aConfig.ReadKey( "DefaultPrinter" );
+ if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) )
+ aDefaultPrinter = aPrinterName;
+
+ aValue = aConfig.ReadKey( "Location" );
+ aPrinter.m_aInfo.m_aLocation = String( aValue, RTL_TEXTENCODING_UTF8 );
+
+ aValue = aConfig.ReadKey( "Comment" );
+ aPrinter.m_aInfo.m_aComment = String( aValue, RTL_TEXTENCODING_UTF8 );
+
+ aValue = aConfig.ReadKey( "Copies" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nCopies = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "Orientation" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait;
+
+ aValue = aConfig.ReadKey( "MarginAdjust" );
+ if( aValue.Len() )
+ {
+ aPrinter.m_aInfo.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32();
+ aPrinter.m_aInfo.m_nRightMarginAdjust = aValue.GetToken( 1, ',' ).ToInt32();
+ aPrinter.m_aInfo.m_nTopMarginAdjust = aValue.GetToken( 2, ',' ).ToInt32();
+ aPrinter.m_aInfo.m_nBottomMarginAdjust = aValue.GetToken( 3, ',' ).ToInt32();
+ }
+
+ aValue = aConfig.ReadKey( "ColorDepth" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nColorDepth = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "ColorDevice" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nColorDevice = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PSLevel" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nPSLevel = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PDFDevice" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nPDFDevice = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PerformFontSubstitution" );
+ if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) )
+ aPrinter.m_aInfo.m_bPerformFontSubstitution = true;
+ else
+ aPrinter.m_aInfo.m_bPerformFontSubstitution = false;
+
+ // now iterate over all keys to extract multi key information:
+ // 1. PPDContext information
+ // 2. Font substitution table
+ for( int nKey = 0; nKey < aConfig.GetKeyCount(); nKey++ )
+ {
+ ByteString aKey( aConfig.GetKeyName( nKey ) );
+ if( aKey.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL && aPrinter.m_aInfo.m_pParser )
+ {
+ aValue = aConfig.ReadKey( aKey );
+ const PPDKey* pKey = aPrinter.m_aInfo.m_pParser->getKey( String( aKey.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( pKey )
+ {
+ aPrinter.m_aInfo.m_aContext.
+ setValue( pKey,
+ aValue.Equals( "*nil" ) ? NULL : pKey->getValue( String( aValue, RTL_TEXTENCODING_ISO_8859_1 ) ),
+ sal_True );
+ }
+ }
+ else if( aKey.Len() > 10 && aKey.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL )
+ {
+ aValue = aConfig.ReadKey( aKey );
+ aPrinter.m_aInfo.m_aFontSubstitutes[ OStringToOUString( aKey.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1 ) ] = OStringToOUString( aValue, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ }
+
+ setDefaultPaper( aPrinter.m_aInfo.m_aContext );
+ fillFontSubstitutions( aPrinter.m_aInfo );
+
+ // finally insert printer
+ FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aPrinter.m_aFile );
+ aPrinter.m_bModified = false;
+ aPrinter.m_aGroup = aConfig.GetGroupName( nGroup );
+ boost::unordered_map< OUString, Printer, OUStringHash >::const_iterator find_it =
+ m_aPrinters.find( aPrinterName );
+ if( find_it != m_aPrinters.end() )
+ {
+ aPrinter.m_aAlternateFiles = find_it->second.m_aAlternateFiles;
+ aPrinter.m_aAlternateFiles.push_front( find_it->second.m_aFile );
+ }
+ m_aPrinters[ aPrinterName ] = aPrinter;
+ }
+ }
+ }
+
+ // set default printer
+ if( m_aPrinters.size() )
+ {
+ if( m_aPrinters.find( aDefaultPrinter ) == m_aPrinters.end() )
+ aDefaultPrinter = m_aPrinters.begin()->first;
+ }
+ else
+ aDefaultPrinter = OUString();
+ m_aDefaultPrinter = aDefaultPrinter;
+
+ if( m_eType != Default )
+ return;
+
+ // add a default printer for every available print queue
+ // merge paper and font substitution from default printer,
+ // all else from global defaults
+ PrinterInfo aMergeInfo( m_aGlobalDefaults );
+ aMergeInfo.m_aDriverName = String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) );
+ aMergeInfo.m_aFeatures = String( RTL_CONSTASCII_USTRINGPARAM( "autoqueue" ) );
+
+ if( m_aDefaultPrinter.getLength() )
+ {
+ PrinterInfo aDefaultInfo( getPrinterInfo( m_aDefaultPrinter ) );
+ aMergeInfo.m_bPerformFontSubstitution = aDefaultInfo.m_bPerformFontSubstitution;
+ fillFontSubstitutions( aMergeInfo );
+
+ const PPDKey* pDefKey = aDefaultInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ const PPDKey* pMergeKey = aMergeInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ const PPDValue* pDefValue = aDefaultInfo.m_aContext.getValue( pDefKey );
+ const PPDValue* pMergeValue = pMergeKey ? pMergeKey->getValue( pDefValue->m_aOption ) : NULL;
+ if( pMergeKey && pMergeValue )
+ aMergeInfo.m_aContext.setValue( pMergeKey, pMergeValue );
+ }
+
+ getSystemPrintQueues();
+ for( ::std::list< SystemPrintQueue >::iterator it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
+ {
+ String aPrinterName( RTL_CONSTASCII_USTRINGPARAM( "<" ) );
+ aPrinterName += String( it->m_aQueue );
+ aPrinterName.Append( '>' );
+
+ if( m_aPrinters.find( aPrinterName ) != m_aPrinters.end() )
+ // probably user made this one permanent in padmin
+ continue;
+
+ String aCmd( m_aSystemPrintCommand );
+ aCmd.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) ), it->m_aQueue );
+
+ Printer aPrinter;
+
+ // initialize to merged defaults
+ aPrinter.m_aInfo = aMergeInfo;
+ aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
+ aPrinter.m_aInfo.m_aCommand = aCmd;
+ aPrinter.m_aInfo.m_aComment = it->m_aComment;
+ aPrinter.m_aInfo.m_aLocation = it->m_aLocation;
+ aPrinter.m_bModified = false;
+ aPrinter.m_aGroup = ByteString( aPrinterName, aEncoding ); //provide group name in case user makes this one permanent in padmin
+
+ m_aPrinters[ aPrinterName ] = aPrinter;
+ }
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::listPrinters( ::std::list< OUString >& rList ) const
+{
+ ::boost::unordered_map< OUString, Printer, OUStringHash >::const_iterator it;
+ rList.clear();
+ for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
+ rList.push_back( it->first );
+}
+
+// -----------------------------------------------------------------
+
+const PrinterInfo& PrinterInfoManager::getPrinterInfo( const OUString& rPrinter ) const
+{
+ static PrinterInfo aEmptyInfo;
+ ::boost::unordered_map< OUString, Printer, OUStringHash >::const_iterator it = m_aPrinters.find( rPrinter );
+
+ DBG_ASSERT( it != m_aPrinters.end(), "Do not ask for info about nonexistent printers" );
+
+ return it != m_aPrinters.end() ? it->second.m_aInfo : aEmptyInfo;
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo )
+{
+ ::boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinter );
+
+ DBG_ASSERT( it != m_aPrinters.end(), "Do not change nonexistant printers" );
+
+ if( it != m_aPrinters.end() )
+ {
+ it->second.m_aInfo = rNewInfo;
+ // recalculate font substitutions
+ fillFontSubstitutions( it->second.m_aInfo );
+ it->second.m_bModified = true;
+ writePrinterConfig();
+ }
+}
+
+// -----------------------------------------------------------------
+
+// need to check writeability / creatability of config files
+static bool checkWriteability( const OUString& rUniPath )
+{
+ bool bRet = false;
+ OUString aSysPath;
+ FileBase::getSystemPathFromFileURL( rUniPath, aSysPath );
+ SvFileStream aStream( aSysPath, STREAM_READ | STREAM_WRITE );
+ if( aStream.IsOpen() && aStream.IsWritable() )
+ bRet = true;
+ return bRet;
+}
+
+bool PrinterInfoManager::writePrinterConfig()
+{
+ // find at least one writeable config
+ ::boost::unordered_map< OUString, Config*, OUStringHash > files;
+ ::boost::unordered_map< OUString, int, OUStringHash > rofiles;
+ ::boost::unordered_map< OUString, Config*, OUStringHash >::iterator file_it;
+
+ for( ::std::list< WatchFile >::const_iterator wit = m_aWatchFiles.begin(); wit != m_aWatchFiles.end(); ++wit )
+ {
+ if( checkWriteability( wit->m_aFilePath ) )
+ {
+ files[ wit->m_aFilePath ] = new Config( wit->m_aFilePath );
+ break;
+ }
+ }
+
+ if( files.empty() )
+ return false;
+
+ Config* pGlobal = files.begin()->second;
+ pGlobal->SetGroup( GLOBAL_DEFAULTS_GROUP );
+ pGlobal->WriteKey( "DisableCUPS", m_bDisableCUPS ? "true" : "false" );
+
+ ::boost::unordered_map< OUString, Printer, OUStringHash >::iterator it;
+ for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
+ {
+ if( ! it->second.m_bModified )
+ // printer was not changed, do nothing
+ continue;
+
+ // don't save autoqueue printers
+ sal_Int32 nIndex = 0;
+ bool bAutoQueue = false;
+ while( nIndex != -1 && ! bAutoQueue )
+ {
+ OUString aToken( it->second.m_aInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( aToken.getLength() && aToken.compareToAscii( "autoqueue" ) == 0 )
+ bAutoQueue = true;
+ }
+ if( bAutoQueue )
+ continue;
+
+ if( it->second.m_aFile.getLength() )
+ {
+ // check if file is writable
+ if( files.find( it->second.m_aFile ) == files.end() )
+ {
+ bool bInsertToNewFile = false;
+ // maybe it is simply not inserted yet
+ if( rofiles.find( it->second.m_aFile ) == rofiles.end() )
+ {
+ if( checkWriteability( it->second.m_aFile ) )
+ files[ it->second.m_aFile ] = new Config( it->second.m_aFile );
+ else
+ bInsertToNewFile = true;
+ }
+ else
+ bInsertToNewFile = true;
+ // original file is read only, insert printer in a new writeable file
+ if( bInsertToNewFile )
+ {
+ rofiles[ it->second.m_aFile ] = 1;
+ // update alternate file list
+ // the remove operation ensures uniqueness of each alternate
+ it->second.m_aAlternateFiles.remove( it->second.m_aFile );
+ it->second.m_aAlternateFiles.remove( files.begin()->first );
+ it->second.m_aAlternateFiles.push_front( it->second.m_aFile );
+ // update file
+ it->second.m_aFile = files.begin()->first;
+ }
+ }
+ }
+ else // a new printer, write it to the first file available
+ it->second.m_aFile = files.begin()->first;
+
+ if( ! it->second.m_aGroup.getLength() ) // probably a new printer
+ it->second.m_aGroup = OString( it->first.getStr(), it->first.getLength(), RTL_TEXTENCODING_UTF8 );
+
+ if( files.find( it->second.m_aFile ) != files.end() )
+ {
+ Config* pConfig = files[ it->second.m_aFile ];
+ pConfig->DeleteGroup( it->second.m_aGroup ); // else some old keys may remain
+ pConfig->SetGroup( it->second.m_aGroup );
+
+ ByteString aValue( String( it->second.m_aInfo.m_aDriverName ), RTL_TEXTENCODING_UTF8 );
+ aValue += '/';
+ aValue += ByteString( String( it->first ), RTL_TEXTENCODING_UTF8 );
+ pConfig->WriteKey( "Printer", aValue );
+ pConfig->WriteKey( "DefaultPrinter", it->first == m_aDefaultPrinter ? "1" : "0" );
+ pConfig->WriteKey( "Location", ByteString( String( it->second.m_aInfo.m_aLocation ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "Comment", ByteString( String( it->second.m_aInfo.m_aComment ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "Command", ByteString( String( it->second.m_aInfo.m_aCommand ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "QuickCommand", ByteString( String( it->second.m_aInfo.m_aQuickCommand ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "Features", ByteString( String( it->second.m_aInfo.m_aFeatures ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "Copies", ByteString::CreateFromInt32( it->second.m_aInfo.m_nCopies ) );
+ pConfig->WriteKey( "Orientation", it->second.m_aInfo.m_eOrientation == orientation::Landscape ? "Landscape" : "Portrait" );
+ pConfig->WriteKey( "PSLevel", ByteString::CreateFromInt32( it->second.m_aInfo.m_nPSLevel ) );
+ pConfig->WriteKey( "PDFDevice", ByteString::CreateFromInt32( it->second.m_aInfo.m_nPDFDevice ) );
+ pConfig->WriteKey( "ColorDevice", ByteString::CreateFromInt32( it->second.m_aInfo.m_nColorDevice ) );
+ pConfig->WriteKey( "ColorDepth", ByteString::CreateFromInt32( it->second.m_aInfo.m_nColorDepth ) );
+ aValue = ByteString::CreateFromInt32( it->second.m_aInfo.m_nLeftMarginAdjust );
+ aValue += ',';
+ aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nRightMarginAdjust );
+ aValue += ',';
+ aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nTopMarginAdjust );
+ aValue += ',';
+ aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nBottomMarginAdjust );
+ pConfig->WriteKey( "MarginAdjust", aValue );
+
+ if( it->second.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) != 0 )
+ {
+ // write PPDContext (not for CUPS)
+ for( int i = 0; i < it->second.m_aInfo.m_aContext.countValuesModified(); i++ )
+ {
+ const PPDKey* pKey = it->second.m_aInfo.m_aContext.getModifiedKey( i );
+ ByteString aKey( "PPD_" );
+ aKey += ByteString( pKey->getKey(), RTL_TEXTENCODING_ISO_8859_1 );
+
+ const PPDValue* pValue = it->second.m_aInfo.m_aContext.getValue( pKey );
+ aValue = pValue ? ByteString( pValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ) : ByteString( "*nil" );
+ pConfig->WriteKey( aKey, aValue );
+ }
+ }
+
+ // write font substitution table
+ pConfig->WriteKey( "PerformFontSubstitution", it->second.m_aInfo.m_bPerformFontSubstitution ? "true" : "false" );
+ for( ::boost::unordered_map< OUString, OUString, OUStringHash >::const_iterator subst = it->second.m_aInfo.m_aFontSubstitutes.begin();
+ subst != it->second.m_aInfo.m_aFontSubstitutes.end(); ++subst )
+ {
+ ByteString aKey( "SubstFont_" );
+ aKey.Append( OUStringToOString( subst->first, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ pConfig->WriteKey( aKey, OUStringToOString( subst->second, RTL_TEXTENCODING_ISO_8859_1 ) );
+ }
+ }
+ }
+
+ // get rid of Config objects. this also writes any changes
+ for( file_it = files.begin(); file_it != files.end(); ++file_it )
+ delete file_it->second;
+
+ return true;
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::addPrinter( const OUString& rPrinterName, const OUString& rDriverName )
+{
+ bool bSuccess = false;
+
+ const PPDParser* pParser = NULL;
+ if( m_aPrinters.find( rPrinterName ) == m_aPrinters.end() && ( pParser = PPDParser::getParser( rDriverName ) ) )
+ {
+ Printer aPrinter;
+ aPrinter.m_bModified = true;
+ aPrinter.m_aInfo = m_aGlobalDefaults;
+ aPrinter.m_aInfo.m_aDriverName = rDriverName;
+ aPrinter.m_aInfo.m_pParser = pParser;
+ aPrinter.m_aInfo.m_aContext.setParser( pParser );
+ aPrinter.m_aInfo.m_aPrinterName = rPrinterName;
+
+ fillFontSubstitutions( aPrinter.m_aInfo );
+ // merge PPD values with global defaults
+ for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
+ {
+ const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
+ const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
+ const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
+ if( pDefKey && pPrinterKey )
+ // at least the options exist in both PPDs
+ {
+ if( pDefValue )
+ {
+ const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
+ if( pPrinterValue )
+ // the printer has a corresponding option for the key
+ aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
+ }
+ else
+ aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
+ }
+ }
+
+ m_aPrinters[ rPrinterName ] = aPrinter;
+ bSuccess = true;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "new printer %s, level = %d, pdfdevice = %d, colordevice = %d, depth = %d\n",
+ OUStringToOString( rPrinterName, osl_getThreadTextEncoding() ).getStr(),
+ m_aPrinters[rPrinterName].m_aInfo.m_nPSLevel,
+ m_aPrinters[rPrinterName].m_aInfo.m_nPDFDevice,
+ m_aPrinters[rPrinterName].m_aInfo.m_nColorDevice,
+ m_aPrinters[rPrinterName].m_aInfo.m_nColorDepth );
+ #endif
+ // comment: logically one should writePrinterConfig() here
+ // but immediately after addPrinter() a changePrinterInfo()
+ // will follow (see padmin code), which writes it again,
+ // so we can currently save some performance here
+ }
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::removePrinter( const OUString& rPrinterName, bool bCheckOnly )
+{
+ bool bSuccess = true;
+
+ ::boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
+ if( it != m_aPrinters.end() )
+ {
+ if( it->second.m_aFile.getLength() )
+ {
+ // this printer already exists in a config file
+
+
+ // check writeability of config file(s)
+ if( ! checkWriteability( it->second.m_aFile ) )
+ bSuccess = false;
+ else
+ {
+ for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
+ file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
+ {
+ if( ! checkWriteability( *file_it ) )
+ bSuccess = false;
+ }
+ }
+ if( bSuccess && ! bCheckOnly )
+ {
+
+ Config aConfig( it->second.m_aFile );
+ aConfig.DeleteGroup( it->second.m_aGroup );
+ aConfig.Flush();
+ for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
+ file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
+ {
+ Config aAltConfig( *file_it );
+ aAltConfig.DeleteGroup( it->second.m_aGroup );
+ aAltConfig.Flush();
+ }
+ }
+ }
+ if( bSuccess && ! bCheckOnly )
+ {
+ m_aPrinters.erase( it );
+ // need this here because someone may call
+ // checkPrintersChanged after the removal
+ // but then other added printers were not flushed
+ // to disk, so they are discarded
+ writePrinterConfig();
+ }
+ }
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::setDefaultPrinter( const OUString& rPrinterName )
+{
+ bool bSuccess = false;
+
+ ::boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
+ if( it != m_aPrinters.end() )
+ {
+ bSuccess = true;
+ it->second.m_bModified = true;
+ if( ( it = m_aPrinters.find( m_aDefaultPrinter ) ) != m_aPrinters.end() )
+ it->second.m_bModified = true;
+ m_aDefaultPrinter = rPrinterName;
+ writePrinterConfig();
+ }
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------
+bool PrinterInfoManager::addOrRemovePossible() const
+{
+ return true;
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::fillFontSubstitutions( PrinterInfo& rInfo ) const
+{
+ PrintFontManager& rFontManager( PrintFontManager::get() );
+ rInfo.m_aFontSubstitutions.clear();
+
+ if( ! rInfo.m_bPerformFontSubstitution ||
+ ! rInfo.m_aFontSubstitutes.size() )
+ return;
+
+ ::std::list< FastPrintFontInfo > aFonts;
+ ::boost::unordered_map< OUString, ::std::list< FastPrintFontInfo >, OUStringHash > aPrinterFonts;
+ rFontManager.getFontListWithFastInfo( aFonts, rInfo.m_pParser );
+
+ // get builtin fonts
+ ::std::list< FastPrintFontInfo >::const_iterator it;
+ for( it = aFonts.begin(); it != aFonts.end(); ++it )
+ if( it->m_eType == fonttype::Builtin )
+ aPrinterFonts[ it->m_aFamilyName.toAsciiLowerCase() ].push_back( *it );
+
+ // map lower case, so build a local copy of the font substitutions
+ ::boost::unordered_map< OUString, OUString, OUStringHash > aSubstitutions;
+ ::boost::unordered_map< OUString, OUString, OUStringHash >::const_iterator subst;
+ for( subst = rInfo.m_aFontSubstitutes.begin(); subst != rInfo.m_aFontSubstitutes.end(); ++subst )
+ {
+ OUString aFamily( subst->first.toAsciiLowerCase() );
+ // first look if there is a builtin of this family
+ // in this case override the substitution table
+ if( aPrinterFonts.find( aFamily ) != aPrinterFonts.end() )
+ aSubstitutions[ aFamily ] = aFamily;
+ else
+ aSubstitutions[ aFamily ] = subst->second.toAsciiLowerCase();
+ }
+
+
+ // now find substitutions
+ for( it = aFonts.begin(); it != aFonts.end(); ++it )
+ {
+ if( it->m_eType != fonttype::Builtin )
+ {
+ OUString aFamily( it->m_aFamilyName.toAsciiLowerCase() );
+ subst = aSubstitutions.find( aFamily );
+ if( subst != aSubstitutions.end() )
+ {
+ // search a substitution
+ const ::std::list< FastPrintFontInfo >& rBuiltins( aPrinterFonts[ aSubstitutions[ aFamily ] ] );
+ ::std::list< FastPrintFontInfo >::const_iterator builtin;
+ int nLastMatch = -10000;
+ fontID nSubstitute = -1;
+ for( builtin = rBuiltins.begin(); builtin != rBuiltins.end(); ++builtin )
+ {
+ int nMatch = 0;
+ int nDiff;
+ if( builtin->m_eItalic == it->m_eItalic )
+ nMatch += 8000;
+
+ nDiff = builtin->m_eWeight - it->m_eWeight;
+ nDiff = nDiff < 0 ? -nDiff : nDiff;
+ nMatch += 4000 - 1000*nDiff;
+
+ nDiff = builtin->m_eWidth - it->m_eWidth;
+ nDiff = nDiff < 0 ? -nDiff : nDiff;
+ nMatch += 2000 - 500*nDiff;
+
+ if( nMatch > nLastMatch )
+ {
+ nLastMatch = nMatch;
+ nSubstitute = builtin->m_nID;
+ }
+ }
+ if( nSubstitute != -1 )
+ {
+ rInfo.m_aFontSubstitutions[ it->m_nID ] = nSubstitute;
+ #if OSL_DEBUG_LEVEL > 2
+ FastPrintFontInfo aInfo;
+ rFontManager.getFontFastInfo( nSubstitute, aInfo );
+ fprintf( stderr,
+ "substitute %s %s %d %d\n"
+ " -> %s %s %d %d\n",
+ OUStringToOString( it->m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ it->m_eItalic == italic::Upright ? "r" : it->m_eItalic == italic::Oblique ? "o" : it->m_eItalic == italic::Italic ? "i" : "u",
+ it->m_eWeight,
+ it->m_eWidth,
+
+ OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ aInfo.m_eItalic == italic::Upright ? "r" : aInfo.m_eItalic == italic::Oblique ? "o" : aInfo.m_eItalic == italic::Italic ? "i" : "u",
+ aInfo.m_eWeight,
+ aInfo.m_eWidth
+ );
+ #endif
+ }
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::getSystemPrintCommands( std::list< OUString >& rCommands )
+{
+ if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
+ {
+ m_aSystemPrintCommand = m_pQueueInfo->getCommand();
+ m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
+ delete m_pQueueInfo, m_pQueueInfo = NULL;
+ }
+
+ std::list< SystemPrintQueue >::const_iterator it;
+ rCommands.clear();
+ String aPrinterConst( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) );
+ for( it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
+ {
+ String aCmd( m_aSystemPrintCommand );
+ aCmd.SearchAndReplace( aPrinterConst, it->m_aQueue );
+ rCommands.push_back( aCmd );
+ }
+}
+
+const std::list< PrinterInfoManager::SystemPrintQueue >& PrinterInfoManager::getSystemPrintQueues()
+{
+ if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
+ {
+ m_aSystemPrintCommand = m_pQueueInfo->getCommand();
+ m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
+ delete m_pQueueInfo, m_pQueueInfo = NULL;
+ }
+
+ return m_aSystemPrintQueues;
+}
+
+bool PrinterInfoManager::checkFeatureToken( const rtl::OUString& rPrinterName, const char* pToken ) const
+{
+ const PrinterInfo& rPrinterInfo( getPrinterInfo( rPrinterName ) );
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ OUString aOuterToken = rPrinterInfo.m_aFeatures.getToken( 0, ',', nIndex );
+ sal_Int32 nInnerIndex = 0;
+ OUString aInnerToken = aOuterToken.getToken( 0, '=', nInnerIndex );
+ if( aInnerToken.equalsIgnoreAsciiCaseAscii( pToken ) )
+ return true;
+ }
+ return false;
+}
+
+FILE* PrinterInfoManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
+{
+ const PrinterInfo& rPrinterInfo = getPrinterInfo (rPrintername);
+ const rtl::OUString& rCommand = (bQuickCommand && rPrinterInfo.m_aQuickCommand.getLength() ) ?
+ rPrinterInfo.m_aQuickCommand : rPrinterInfo.m_aCommand;
+ rtl::OString aShellCommand = OUStringToOString (rCommand, RTL_TEXTENCODING_ISO_8859_1);
+ aShellCommand += rtl::OString( " 2>/dev/null" );
+
+ return popen (aShellCommand.getStr(), "w");
+}
+
+int PrinterInfoManager::endSpool( const OUString& /*rPrintername*/, const OUString& /*rJobTitle*/, FILE* pFile, const JobData& /*rDocumentJobData*/, bool /*bBanner*/ )
+{
+ return (0 == pclose( pFile ));
+}
+
+void PrinterInfoManager::setupJobContextData( JobData& rData )
+{
+ boost::unordered_map< OUString, Printer, OUStringHash >::iterator it =
+ m_aPrinters.find( rData.m_aPrinterName );
+ if( it != m_aPrinters.end() )
+ {
+ rData.m_pParser = it->second.m_aInfo.m_pParser;
+ rData.m_aContext = it->second.m_aInfo.m_aContext;
+ }
+}
+
+void PrinterInfoManager::setDefaultPaper( PPDContext& rContext ) const
+{
+ if( ! rContext.getParser() )
+ return;
+
+ const PPDKey* pPageSizeKey = rContext.getParser()->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ if( ! pPageSizeKey )
+ return;
+
+ int nModified = rContext.countValuesModified();
+ while( nModified-- &&
+ rContext.getModifiedKey( nModified ) != pPageSizeKey )
+ ;
+
+ if( nModified >= 0 ) // paper was set already, do not modify
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "not setting default paper, already set %s\n",
+ OUStringToOString( rContext.getValue( pPageSizeKey )->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ #endif
+ return;
+ }
+
+ // paper not set, fill in default value
+ const PPDValue* pPaperVal = NULL;
+ int nValues = pPageSizeKey->countValues();
+ for( int i = 0; i < nValues && ! pPaperVal; i++ )
+ {
+ const PPDValue* pVal = pPageSizeKey->getValue( i );
+ if( pVal->m_aOption.EqualsIgnoreCaseAscii( m_aSystemDefaultPaper.getStr() ) )
+ pPaperVal = pVal;
+ }
+ if( pPaperVal )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "setting default paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ #endif
+ rContext.setValue( pPageSizeKey, pPaperVal );
+ #if OSL_DEBUG_LEVEL > 1
+ pPaperVal = rContext.getValue( pPageSizeKey );
+ fprintf( stderr, "-> got paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ #endif
+ }
+}
+
+// -----------------------------------------------------------------
+
+SystemQueueInfo::SystemQueueInfo() :
+ m_bChanged( false )
+{
+ create();
+}
+
+SystemQueueInfo::~SystemQueueInfo()
+{
+ static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
+ if( ! pNoSyncDetection || !*pNoSyncDetection )
+ join();
+ else
+ terminate();
+}
+
+bool SystemQueueInfo::hasChanged() const
+{
+ MutexGuard aGuard( m_aMutex );
+ bool bChanged = m_bChanged;
+ return bChanged;
+}
+
+void SystemQueueInfo::getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues )
+{
+ MutexGuard aGuard( m_aMutex );
+ rQueues = m_aQueues;
+ m_bChanged = false;
+}
+
+OUString SystemQueueInfo::getCommand() const
+{
+ MutexGuard aGuard( m_aMutex );
+ OUString aRet = m_aCommand;
+ return aRet;
+}
+
+struct SystemCommandParameters;
+typedef void(* tokenHandler)(const std::list< rtl::OString >&,
+ std::list< PrinterInfoManager::SystemPrintQueue >&,
+ const SystemCommandParameters*);
+
+struct SystemCommandParameters
+{
+ const char* pQueueCommand;
+ const char* pPrintCommand;
+ const char* pForeToken;
+ const char* pAftToken;
+ unsigned int nForeTokenCount;
+ tokenHandler pHandler;
+};
+
+#if ! (defined(LINUX) || defined(NETBSD) || defined(FREEBSD) || defined(OPENBSD))
+static void lpgetSysQueueTokenHandler(
+ const std::list< rtl::OString >& i_rLines,
+ std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
+ const SystemCommandParameters* )
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ boost::unordered_set< OUString, OUStringHash > aUniqueSet;
+ boost::unordered_set< OUString, OUStringHash > aOnlySet;
+ aUniqueSet.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_all" ) ) );
+ aUniqueSet.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
+
+ // the eventual "all" attribute of the "_all" queue tells us, which
+ // printers are to be used for this user at all
+
+ // find _all: line
+ rtl::OString aAllLine( "_all:" );
+ rtl::OString aAllAttr( "all=" );
+ for( std::list< rtl::OString >::const_iterator it = i_rLines.begin();
+ it != i_rLines.end(); ++it )
+ {
+ if( it->indexOf( aAllLine, 0 ) == 0 )
+ {
+ // now find the "all" attribute
+ ++it;
+ while( it != i_rLines.end() )
+ {
+ rtl::OString aClean( WhitespaceToSpace( *it ) );
+ if( aClean.indexOf( aAllAttr, 0 ) == 0 )
+ {
+ // insert the comma separated entries into the set of printers to use
+ sal_Int32 nPos = aAllAttr.getLength();
+ while( nPos != -1 )
+ {
+ OString aTok( aClean.getToken( 0, ',', nPos ) );
+ if( aTok.getLength() > 0 )
+ aOnlySet.insert( rtl::OStringToOUString( aTok, aEncoding ) );
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ bool bInsertAttribute = false;
+ rtl::OString aDescrStr( "description=" );
+ rtl::OString aLocStr( "location=" );
+ for( std::list< rtl::OString >::const_iterator it = i_rLines.begin();
+ it != i_rLines.end(); ++it )
+ {
+ sal_Int32 nPos = 0;
+ // find the begin of a new printer section
+ nPos = it->indexOf( ':', 0 );
+ if( nPos != -1 )
+ {
+ OUString aSysQueue( rtl::OStringToOUString( it->copy( 0, nPos ), aEncoding ) );
+ // do not insert duplicates (e.g. lpstat tends to produce such lines)
+ // in case there was a "_all" section, insert only those printer explicitly
+ // set in the "all" attribute
+ if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() &&
+ ( aOnlySet.empty() || aOnlySet.find( aSysQueue ) != aOnlySet.end() )
+ )
+ {
+ o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
+ o_rQueues.back().m_aQueue = aSysQueue;
+ o_rQueues.back().m_aLocation = aSysQueue;
+ aUniqueSet.insert( aSysQueue );
+ bInsertAttribute = true;
+ }
+ else
+ bInsertAttribute = false;
+ continue;
+ }
+ if( bInsertAttribute && ! o_rQueues.empty() )
+ {
+ // look for "description" attribute, insert as comment
+ nPos = it->indexOf( aDescrStr, 0 );
+ if( nPos != -1 )
+ {
+ ByteString aComment( WhitespaceToSpace( it->copy(nPos+12) ) );
+ if( aComment.Len() > 0 )
+ o_rQueues.back().m_aComment = String( aComment, aEncoding );
+ continue;
+ }
+ // look for "location" attribute, inser as location
+ nPos = it->indexOf( aLocStr, 0 );
+ if( nPos != -1 )
+ {
+ ByteString aLoc( WhitespaceToSpace( it->copy(nPos+9) ) );
+ if( aLoc.Len() > 0 )
+ o_rQueues.back().m_aLocation = String( aLoc, aEncoding );
+ continue;
+ }
+ }
+ }
+}
+#endif
+static void standardSysQueueTokenHandler(
+ const std::list< rtl::OString >& i_rLines,
+ std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
+ const SystemCommandParameters* i_pParms)
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ boost::unordered_set< OUString, OUStringHash > aUniqueSet;
+ rtl::OString aForeToken( i_pParms->pForeToken );
+ rtl::OString aAftToken( i_pParms->pAftToken );
+ /* Normal Unix print queue discovery, also used for Darwin 5 LPR printing
+ */
+ for( std::list< rtl::OString >::const_iterator it = i_rLines.begin();
+ it != i_rLines.end(); ++it )
+ {
+ sal_Int32 nPos = 0;
+
+ // search for a line describing a printer:
+ // find if there are enough tokens before the name
+ for( unsigned int i = 0; i < i_pParms->nForeTokenCount && nPos != -1; i++ )
+ {
+ nPos = it->indexOf( aForeToken, nPos );
+ if( nPos != -1 && it->getLength() >= nPos+aForeToken.getLength() )
+ nPos += aForeToken.getLength();
+ }
+ if( nPos != -1 )
+ {
+ // find if there is the token after the queue
+ sal_Int32 nAftPos = it->indexOf( aAftToken, nPos );
+ if( nAftPos != -1 )
+ {
+ // get the queue name between fore and aft tokens
+ OUString aSysQueue( rtl::OStringToOUString( it->copy( nPos, nAftPos - nPos ), aEncoding ) );
+ // do not insert duplicates (e.g. lpstat tends to produce such lines)
+ if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() )
+ {
+ o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
+ o_rQueues.back().m_aQueue = aSysQueue;
+ o_rQueues.back().m_aLocation = aSysQueue;
+ aUniqueSet.insert( aSysQueue );
+ }
+ }
+ }
+ }
+}
+
+static const struct SystemCommandParameters aParms[] =
+{
+ #if defined(LINUX) || defined(NETBSD) || defined(FREEBSD) || defined(OPENBSD)
+ { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
+ { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
+ { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler }
+ #else
+ { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpget list", "lp -d \"(PRINTER)\"", "", ":", 0, lpgetSysQueueTokenHandler },
+ { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler },
+ { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
+ { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }
+ #endif
+};
+
+void SystemQueueInfo::run()
+{
+ char pBuffer[1024];
+ FILE *pPipe;
+ std::list< rtl::OString > aLines;
+
+ /* Discover which command we can use to get a list of all printer queues */
+ for( unsigned int i = 0; i < SAL_N_ELEMENTS(aParms); i++ )
+ {
+ aLines.clear();
+ rtl::OStringBuffer aCmdLine( 128 );
+ aCmdLine.append( aParms[i].pQueueCommand );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "trying print queue command \"%s\" ... ", aParms[i].pQueueCommand );
+ #endif
+ aCmdLine.append( " 2>/dev/null" );
+ if( (pPipe = popen( aCmdLine.getStr(), "r" )) )
+ {
+ while( fgets( pBuffer, 1024, pPipe ) )
+ aLines.push_back( rtl::OString( pBuffer ) );
+ if( ! pclose( pPipe ) )
+ {
+ std::list< PrinterInfoManager::SystemPrintQueue > aSysPrintQueues;
+ aParms[i].pHandler( aLines, aSysPrintQueues, &(aParms[i]) );
+ MutexGuard aGuard( m_aMutex );
+ m_bChanged = true;
+ m_aQueues = aSysPrintQueues;
+ m_aCommand = rtl::OUString::createFromAscii( aParms[i].pPrintCommand );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "success\n" );
+ #endif
+ break;
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "failed\n" );
+ #endif
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/printergfx/bitmap_gfx.cxx b/vcl/unx/generic/printergfx/bitmap_gfx.cxx
new file mode 100644
index 000000000000..0c139678f8ab
--- /dev/null
+++ b/vcl/unx/generic/printergfx/bitmap_gfx.cxx
@@ -0,0 +1,735 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 "psputil.hxx"
+
+#include "printergfx.hxx"
+#include "vcl/strhelper.hxx"
+
+namespace psp {
+
+const sal_uInt32 nLineLength = 80;
+const sal_uInt32 nBufferSize = 16384;
+
+/*
+ *
+ * Bitmap compression / Hex encoding / Ascii85 Encoding
+ *
+ */
+
+PrinterBmp::~PrinterBmp ()
+{ /* dont need this, but C50 does */ }
+
+/* virtual base class */
+
+class ByteEncoder
+{
+private:
+
+public:
+
+ virtual void EncodeByte (sal_uInt8 nByte) = 0;
+ virtual ~ByteEncoder () = 0;
+};
+
+ByteEncoder::~ByteEncoder ()
+{ /* dont need this, but the C50 does */ }
+
+/* HexEncoder */
+
+class HexEncoder : public ByteEncoder
+{
+private:
+
+ osl::File* mpFile;
+ sal_uInt32 mnColumn;
+ sal_uInt32 mnOffset;
+ sal_Char mpFileBuffer[nBufferSize + 16];
+
+ HexEncoder (); /* dont use */
+
+public:
+
+ HexEncoder (osl::File* pFile);
+ virtual ~HexEncoder ();
+ void WriteAscii (sal_uInt8 nByte);
+ virtual void EncodeByte (sal_uInt8 nByte);
+ void FlushLine ();
+};
+
+HexEncoder::HexEncoder (osl::File* pFile) :
+ mpFile (pFile),
+ mnColumn (0),
+ mnOffset (0)
+{}
+
+HexEncoder::~HexEncoder ()
+{
+ FlushLine ();
+ if (mnColumn > 0)
+ WritePS (mpFile, "\n");
+}
+
+void
+HexEncoder::WriteAscii (sal_uInt8 nByte)
+{
+ sal_uInt32 nOff = psp::getHexValueOf (nByte, mpFileBuffer + mnOffset);
+ mnColumn += nOff;
+ mnOffset += nOff;
+
+ if (mnColumn >= nLineLength)
+ {
+ mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
+ mnColumn = 0;
+ }
+ if (mnOffset >= nBufferSize)
+ FlushLine ();
+}
+
+void
+HexEncoder::EncodeByte (sal_uInt8 nByte)
+{
+ WriteAscii (nByte);
+}
+
+void
+HexEncoder::FlushLine ()
+{
+ if (mnOffset > 0)
+ {
+ WritePS (mpFile, mpFileBuffer, mnOffset);
+ mnOffset = 0;
+ }
+}
+
+/* Ascii85 encoder, is abi compatible with HexEncoder but writes a ~> to
+ indicate end of data EOD */
+
+class Ascii85Encoder : public ByteEncoder
+{
+private:
+
+ osl::File* mpFile;
+ sal_uInt32 mnByte;
+ sal_uInt8 mpByteBuffer[4];
+
+ sal_uInt32 mnColumn;
+ sal_uInt32 mnOffset;
+ sal_Char mpFileBuffer[nBufferSize + 16];
+
+ Ascii85Encoder (); /* dont use */
+
+ inline void PutByte (sal_uInt8 nByte);
+ inline void PutEOD ();
+ void ConvertToAscii85 ();
+ void FlushLine ();
+
+public:
+
+ Ascii85Encoder (osl::File* pFile);
+ virtual ~Ascii85Encoder ();
+ virtual void EncodeByte (sal_uInt8 nByte);
+ void WriteAscii (sal_uInt8 nByte);
+};
+
+Ascii85Encoder::Ascii85Encoder (osl::File* pFile) :
+ mpFile (pFile),
+ mnByte (0),
+ mnColumn (0),
+ mnOffset (0)
+{}
+
+inline void
+Ascii85Encoder::PutByte (sal_uInt8 nByte)
+{
+ mpByteBuffer [mnByte++] = nByte;
+}
+
+inline void
+Ascii85Encoder::PutEOD ()
+{
+ WritePS (mpFile, "~>\n");
+}
+
+void
+Ascii85Encoder::ConvertToAscii85 ()
+{
+ if (mnByte < 4)
+ std::memset (mpByteBuffer + mnByte, 0, (4 - mnByte) * sizeof(sal_uInt8));
+
+ sal_uInt32 nByteValue = mpByteBuffer[0] * 256 * 256 * 256
+ + mpByteBuffer[1] * 256 * 256
+ + mpByteBuffer[2] * 256
+ + mpByteBuffer[3];
+
+ if (nByteValue == 0 && mnByte == 4)
+ {
+ /* special case of 4 Bytes in row */
+ mpFileBuffer [mnOffset] = 'z';
+
+ mnOffset += 1;
+ mnColumn += 1;
+ }
+ else
+ {
+ /* real ascii85 encoding */
+ mpFileBuffer [mnOffset + 4] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 3] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 2] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 1] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 0] = (nByteValue % 85) + 33;
+
+ mnColumn += (mnByte + 1);
+ mnOffset += (mnByte + 1);
+
+ /* insert a newline if necessary */
+ if (mnColumn > nLineLength)
+ {
+ sal_uInt32 nEolOff = mnColumn - nLineLength;
+ sal_uInt32 nBufOff = mnOffset - nEolOff;
+
+ std::memmove (mpFileBuffer + nBufOff + 1, mpFileBuffer + nBufOff, nEolOff);
+ mpFileBuffer[ nBufOff ] = '\n';
+
+ mnOffset++;
+ mnColumn = nEolOff;
+ }
+ }
+
+ mnByte = 0;
+}
+
+void
+Ascii85Encoder::WriteAscii (sal_uInt8 nByte)
+{
+ PutByte (nByte);
+ if (mnByte == 4)
+ ConvertToAscii85 ();
+
+ if (mnColumn >= nLineLength)
+ {
+ mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
+ mnColumn = 0;
+ }
+ if (mnOffset >= nBufferSize)
+ FlushLine ();
+}
+
+void
+Ascii85Encoder::EncodeByte (sal_uInt8 nByte)
+{
+ WriteAscii (nByte);
+}
+
+void
+Ascii85Encoder::FlushLine ()
+{
+ if (mnOffset > 0)
+ {
+ WritePS (mpFile, mpFileBuffer, mnOffset);
+ mnOffset = 0;
+ }
+}
+
+Ascii85Encoder::~Ascii85Encoder ()
+{
+ if (mnByte > 0)
+ ConvertToAscii85 ();
+ if (mnOffset > 0)
+ FlushLine ();
+ PutEOD ();
+}
+
+/* LZW encoder */
+
+class LZWEncoder : public Ascii85Encoder
+{
+private:
+
+ struct LZWCTreeNode
+ {
+ LZWCTreeNode* mpBrother; // next node with same parent
+ LZWCTreeNode* mpFirstChild; // first son
+ sal_uInt16 mnCode; // code for the string
+ sal_uInt16 mnValue; // pixelvalue
+ };
+
+ LZWCTreeNode* mpTable; // LZW compression data
+ LZWCTreeNode* mpPrefix; // the compression is as same as the TIFF compression
+ sal_uInt16 mnDataSize;
+ sal_uInt16 mnClearCode;
+ sal_uInt16 mnEOICode;
+ sal_uInt16 mnTableSize;
+ sal_uInt16 mnCodeSize;
+ sal_uInt32 mnOffset;
+ sal_uInt32 mdwShift;
+
+ LZWEncoder ();
+ void WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen);
+
+public:
+
+ LZWEncoder (osl::File* pOutputFile);
+ ~LZWEncoder ();
+
+ virtual void EncodeByte (sal_uInt8 nByte);
+};
+
+LZWEncoder::LZWEncoder(osl::File* pOutputFile) :
+ Ascii85Encoder (pOutputFile)
+{
+ mnDataSize = 8;
+
+ mnClearCode = 1 << mnDataSize;
+ mnEOICode = mnClearCode + 1;
+ mnTableSize = mnEOICode + 1;
+ mnCodeSize = mnDataSize + 1;
+
+ mnOffset = 32; // free bits in dwShift
+ mdwShift = 0;
+
+ mpTable = new LZWCTreeNode[ 4096 ];
+
+ for (sal_uInt32 i = 0; i < 4096; i++)
+ {
+ mpTable[i].mpBrother = NULL;
+ mpTable[i].mpFirstChild = NULL;
+ mpTable[i].mnCode = i;
+ mpTable[i].mnValue = (sal_uInt8)mpTable[i].mnCode;
+ }
+
+ mpPrefix = NULL;
+
+ WriteBits( mnClearCode, mnCodeSize );
+}
+
+LZWEncoder::~LZWEncoder()
+{
+ if (mpPrefix)
+ WriteBits (mpPrefix->mnCode, mnCodeSize);
+
+ WriteBits (mnEOICode, mnCodeSize);
+
+ delete[] mpTable;
+}
+
+void
+LZWEncoder::WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen)
+{
+ mdwShift |= (nCode << (mnOffset - nCodeLen));
+ mnOffset -= nCodeLen;
+ while (mnOffset < 24)
+ {
+ WriteAscii ((sal_uInt8)(mdwShift >> 24));
+ mdwShift <<= 8;
+ mnOffset += 8;
+ }
+ if (nCode == 257 && mnOffset != 32)
+ WriteAscii ((sal_uInt8)(mdwShift >> 24));
+}
+
+void
+LZWEncoder::EncodeByte (sal_uInt8 nByte )
+{
+ LZWCTreeNode* p;
+ sal_uInt16 i;
+ sal_uInt8 nV;
+
+ if (!mpPrefix)
+ {
+ mpPrefix = mpTable + nByte;
+ }
+ else
+ {
+ nV = nByte;
+ for (p = mpPrefix->mpFirstChild; p != NULL; p = p->mpBrother)
+ {
+ if (p->mnValue == nV)
+ break;
+ }
+
+ if (p != NULL)
+ {
+ mpPrefix = p;
+ }
+ else
+ {
+ WriteBits (mpPrefix->mnCode, mnCodeSize);
+
+ if (mnTableSize == 409)
+ {
+ WriteBits (mnClearCode, mnCodeSize);
+
+ for (i = 0; i < mnClearCode; i++)
+ mpTable[i].mpFirstChild = NULL;
+
+ mnCodeSize = mnDataSize + 1;
+ mnTableSize = mnEOICode + 1;
+ }
+ else
+ {
+ if(mnTableSize == (sal_uInt16)((1 << mnCodeSize) - 1))
+ mnCodeSize++;
+
+ p = mpTable + (mnTableSize++);
+ p->mpBrother = mpPrefix->mpFirstChild;
+ mpPrefix->mpFirstChild = p;
+ p->mnValue = nV;
+ p->mpFirstChild = NULL;
+ }
+
+ mpPrefix = mpTable + nV;
+ }
+ }
+}
+
+/*
+ *
+ * bitmap handling routines
+ *
+ */
+
+void
+PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp& rBitmap)
+{
+ double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
+ double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
+
+ PSGSave ();
+ PSTranslate (rDest.BottomLeft());
+ PSScale (fScaleX, fScaleY);
+
+ if (mnPSLevel >= 2)
+ {
+ if (rBitmap.GetDepth() == 1)
+ {
+ DrawPS2MonoImage (rBitmap, rSrc);
+ }
+ else
+ if (rBitmap.GetDepth() == 8 && mbColor)
+ {
+ // if the palette is larger than the image itself print it as a truecolor
+ // image to save diskspace. This is important for printing transparent
+ // bitmaps that are disassembled into small pieces
+ sal_Int32 nImageSz = rSrc.GetWidth() * rSrc.GetHeight();
+ sal_Int32 nPaletteSz = rBitmap.GetPaletteEntryCount();
+ if ((nImageSz < nPaletteSz) || (nImageSz < 24) )
+ DrawPS2TrueColorImage (rBitmap, rSrc);
+ else
+ DrawPS2PaletteImage (rBitmap, rSrc);
+ }
+ else
+ if (rBitmap.GetDepth() == 24 && mbColor)
+ {
+ DrawPS2TrueColorImage (rBitmap, rSrc);
+ }
+ else
+ {
+ DrawPS2GrayImage (rBitmap, rSrc);
+ }
+ }
+ else
+ {
+ DrawPS1GrayImage (rBitmap, rSrc);
+ }
+
+ PSGRestore ();
+}
+
+/* XXX does not work XXX */
+void
+PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp& /*rBitmap*/, const PrinterBmp& /*rTransBitmap*/)
+{
+ double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
+ double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
+
+ PSGSave ();
+ PSTranslate (rDest.BottomLeft());
+ PSScale (fScaleX, fScaleY);
+ PSGRestore ();
+}
+
+/* XXX does not work XXX */
+void
+PrinterGfx::DrawMask (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp &/*rBitmap*/, PrinterColor& /*rMaskColor*/)
+{
+ double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
+ double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
+
+ PSGSave ();
+ PSTranslate (rDest.BottomLeft());
+ PSScale (fScaleX, fScaleY);
+ PSGRestore ();
+}
+
+/*
+ *
+ * Implementation: PS Level 1
+ *
+ */
+
+void
+PrinterGfx::DrawPS1GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ sal_uInt32 nWidth = rArea.GetWidth();
+ sal_uInt32 nHeight = rArea.GetHeight();
+
+ sal_Char pGrayImage [512];
+ sal_Int32 nChar = 0;
+
+ // image header
+ nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
+ nChar += psp::appendStr (" ", pGrayImage + nChar);
+ nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
+ nChar += psp::appendStr (" 8 ", pGrayImage + nChar);
+ nChar += psp::appendStr ("[ 1 0 0 1 0 ", pGrayImage + nChar);
+ nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
+ nChar += psp::appendStr ("]", pGrayImage + nChar);
+ nChar += psp::appendStr (" {currentfile ", pGrayImage + nChar);
+ nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
+ nChar += psp::appendStr (" string readhexstring pop}\n", pGrayImage + nChar);
+ nChar += psp::appendStr ("image\n", pGrayImage + nChar);
+
+ WritePS (mpPageBody, pGrayImage);
+
+ // image body
+ HexEncoder* pEncoder = new HexEncoder (mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn);
+ pEncoder->EncodeByte (nByte);
+ }
+ }
+
+ delete pEncoder;
+
+ WritePS (mpPageBody, "\n");
+}
+
+/*
+ *
+ * Implementation: PS Level 2
+ *
+ */
+
+void
+PrinterGfx::writePS2ImageHeader (const Rectangle& rArea, psp::ImageType nType)
+{
+ sal_Int32 nChar = 0;
+ sal_Char pImage [512];
+
+ sal_Int32 nDictType = 0;
+ switch (nType)
+ {
+ case psp::TrueColorImage: nDictType = 0; break;
+ case psp::PaletteImage: nDictType = 1; break;
+ case psp::GrayScaleImage: nDictType = 2; break;
+ case psp::MonochromeImage: nDictType = 3; break;
+ default: break;
+ }
+ sal_Int32 nCompressType = mbCompressBmp ? 1 : 0;
+
+ nChar += psp::getValueOf (rArea.GetWidth(), pImage + nChar);
+ nChar += psp::appendStr (" ", pImage + nChar);
+ nChar += psp::getValueOf (rArea.GetHeight(), pImage + nChar);
+ nChar += psp::appendStr (" ", pImage + nChar);
+ nChar += psp::getValueOf (nDictType, pImage + nChar);
+ nChar += psp::appendStr (" ", pImage + nChar);
+ nChar += psp::getValueOf (nCompressType, pImage + nChar);
+ nChar += psp::appendStr (" psp_imagedict image\n", pImage + nChar);
+
+ WritePS (mpPageBody, pImage);
+}
+
+void
+PrinterGfx::writePS2Colorspace(const PrinterBmp& rBitmap, psp::ImageType nType)
+{
+ switch (nType)
+ {
+ case psp::GrayScaleImage:
+
+ WritePS (mpPageBody, "/DeviceGray setcolorspace\n");
+ break;
+
+ case psp::TrueColorImage:
+
+ WritePS (mpPageBody, "/DeviceRGB setcolorspace\n");
+ break;
+
+ case psp::MonochromeImage:
+ case psp::PaletteImage:
+ {
+
+ sal_Int32 nChar = 0;
+ sal_Char pImage [4096];
+
+ const sal_uInt32 nSize = rBitmap.GetPaletteEntryCount();
+
+ nChar += psp::appendStr ("[/Indexed /DeviceRGB ", pImage + nChar);
+ nChar += psp::getValueOf (nSize - 1, pImage + nChar);
+ if (mbCompressBmp)
+ nChar += psp::appendStr ("\npsp_lzwstring\n", pImage + nChar);
+ else
+ nChar += psp::appendStr ("\npsp_ascii85string\n", pImage + nChar);
+ WritePS (mpPageBody, pImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+ for (sal_uInt32 i = 0; i < nSize; i++)
+ {
+ PrinterColor aColor = rBitmap.GetPaletteColor(i);
+
+ pEncoder->EncodeByte (aColor.GetRed());
+ pEncoder->EncodeByte (aColor.GetGreen());
+ pEncoder->EncodeByte (aColor.GetBlue());
+ }
+ delete pEncoder;
+
+ WritePS (mpPageBody, "pop ] setcolorspace\n");
+ }
+ break;
+ default: break;
+ }
+}
+
+void
+PrinterGfx::DrawPS2GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::GrayScaleImage);
+ writePS2ImageHeader(rArea, psp::GrayScaleImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn);
+ pEncoder->EncodeByte (nByte);
+ }
+ }
+
+ delete pEncoder;
+}
+
+void
+PrinterGfx::DrawPS2MonoImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::MonochromeImage);
+ writePS2ImageHeader(rArea, psp::MonochromeImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ long nBitPos = 0;
+ sal_uChar nBit = 0;
+ sal_uChar nByte = 0;
+
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ nBit = rBitmap.GetPixelIdx (nRow, nColumn);
+ nByte |= nBit << (7 - nBitPos);
+
+ if (++nBitPos == 8)
+ {
+ pEncoder->EncodeByte (nByte);
+ nBitPos = 0;
+ nByte = 0;
+ }
+ }
+ // keep the row byte aligned
+ if (nBitPos != 0)
+ pEncoder->EncodeByte (nByte);
+ }
+
+ delete pEncoder;
+}
+
+void
+PrinterGfx::DrawPS2PaletteImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::PaletteImage);
+ writePS2ImageHeader(rArea, psp::PaletteImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ sal_uChar nByte = rBitmap.GetPixelIdx (nRow, nColumn);
+ pEncoder->EncodeByte (nByte);
+ }
+ }
+
+ delete pEncoder;
+}
+
+void
+PrinterGfx::DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::TrueColorImage);
+ writePS2ImageHeader(rArea, psp::TrueColorImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ PrinterColor aColor = rBitmap.GetPixelRGB (nRow, nColumn);
+ pEncoder->EncodeByte (aColor.GetRed());
+ pEncoder->EncodeByte (aColor.GetGreen());
+ pEncoder->EncodeByte (aColor.GetBlue());
+ }
+ }
+
+ delete pEncoder;
+}
+
+} /* namespace psp */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/printergfx/common_gfx.cxx b/vcl/unx/generic/printergfx/common_gfx.cxx
new file mode 100644
index 000000000000..7cae4586bf6e
--- /dev/null
+++ b/vcl/unx/generic/printergfx/common_gfx.cxx
@@ -0,0 +1,1287 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "printergfx.hxx"
+#include "printerjob.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include "tools/debug.hxx"
+#include "tools/color.hxx"
+#include "tools/poly.hxx"
+
+using namespace psp ;
+
+static const sal_Int32 nMaxTextColumn = 80;
+
+GraphicsStatus::GraphicsStatus() :
+ mbArtItalic( false ),
+ mbArtBold( false ),
+ mnTextHeight( 0 ),
+ mnTextWidth( 0 ),
+ mfLineWidth( -1 )
+{
+}
+
+/*
+ * non graphics graphics routines
+ */
+
+sal_Bool
+PrinterGfx::Init (PrinterJob &rPrinterJob)
+{
+ mpPageHeader = rPrinterJob.GetCurrentPageHeader ();
+ mpPageBody = rPrinterJob.GetCurrentPageBody ();
+ mnDepth = rPrinterJob.GetDepth ();
+ mnPSLevel = rPrinterJob.GetPostscriptLevel ();
+ mbColor = rPrinterJob.IsColorPrinter ();
+
+ mnDpi = rPrinterJob.GetResolution();
+ rPrinterJob.GetScale (mfScaleX, mfScaleY);
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rPrinterJob.GetPrinterName() ) );
+ if( mpFontSubstitutes )
+ delete const_cast< ::boost::unordered_map<fontID,fontID>* >(mpFontSubstitutes);
+ if( rInfo.m_bPerformFontSubstitution )
+ mpFontSubstitutes = new ::boost::unordered_map< fontID, fontID >( rInfo.m_aFontSubstitutions );
+ else
+ mpFontSubstitutes = NULL;
+ mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
+
+ return sal_True;
+}
+
+sal_Bool
+PrinterGfx::Init (const JobData& rData)
+{
+ mpPageHeader = NULL;
+ mpPageBody = NULL;
+ mnDepth = rData.m_nColorDepth;
+ mnPSLevel = rData.m_nPSLevel ? rData.m_nPSLevel : (rData.m_pParser ? rData.m_pParser->getLanguageLevel() : 2 );
+ mbColor = rData.m_nColorDevice ? ( rData.m_nColorDevice == -1 ? sal_False : sal_True ) : (( rData.m_pParser ? (rData.m_pParser->isColorDevice() ? sal_True : sal_False ) : sal_True ) );
+ int nRes = rData.m_aContext.getRenderResolution();
+ mnDpi = nRes;
+ mfScaleX = (double)72.0 / (double)mnDpi;
+ mfScaleY = (double)72.0 / (double)mnDpi;
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rData.m_aPrinterName ) );
+ if( mpFontSubstitutes )
+ delete const_cast< ::boost::unordered_map<fontID,fontID>* >(mpFontSubstitutes);
+ if( rInfo.m_bPerformFontSubstitution )
+ mpFontSubstitutes = new ::boost::unordered_map< fontID, fontID >( rInfo.m_aFontSubstitutions );
+ else
+ mpFontSubstitutes = NULL;
+ mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
+
+ return sal_True;
+}
+
+void
+PrinterGfx::GetResolution (sal_Int32 &rDpiX, sal_Int32 &rDpiY) const
+{
+ rDpiX = mnDpi;
+ rDpiY = mnDpi;
+}
+
+sal_uInt16
+PrinterGfx::GetBitCount ()
+{
+ return mnDepth;
+}
+
+PrinterGfx::PrinterGfx() :
+ mpPageHeader (NULL),
+ mpPageBody (NULL),
+ mnFontID (0),
+ mnFallbackID (0),
+ mnTextAngle (0),
+ mbTextVertical (false),
+ mrFontMgr (PrintFontManager::get()),
+ mbCompressBmp (sal_True),
+ maFillColor (0xff,0,0),
+ maTextColor (0,0,0),
+ maLineColor (0, 0xff, 0),
+ mpFontSubstitutes( NULL ),
+ mbStrictSO52Compatibility( false )
+{
+ maVirtualStatus.mfLineWidth = 1.0;
+ maVirtualStatus.mnTextHeight = 12;
+ maVirtualStatus.mnTextWidth = 0;
+
+ maGraphicsStack.push_back( GraphicsStatus() );
+}
+
+PrinterGfx::~PrinterGfx()
+{
+ /*
+ * the original reasoning why mpFontSubstitutes is a pointer was
+ * that applications should release all PrinterGfx when printers change
+ * because they are really invalid; the corresponding printers may have
+ * changed their settings or even not exist anymore.
+ *
+ * Alas, this is not always done real time. So we keep a local copy of
+ * the font substitutes now in case of bad timing.
+ */
+ delete const_cast< ::boost::unordered_map<fontID,fontID>* >(mpFontSubstitutes);
+}
+
+void
+PrinterGfx::Clear()
+{
+ mpPageHeader = NULL;
+ mpPageBody = NULL;
+ mnFontID = 0;
+ maVirtualStatus = GraphicsStatus();
+ maVirtualStatus.mnTextHeight = 12;
+ maVirtualStatus.mnTextWidth = 0;
+ maVirtualStatus.mfLineWidth = 1.0;
+ mbTextVertical = false;
+ maLineColor = PrinterColor();
+ maFillColor = PrinterColor();
+ maTextColor = PrinterColor();
+ mbCompressBmp = sal_True;
+ mnDpi = 300;
+ mnDepth = 24;
+ mnPSLevel = 2;
+ mbColor = sal_True;
+ mnTextAngle = 0;
+
+ maClipRegion.clear();
+ maGraphicsStack.clear();
+ maGraphicsStack.push_back( GraphicsStatus() );
+}
+
+/*
+ * clip region handling
+ */
+
+void
+PrinterGfx::ResetClipRegion()
+{
+ maClipRegion.clear();
+ PSGRestore ();
+ PSGSave (); // get "clean" clippath
+}
+
+void
+PrinterGfx::BeginSetClipRegion( sal_uInt32 )
+{
+ maClipRegion.clear();
+}
+
+sal_Bool
+PrinterGfx::UnionClipRegion (sal_Int32 nX,sal_Int32 nY,sal_Int32 nDX,sal_Int32 nDY)
+{
+ if( nDX && nDY )
+ maClipRegion.push_back (Rectangle(Point(nX,nY ), Size(nDX,nDY)));
+ return sal_True;
+}
+
+sal_Bool
+PrinterGfx::JoinVerticalClipRectangles( std::list< Rectangle >::iterator& it,
+ Point& rOldPoint, sal_Int32& rColumn )
+{
+ sal_Bool bSuccess = sal_False;
+
+ std::list< Rectangle >::iterator tempit, nextit;
+ nextit = it;
+ ++nextit;
+ std::list< Point > leftside, rightside;
+
+ Rectangle aLastRect( *it );
+ leftside.push_back( Point( it->Left(), it->Top() ) );
+ rightside.push_back( Point( it->Right()+1, it->Top() ) );
+ while( nextit != maClipRegion.end() )
+ {
+ tempit = nextit;
+ ++tempit;
+ if( nextit->Top() == aLastRect.Bottom()+1 )
+ {
+ if(
+ ( nextit->Left() >= aLastRect.Left() && nextit->Left() <= aLastRect.Right() ) // left endpoint touches last rectangle
+ ||
+ ( nextit->Right() >= aLastRect.Left() && nextit->Right() <= aLastRect.Right() ) // right endpoint touches last rectangle
+ ||
+ ( nextit->Left() <= aLastRect.Left() && nextit->Right() >= aLastRect.Right() ) // whole line touches last rectangle
+ )
+ {
+ if( aLastRect.GetHeight() > 1 ||
+ abs( aLastRect.Left() - nextit->Left() ) > 2 ||
+ abs( aLastRect.Right() - nextit->Right() ) > 2
+ )
+ {
+ leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
+ rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
+ }
+ aLastRect = *nextit;
+ leftside.push_back( aLastRect.TopLeft() );
+ rightside.push_back( aLastRect.TopRight() );
+ maClipRegion.erase( nextit );
+ }
+ }
+ nextit = tempit;
+ }
+ if( leftside.size() > 1 )
+ {
+ // push the last coordinates
+ leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
+ rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
+
+ // cool, we can concatenate rectangles
+ int nDX = -65536, nDY = 65536;
+ int nNewDX = 0, nNewDY = 0;
+
+ Point aLastPoint = leftside.front();
+ PSBinMoveTo (aLastPoint, rOldPoint, rColumn);
+ leftside.pop_front();
+ while( leftside.begin() != leftside.end() )
+ {
+ Point aPoint (leftside.front());
+ leftside.pop_front();
+ // may have been the last one
+ if( leftside.begin() != leftside.end() )
+ {
+ nNewDX = aPoint.X() - aLastPoint.X();
+ nNewDY = aPoint.Y() - aLastPoint.Y();
+ if( nNewDX == 0 && nDX == 0 )
+ continue;
+ if( nDX != 0 && nNewDX != 0 &&
+ (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
+ continue;
+ }
+ PSBinLineTo (aPoint, rOldPoint, rColumn);
+ aLastPoint = aPoint;
+ }
+
+ aLastPoint = rightside.back();
+ nDX = -65536;
+ nDY = 65536;
+ PSBinLineTo (aLastPoint, rOldPoint, rColumn);
+ rightside.pop_back();
+ while( rightside.begin() != rightside.end() )
+ {
+ Point aPoint (rightside.back());
+ rightside.pop_back();
+ if( rightside.begin() != rightside.end() )
+ {
+ nNewDX = aPoint.X() - aLastPoint.X();
+ nNewDY = aPoint.Y() - aLastPoint.Y();
+ if( nNewDX == 0 && nDX == 0 )
+ continue;
+ if( nDX != 0 && nNewDX != 0 &&
+ (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
+ continue;
+ }
+ PSBinLineTo (aPoint, rOldPoint, rColumn);
+ }
+
+ tempit = it;
+ ++tempit;
+ maClipRegion.erase( it );
+ it = tempit;
+ bSuccess = sal_True;
+ }
+ return bSuccess;
+}
+
+void
+PrinterGfx::EndSetClipRegion()
+{
+ PSGRestore ();
+ PSGSave (); // get "clean" clippath
+
+ PSBinStartPath ();
+ Point aOldPoint (0, 0);
+ sal_Int32 nColumn = 0;
+
+ std::list< Rectangle >::iterator it = maClipRegion.begin();
+ while( it != maClipRegion.end() )
+ {
+ // try to concatenate adjacent rectangles
+ // first try in y direction, then in x direction
+ if( ! JoinVerticalClipRectangles( it, aOldPoint, nColumn ) )
+ {
+ // failed, so it is a single rectangle
+ PSBinMoveTo (it->TopLeft(), aOldPoint, nColumn );
+ PSBinLineTo (Point( it->Left(), it->Bottom()+1 ), aOldPoint, nColumn );
+ PSBinLineTo (Point( it->Right()+1, it->Bottom()+1 ), aOldPoint, nColumn );
+ PSBinLineTo (Point( it->Right()+1, it->Top() ), aOldPoint, nColumn );
+ ++it;
+ }
+ }
+
+ PSBinEndPath ();
+
+ WritePS (mpPageBody, "closepath clip newpath\n");
+ maClipRegion.clear();
+}
+
+/*
+ * draw graphic primitives
+ */
+
+void
+PrinterGfx::DrawRect (const Rectangle& rRectangle )
+{
+ char pRect [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOf (rRectangle.TopLeft().X(), pRect);
+ nChar += psp::appendStr (" ", pRect + nChar);
+ nChar += psp::getValueOf (rRectangle.TopLeft().Y(), pRect + nChar);
+ nChar += psp::appendStr (" ", pRect + nChar);
+ nChar += psp::getValueOf (rRectangle.GetWidth(), pRect + nChar);
+ nChar += psp::appendStr (" ", pRect + nChar);
+ nChar += psp::getValueOf (rRectangle.GetHeight(), pRect + nChar);
+ nChar += psp::appendStr (" ", pRect + nChar);
+
+ if( maFillColor.Is() )
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, pRect, nChar);
+ WritePS (mpPageBody, "rectfill\n");
+ }
+ if( maLineColor.Is() )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+ WritePS (mpPageBody, pRect, nChar);
+ WritePS (mpPageBody, "rectstroke\n");
+ }
+}
+
+void
+PrinterGfx::DrawLine (const Point& rFrom, const Point& rTo)
+{
+ if( maLineColor.Is() )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+
+ PSMoveTo (rFrom);
+ PSLineTo (rTo);
+ WritePS (mpPageBody, "stroke\n" );
+ }
+}
+
+void
+PrinterGfx::DrawPixel (const Point& rPoint, const PrinterColor& rPixelColor)
+{
+ if( rPixelColor.Is() )
+ {
+ PSSetColor (rPixelColor);
+ PSSetColor ();
+
+ PSMoveTo (rPoint);
+ PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()));
+ PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()+1));
+ PSLineTo (Point (rPoint.X (), rPoint.Y ()+1));
+ WritePS (mpPageBody, "fill\n" );
+ }
+}
+
+void
+PrinterGfx::DrawPolyLine (sal_uInt32 nPoints, const Point* pPath)
+{
+ if( maLineColor.Is() && nPoints && pPath )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+
+ PSBinCurrentPath (nPoints, pPath);
+
+ WritePS (mpPageBody, "stroke\n" );
+ }
+}
+
+void
+PrinterGfx::DrawPolygon (sal_uInt32 nPoints, const Point* pPath)
+{
+ // premature end of operation
+ if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+ // setup closed path
+ Point aPoint( 0, 0 );
+ sal_Int32 nColumn( 0 );
+
+ PSBinStartPath();
+ PSBinMoveTo( pPath[0], aPoint, nColumn );
+ for( unsigned int n = 1; n < nPoints; n++ )
+ PSBinLineTo( pPath[n], aPoint, nColumn );
+ if( pPath[0] != pPath[nPoints-1] )
+ PSBinLineTo( pPath[0], aPoint, nColumn );
+ PSBinEndPath();
+
+ // fill the polygon first, then draw the border, note that fill and
+ // stroke reset the currentpath
+
+ // if fill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ if (maFillColor.Is ())
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+
+ if (maLineColor.Is ())
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+ WritePS (mpPageBody, "stroke\n");
+ }
+}
+
+void
+PrinterGfx::DrawPolyPolygon (sal_uInt32 nPoly, const sal_uInt32* pSizes, const Point** pPaths )
+{
+ // sanity check
+ if ( !nPoly || !pPaths || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+
+ // setup closed path
+ for( unsigned int i = 0; i < nPoly; i++ )
+ {
+ Point aPoint( 0, 0 );
+ sal_Int32 nColumn( 0 );
+
+ PSBinStartPath();
+ PSBinMoveTo( pPaths[i][0], aPoint, nColumn );
+ for( unsigned int n = 1; n < pSizes[i]; n++ )
+ PSBinLineTo( pPaths[i][n], aPoint, nColumn );
+ if( pPaths[i][0] != pPaths[i][pSizes[i]-1] )
+ PSBinLineTo( pPaths[i][0], aPoint, nColumn );
+ PSBinEndPath();
+ }
+
+ // if eofill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ // first draw area
+ if( maFillColor.Is() )
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+
+ // now draw outlines
+ if( maLineColor.Is() )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+ WritePS (mpPageBody, "stroke\n");
+ }
+}
+
+/*
+ * Bezier Polygon Drawing methods.
+ */
+
+void
+PrinterGfx::DrawPolyLineBezier (sal_uInt32 nPoints, const Point* pPath, const sal_uInt8* pFlgAry)
+{
+ const sal_uInt32 nBezString= 1024;
+ sal_Char pString[nBezString];
+
+ if ( nPoints > 1 && maLineColor.Is() && pPath )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+
+ snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
+ WritePS(mpPageBody, pString);
+
+ // Handle the drawing of mixed lines mixed with curves
+ // - a normal point followed by a normal point is a line
+ // - a normal point followed by 2 control points and a normal point is a curve
+ for (unsigned int i=1; i<nPoints;)
+ {
+ if (pFlgAry[i] != POLY_CONTROL) //If the next point is a POLY_NORMAL, we're drawing a line
+ {
+ snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
+ i++;
+ }
+ else //Otherwise we're drawing a spline
+ {
+ if (i+2 >= nPoints)
+ return; //Error: wrong sequence of contol/normal points somehow
+ if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
+ (pFlgAry[i+2] != POLY_CONTROL))
+ {
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPath[i].X(), pPath[i].Y(),
+ pPath[i+1].X(), pPath[i+1].Y(),
+ pPath[i+2].X(), pPath[i+2].Y());
+ }
+ else
+ {
+ OSL_FAIL( "PrinterGfx::DrawPolyLineBezier: Strange output" );
+ }
+ i+=3;
+ }
+ WritePS(mpPageBody, pString);
+ }
+
+ // now draw outlines
+ WritePS (mpPageBody, "stroke\n");
+ }
+}
+
+void
+PrinterGfx::DrawPolygonBezier (sal_uInt32 nPoints, const Point* pPath, const sal_uInt8* pFlgAry)
+{
+ const sal_uInt32 nBezString = 1024;
+ sal_Char pString[nBezString];
+ // premature end of operation
+ if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+ snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
+ WritePS(mpPageBody, pString); //Move to the starting point for the PolyPoygon
+ for (unsigned int i=1; i < nPoints;)
+ {
+ if (pFlgAry[i] != POLY_CONTROL)
+ {
+ snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
+ WritePS(mpPageBody, pString);
+ i++;
+ }
+ else
+ {
+ if (i+2 >= nPoints)
+ return; //Error: wrong sequence of contol/normal points somehow
+ if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
+ (pFlgAry[i+2] != POLY_CONTROL))
+ {
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPath[i].X(), pPath[i].Y(),
+ pPath[i+1].X(), pPath[i+1].Y(),
+ pPath[i+2].X(), pPath[i+2].Y());
+ WritePS(mpPageBody, pString);
+ }
+ else
+ {
+ OSL_FAIL( "PrinterGfx::DrawPolygonBezier: Strange output" );
+ }
+ i+=3;
+ }
+ }
+
+ // if fill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ if (maFillColor.Is ())
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+}
+
+void
+PrinterGfx::DrawPolyPolygonBezier (sal_uInt32 nPoly, const sal_uInt32 * pPoints, const Point* const * pPtAry, const sal_uInt8* const* pFlgAry)
+{
+ const sal_uInt32 nBezString = 1024;
+ sal_Char pString[nBezString];
+ if ( !nPoly || !pPtAry || !pPoints || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+
+ for (unsigned int i=0; i<nPoly;i++)
+ {
+ sal_uInt32 nPoints = pPoints[i];
+ // sanity check
+ if( nPoints == 0 || pPtAry[i] == NULL )
+ continue;
+
+ snprintf(pString, nBezString, "%li %li moveto\n", pPtAry[i][0].X(), pPtAry[i][0].Y()); //Move to the starting point
+ WritePS(mpPageBody, pString);
+ for (unsigned int j=1; j < nPoints;)
+ {
+ // if no flag array exists for this polygon, then it must be a regular
+ // polygon without beziers
+ if ( ! pFlgAry[i] || pFlgAry[i][j] != POLY_CONTROL)
+ {
+ snprintf(pString, nBezString, "%li %li lineto\n", pPtAry[i][j].X(), pPtAry[i][j].Y());
+ WritePS(mpPageBody, pString);
+ j++;
+ }
+ else
+ {
+ if (j+2 >= nPoints)
+ break; //Error: wrong sequence of contol/normal points somehow
+ if ((pFlgAry[i][j] == POLY_CONTROL) && (pFlgAry[i][j+1] == POLY_CONTROL) && (pFlgAry[i][j+2] != POLY_CONTROL))
+ {
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPtAry[i][j].X(), pPtAry[i][j].Y(),
+ pPtAry[i][j+1].X(), pPtAry[i][j+1].Y(),
+ pPtAry[i][j+2].X(), pPtAry[i][j+2].Y());
+ WritePS(mpPageBody, pString);
+ }
+ else
+ {
+ OSL_FAIL( "PrinterGfx::DrawPolyPolygonBezier: Strange output" );
+ }
+ j+=3;
+ }
+ }
+ }
+
+ // if fill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ if (maFillColor.Is ())
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+}
+
+
+/*
+ * postscript generating routines
+ */
+void
+PrinterGfx::PSGSave ()
+{
+ WritePS (mpPageBody, "gsave\n" );
+ GraphicsStatus aNewState;
+ if( maGraphicsStack.begin() != maGraphicsStack.end() )
+ aNewState = maGraphicsStack.front();
+ maGraphicsStack.push_front( aNewState );
+}
+
+void
+PrinterGfx::PSGRestore ()
+{
+ WritePS (mpPageBody, "grestore\n" );
+ if( maGraphicsStack.begin() == maGraphicsStack.end() )
+ WritePS (mpPageBody, "Error: too many grestores\n" );
+ else
+ maGraphicsStack.pop_front();
+}
+
+void
+PrinterGfx::PSSetLineWidth ()
+{
+ if( currentState().mfLineWidth != maVirtualStatus.mfLineWidth )
+ {
+ char pBuffer[128];
+ sal_Int32 nChar = 0;
+
+ currentState().mfLineWidth = maVirtualStatus.mfLineWidth;
+ nChar = psp::getValueOfDouble (pBuffer, maVirtualStatus.mfLineWidth, 5);
+ nChar += psp::appendStr (" setlinewidth\n", pBuffer + nChar);
+ WritePS (mpPageBody, pBuffer, nChar);
+ }
+}
+
+void
+PrinterGfx::PSSetColor ()
+{
+ PrinterColor& rColor( maVirtualStatus.maColor );
+
+ if( currentState().maColor != rColor )
+ {
+ currentState().maColor = rColor;
+
+ char pBuffer[128];
+ sal_Int32 nChar = 0;
+
+ if( mbColor )
+ {
+ nChar = psp::getValueOfDouble (pBuffer,
+ (double)rColor.GetRed() / 255.0, 5);
+ nChar += psp::appendStr (" ", pBuffer + nChar);
+ nChar += psp::getValueOfDouble (pBuffer + nChar,
+ (double)rColor.GetGreen() / 255.0, 5);
+ nChar += psp::appendStr (" ", pBuffer + nChar);
+ nChar += psp::getValueOfDouble (pBuffer + nChar,
+ (double)rColor.GetBlue() / 255.0, 5);
+ nChar += psp::appendStr (" setrgbcolor\n", pBuffer + nChar );
+ }
+ else
+ {
+ Color aColor( rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
+ sal_uInt8 nCol = aColor.GetLuminance();
+ nChar = psp::getValueOfDouble( pBuffer, (double)nCol / 255.0, 5 );
+ nChar += psp::appendStr( " setgray\n", pBuffer + nChar );
+ }
+
+ WritePS (mpPageBody, pBuffer, nChar);
+ }
+}
+
+void
+PrinterGfx::PSSetFont ()
+{
+ GraphicsStatus& rCurrent( currentState() );
+ if( maVirtualStatus.maFont != rCurrent.maFont ||
+ maVirtualStatus.mnTextHeight != rCurrent.mnTextHeight ||
+ maVirtualStatus.maEncoding != rCurrent.maEncoding ||
+ maVirtualStatus.mnTextWidth != rCurrent.mnTextWidth ||
+ maVirtualStatus.mbArtBold != rCurrent.mbArtBold ||
+ maVirtualStatus.mbArtItalic != rCurrent.mbArtItalic
+ )
+ {
+ rCurrent.maFont = maVirtualStatus.maFont;
+ rCurrent.maEncoding = maVirtualStatus.maEncoding;
+ rCurrent.mnTextWidth = maVirtualStatus.mnTextWidth;
+ rCurrent.mnTextHeight = maVirtualStatus.mnTextHeight;
+ rCurrent.mbArtItalic = maVirtualStatus.mbArtItalic;
+ rCurrent.mbArtBold = maVirtualStatus.mbArtBold;
+
+ sal_Int32 nTextHeight = rCurrent.mnTextHeight;
+ sal_Int32 nTextWidth = rCurrent.mnTextWidth ? rCurrent.mnTextWidth
+ : rCurrent.mnTextHeight;
+
+ sal_Char pSetFont [256];
+ sal_Int32 nChar = 0;
+
+ // postscript based fonts need reencoding
+ if ( ( rCurrent.maEncoding == RTL_TEXTENCODING_MS_1252)
+ || ( rCurrent.maEncoding == RTL_TEXTENCODING_ISO_8859_1)
+ || ( rCurrent.maEncoding >= RTL_TEXTENCODING_USER_START
+ && rCurrent.maEncoding <= RTL_TEXTENCODING_USER_END)
+ )
+ {
+ rtl::OString aReencodedFont =
+ psp::GlyphSet::GetReencodedFontName (rCurrent.maEncoding,
+ rCurrent.maFont);
+
+ nChar += psp::appendStr ("(", pSetFont + nChar);
+ nChar += psp::appendStr (aReencodedFont.getStr(),
+ pSetFont + nChar);
+ nChar += psp::appendStr (") cvn findfont ",
+ pSetFont + nChar);
+ }
+ else
+ // tt based fonts mustn't reencode, the encoding is implied by the fontname
+ // same for symbol type1 fonts, dont try to touch them
+ {
+ nChar += psp::appendStr ("(", pSetFont + nChar);
+ nChar += psp::appendStr (rCurrent.maFont.getStr(),
+ pSetFont + nChar);
+ nChar += psp::appendStr (") cvn findfont ",
+ pSetFont + nChar);
+ }
+
+ if( ! rCurrent.mbArtItalic )
+ {
+ nChar += psp::getValueOf (nTextWidth, pSetFont + nChar);
+ nChar += psp::appendStr (" ", pSetFont + nChar);
+ nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
+ nChar += psp::appendStr (" matrix scale makefont setfont\n", pSetFont + nChar);
+ }
+ else // skew 15 degrees to right
+ {
+ nChar += psp::appendStr ( " [", pSetFont + nChar);
+ nChar += psp::getValueOf (nTextWidth, pSetFont + nChar);
+ nChar += psp::appendStr (" 0 ", pSetFont + nChar);
+ nChar += psp::getValueOfDouble (pSetFont + nChar, 0.27*(double)nTextWidth, 3 );
+ nChar += psp::appendStr ( " ", pSetFont + nChar);
+ nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
+
+ nChar += psp::appendStr (" 0 0] makefont setfont\n", pSetFont + nChar);
+ }
+
+ WritePS (mpPageBody, pSetFont);
+ }
+}
+
+void
+PrinterGfx::PSRotate (sal_Int32 nAngle)
+{
+ sal_Int32 nPostScriptAngle = -nAngle;
+ while( nPostScriptAngle < 0 )
+ nPostScriptAngle += 3600;
+
+ if (nPostScriptAngle == 0)
+ return;
+
+ sal_Int32 nFullAngle = nPostScriptAngle / 10;
+ sal_Int32 nTenthAngle = nPostScriptAngle % 10;
+
+ sal_Char pRotate [48];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOf (nFullAngle, pRotate);
+ nChar += psp::appendStr (".", pRotate + nChar);
+ nChar += psp::getValueOf (nTenthAngle, pRotate + nChar);
+ nChar += psp::appendStr (" rotate\n", pRotate + nChar);
+
+ WritePS (mpPageBody, pRotate);
+}
+
+void
+PrinterGfx::PSPointOp (const Point& rPoint, const sal_Char* pOperator)
+{
+ sal_Char pPSCommand [48];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOf (rPoint.X(), pPSCommand);
+ nChar += psp::appendStr (" ", pPSCommand + nChar);
+ nChar += psp::getValueOf (rPoint.Y(), pPSCommand + nChar);
+ nChar += psp::appendStr (" ", pPSCommand + nChar);
+ nChar += psp::appendStr (pOperator, pPSCommand + nChar);
+ nChar += psp::appendStr ("\n", pPSCommand + nChar);
+
+ DBG_ASSERT (nChar < 48, "Buffer overflow in PSPointOp");
+
+ WritePS (mpPageBody, pPSCommand);
+}
+
+void
+PrinterGfx::PSTranslate (const Point& rPoint)
+{
+ PSPointOp (rPoint, "translate");
+}
+
+void
+PrinterGfx::PSMoveTo (const Point& rPoint)
+{
+ PSPointOp (rPoint, "moveto");
+}
+
+void
+PrinterGfx::PSLineTo (const Point& rPoint)
+{
+ PSPointOp (rPoint, "lineto");
+}
+
+void
+PrinterGfx::PSRMoveTo (sal_Int32 nDx, sal_Int32 nDy)
+{
+ Point aPoint(nDx, nDy);
+ PSPointOp (aPoint, "rmoveto");
+}
+
+/* get a compressed representation of the path information */
+
+#define DEBUG_BINPATH 0
+
+void
+PrinterGfx::PSBinLineTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
+{
+#if (DEBUG_BINPATH == 1)
+ PSLineTo (rCurrent);
+#else
+ PSBinPath (rCurrent, rOld, lineto, nColumn);
+#endif
+}
+
+void
+PrinterGfx::PSBinMoveTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
+{
+#if (DEBUG_BINPATH == 1)
+ PSMoveTo (rCurrent);
+#else
+ PSBinPath (rCurrent, rOld, moveto, nColumn);
+#endif
+}
+
+void
+PrinterGfx::PSBinStartPath ()
+{
+#if (DEBUG_BINPATH == 1)
+ WritePS (mpPageBody, "% PSBinStartPath\n");
+#else
+ WritePS (mpPageBody, "readpath\n" );
+#endif
+}
+
+void
+PrinterGfx::PSBinEndPath ()
+{
+#if (DEBUG_BINPATH == 1)
+ WritePS (mpPageBody, "% PSBinEndPath\n");
+#else
+ WritePS (mpPageBody, "~\n");
+#endif
+}
+
+void
+PrinterGfx::PSBinCurrentPath (sal_uInt32 nPoints, const Point* pPath)
+{
+ // create the path
+ Point aPoint (0, 0);
+ sal_Int32 nColumn = 0;
+
+ PSBinStartPath ();
+ PSBinMoveTo (*pPath, aPoint, nColumn);
+ for (unsigned int i = 1; i < nPoints; i++)
+ PSBinLineTo (pPath[i], aPoint, nColumn);
+ PSBinEndPath ();
+}
+
+void
+PrinterGfx::PSBinPath (const Point& rCurrent, Point& rOld,
+ pspath_t eType, sal_Int32& nColumn)
+{
+ sal_Char pPath[48];
+ sal_Int32 nChar;
+
+ // create the hex representation of the dx and dy path shift, store the field
+ // width as it is needed for the building the command
+ sal_Int32 nXPrec = getAlignedHexValueOf (rCurrent.X() - rOld.X(), pPath + 1);
+ sal_Int32 nYPrec = getAlignedHexValueOf (rCurrent.Y() - rOld.Y(), pPath + 1 + nXPrec);
+ pPath [ 1 + nXPrec + nYPrec ] = 0;
+
+ // build the command, it is a char with bit represention 000cxxyy
+ // c represents the char, xx and yy repr. the field width of the dx and dy shift,
+ // dx and dy represent the number of bytes to read after the opcode
+ sal_Char cCmd = (eType == lineto ? (sal_Char)0x00 : (sal_Char)0x10);
+ switch (nYPrec)
+ {
+ case 2: break;
+ case 4: cCmd |= 0x01; break;
+ case 6: cCmd |= 0x02; break;
+ case 8: cCmd |= 0x03; break;
+ default: OSL_FAIL("invalid x precision in binary path");
+ }
+ switch (nXPrec)
+ {
+ case 2: break;
+ case 4: cCmd |= 0x04; break;
+ case 6: cCmd |= 0x08; break;
+ case 8: cCmd |= 0x0c; break;
+ default: OSL_FAIL("invalid y precision in binary path");
+ }
+ cCmd += 'A';
+ pPath[0] = cCmd;
+
+ // write the command to file,
+ // line breaking at column nMaxTextColumn (80)
+ nChar = 1 + nXPrec + nYPrec;
+ if ((nColumn + nChar) > nMaxTextColumn)
+ {
+ sal_Int32 nSegment = nMaxTextColumn - nColumn;
+
+ WritePS (mpPageBody, pPath, nSegment);
+ WritePS (mpPageBody, "\n", 1);
+ WritePS (mpPageBody, pPath + nSegment, nChar - nSegment);
+
+ nColumn = nChar - nSegment;
+ }
+ else
+ {
+ WritePS (mpPageBody, pPath, nChar);
+
+ nColumn += nChar;
+ }
+
+ rOld = rCurrent;
+}
+
+void
+PrinterGfx::PSScale (double fScaleX, double fScaleY)
+{
+ sal_Char pScale [48];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOfDouble (pScale, fScaleX, 5);
+ nChar += psp::appendStr (" ", pScale + nChar);
+ nChar += psp::getValueOfDouble (pScale + nChar, fScaleY, 5);
+ nChar += psp::appendStr (" scale\n", pScale + nChar);
+
+ WritePS (mpPageBody, pScale);
+}
+
+/* psshowtext helper routines: draw an hex string for show/xshow */
+void
+PrinterGfx::PSHexString (const sal_uChar* pString, sal_Int16 nLen)
+{
+ sal_Char pHexString [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("<", pHexString);
+ for (int i = 0; i < nLen; i++)
+ {
+ if (nChar >= (nMaxTextColumn - 1))
+ {
+ nChar += psp::appendStr ("\n", pHexString + nChar);
+ WritePS (mpPageBody, pHexString, nChar);
+ nChar = 0;
+ }
+ nChar += psp::getHexValueOf ((sal_Int32)pString[i], pHexString + nChar);
+ }
+
+ nChar += psp::appendStr (">\n", pHexString + nChar);
+ WritePS (mpPageBody, pHexString, nChar);
+}
+
+/* psshowtext helper routines: draw an array for xshow ps operator */
+void
+PrinterGfx::PSDeltaArray (const sal_Int32 *pArray, sal_Int16 nEntries)
+{
+ sal_Char pPSArray [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("[", pPSArray + nChar);
+ nChar += psp::getValueOf (pArray[0], pPSArray + nChar);
+
+ for (int i = 1; i < nEntries; i++)
+ {
+ if (nChar >= (nMaxTextColumn - 1))
+ {
+ nChar += psp::appendStr ("\n", pPSArray + nChar);
+ WritePS (mpPageBody, pPSArray, nChar);
+ nChar = 0;
+ }
+
+ nChar += psp::appendStr (" ", pPSArray + nChar);
+ nChar += psp::getValueOf (pArray[i] - pArray[i-1], pPSArray + nChar);
+ }
+
+ nChar += psp::appendStr (" 0]\n", pPSArray + nChar);
+ WritePS (mpPageBody, pPSArray);
+}
+
+/* the DrawText equivalent, pDeltaArray may be NULL. For Type1 fonts or single byte
+ * fonts in general nBytes and nGlyphs is the same. For printer resident Composite
+ * fonts it may be different (these fonts may be SJIS encoded for example) */
+void
+PrinterGfx::PSShowText (const sal_uChar* pStr, sal_Int16 nGlyphs, sal_Int16 nBytes,
+ const sal_Int32* pDeltaArray)
+{
+ PSSetColor (maTextColor);
+ PSSetColor ();
+ PSSetFont ();
+ // rotate the user coordinate system
+ if (mnTextAngle != 0)
+ {
+ PSGSave ();
+ PSRotate (mnTextAngle);
+ }
+
+ sal_Char pBuffer[256];
+ if( maVirtualStatus.mbArtBold )
+ {
+ sal_Int32 nLW = maVirtualStatus.mnTextWidth;
+ if( nLW == 0 )
+ nLW = maVirtualStatus.mnTextHeight;
+ else
+ nLW = nLW < maVirtualStatus.mnTextHeight ? nLW : maVirtualStatus.mnTextHeight;
+ psp::getValueOfDouble( pBuffer, (double)nLW / 30.0 );
+ }
+ // dispatch to the drawing method
+ if (pDeltaArray == NULL)
+ {
+ PSHexString (pStr, nBytes);
+
+ if( maVirtualStatus.mbArtBold )
+ {
+ WritePS( mpPageBody, pBuffer );
+ WritePS( mpPageBody, " bshow\n" );
+ }
+ else
+ WritePS (mpPageBody, "show\n");
+ }
+ else
+ {
+ PSHexString (pStr, nBytes);
+ PSDeltaArray (pDeltaArray, nGlyphs - 1);
+ if( maVirtualStatus.mbArtBold )
+ {
+ WritePS( mpPageBody, pBuffer );
+ WritePS( mpPageBody, " bxshow\n" );
+ }
+ else
+ WritePS (mpPageBody, "xshow\n");
+ }
+
+ // restore the user coordinate system
+ if (mnTextAngle != 0)
+ PSGRestore ();
+}
+
+void
+PrinterGfx::PSComment( const sal_Char* pComment )
+{
+ const sal_Char* pLast = pComment;
+ while( pComment && *pComment )
+ {
+ while( *pComment && *pComment != '\n' && *pComment != '\r' )
+ pComment++;
+ if( pComment - pLast > 1 )
+ {
+ WritePS( mpPageBody, "% ", 2 );
+ WritePS( mpPageBody, pLast, pComment - pLast );
+ WritePS( mpPageBody, "\n", 1 );
+ }
+ if( *pComment )
+ pLast = ++pComment;
+ }
+}
+
+sal_Bool
+PrinterGfx::DrawEPS( const Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize )
+{
+ if( nSize == 0 )
+ return sal_True;
+ if( ! mpPageBody )
+ return sal_False;
+
+ sal_Bool bSuccess = sal_False;
+
+ // first search the BoundingBox of the EPS data
+ SvMemoryStream aStream( pPtr, nSize, STREAM_READ );
+ aStream.Seek( STREAM_SEEK_TO_BEGIN );
+ ByteString aLine;
+
+ ByteString aDocTitle;
+ double fLeft = 0, fRight = 0, fTop = 0, fBottom = 0;
+ bool bEndComments = false;
+ while( ! aStream.IsEof()
+ && ( ( fLeft == 0 && fRight == 0 && fTop == 0 && fBottom == 0 ) ||
+ ( aDocTitle.Len() == 0 && bEndComments == false ) )
+ )
+ {
+ aStream.ReadLine( aLine );
+ if( aLine.Len() > 1 && aLine.GetChar( 0 ) == '%' )
+ {
+ char cChar = aLine.GetChar(1);
+ if( cChar == '%' )
+ {
+ if( aLine.CompareIgnoreCaseToAscii( "%%BoundingBox:", 14 ) == COMPARE_EQUAL )
+ {
+ aLine = WhitespaceToSpace( aLine.GetToken( 1, ':' ) );
+ if( aLine.Len() && aLine.Search( "atend" ) == STRING_NOTFOUND )
+ {
+ fLeft = StringToDouble( GetCommandLineToken( 0, aLine ) );
+ fBottom = StringToDouble( GetCommandLineToken( 1, aLine ) );
+ fRight = StringToDouble( GetCommandLineToken( 2, aLine ) );
+ fTop = StringToDouble( GetCommandLineToken( 3, aLine ) );
+ }
+ }
+ else if( aLine.CompareIgnoreCaseToAscii( "%%Title:", 8 ) == COMPARE_EQUAL )
+ aDocTitle = WhitespaceToSpace( aLine.Copy( 8 ) );
+ else if( aLine.CompareIgnoreCaseToAscii( "%%EndComments", 13 ) == COMPARE_EQUAL )
+ bEndComments = true;
+ }
+ else if( cChar == ' ' || cChar == '\t' || cChar == '\r' || cChar == '\n' )
+ bEndComments = true;
+ }
+ else
+ bEndComments = true;
+ }
+
+ static sal_uInt16 nEps = 0;
+ if( ! aDocTitle.Len() )
+ aDocTitle = ByteString::CreateFromInt32( (sal_Int32)(nEps++) );
+
+ if( fLeft != fRight && fTop != fBottom )
+ {
+ double fScaleX = (double)rBoundingBox.GetWidth()/(fRight-fLeft);
+ double fScaleY = -(double)rBoundingBox.GetHeight()/(fTop-fBottom);
+ Point aTranslatePoint( (int)(rBoundingBox.Left()-fLeft*fScaleX),
+ (int)(rBoundingBox.Bottom()+1-fBottom*fScaleY) );
+ // prepare EPS
+ WritePS( mpPageBody,
+ "/b4_Inc_state save def\n"
+ "/dict_count countdictstack def\n"
+ "/op_count count 1 sub def\n"
+ "userdict begin\n"
+ "/showpage {} def\n"
+ "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n"
+ "10 setmiterlimit [] 0 setdash newpath\n"
+ "/languagelevel where\n"
+ "{pop languagelevel\n"
+ "1 ne\n"
+ " {false setstrokeadjust false setoverprint\n"
+ " } if\n"
+ "}if\n" );
+ // set up clip path and scale
+ BeginSetClipRegion( 1 );
+ UnionClipRegion( rBoundingBox.Left(), rBoundingBox.Top(), rBoundingBox.GetWidth(), rBoundingBox.GetHeight() );
+ EndSetClipRegion();
+ PSTranslate( aTranslatePoint );
+ PSScale( fScaleX, fScaleY );
+
+ // DSC requires BeginDocument
+ WritePS( mpPageBody, "%%BeginDocument: " );
+ WritePS( mpPageBody, aDocTitle );
+ WritePS( mpPageBody, "\n" );
+
+ // write the EPS data
+ sal_uInt64 nOutLength;
+ mpPageBody->write( pPtr, nSize, nOutLength );
+ bSuccess = nOutLength == nSize;
+
+ // corresponding EndDocument
+ if( ((char*)pPtr)[ nSize-1 ] != '\n' )
+ WritePS( mpPageBody, "\n" );
+ WritePS( mpPageBody, "%%EndDocument\n" );
+
+ // clean up EPS
+ WritePS( mpPageBody,
+ "count op_count sub {pop} repeat\n"
+ "countdictstack dict_count sub {end} repeat\n"
+ "b4_Inc_state restore\n" );
+ }
+ return bSuccess;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/printergfx/glyphset.cxx b/vcl/unx/generic/printergfx/glyphset.cxx
new file mode 100644
index 000000000000..967c9f2a175f
--- /dev/null
+++ b/vcl/unx/generic/printergfx/glyphset.cxx
@@ -0,0 +1,949 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 "glyphset.hxx"
+#include "psputil.hxx"
+
+#include "sft.hxx"
+
+#include "printergfx.hxx"
+#include "fontsubset.hxx"
+#include "vcl/fontmanager.hxx"
+
+#include "osl/thread.h"
+
+#include "sal/alloca.h"
+
+#include "rtl/ustring.hxx"
+#include "rtl/strbuf.hxx"
+
+#include <set>
+#include <map>
+#include <algorithm>
+
+using namespace vcl;
+using namespace psp;
+
+using ::rtl::OUString;
+using ::rtl::OString;
+using ::rtl::OStringBuffer;
+using ::rtl::OUStringToOString;
+
+GlyphSet::GlyphSet ()
+ : mnFontID (-1),
+ mbVertical (0),
+ mbUseFontEncoding (false)
+{}
+
+GlyphSet::GlyphSet (sal_Int32 nFontID, sal_Bool bVertical)
+ : mnFontID (nFontID),
+ mbVertical (bVertical)
+{
+ PrintFontManager &rMgr = PrintFontManager::get();
+ meBaseType = rMgr.getFontType (mnFontID);
+ maBaseName = OUStringToOString (rMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ mnBaseEncoding = rMgr.getFontEncoding(mnFontID);
+ mbUseFontEncoding = rMgr.getUseOnlyFontEncoding(mnFontID);
+}
+
+GlyphSet::~GlyphSet ()
+{
+ /* FIXME delete the glyphlist ??? */
+}
+
+sal_Int32
+GlyphSet::GetFontID ()
+{
+ return mnFontID;
+}
+
+fonttype::type
+GlyphSet::GetFontType ()
+{
+ return meBaseType;
+}
+
+sal_Bool
+GlyphSet::IsVertical ()
+{
+ return mbVertical;
+}
+
+sal_Bool
+GlyphSet::SetFont (sal_Int32 nFontID, sal_Bool bVertical)
+{
+ if (mnFontID != -1)
+ return sal_False;
+
+ mnFontID = nFontID;
+ mbVertical = bVertical;
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ meBaseType = rMgr.getFontType (mnFontID);
+ maBaseName = OUStringToOString (rMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ mnBaseEncoding = rMgr.getFontEncoding(mnFontID);
+ mbUseFontEncoding = rMgr.getUseOnlyFontEncoding(mnFontID);
+
+ return sal_True;
+}
+
+sal_Bool
+GlyphSet::GetCharID (
+ sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ return LookupCharID (nChar, nOutGlyphID, nOutGlyphSetID)
+ || AddCharID (nChar, nOutGlyphID, nOutGlyphSetID);
+}
+
+sal_Bool
+GlyphSet::GetGlyphID (
+ sal_uInt32 nGlyph,
+ sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ return LookupGlyphID (nGlyph, nOutGlyphID, nOutGlyphSetID)
+ || AddGlyphID (nGlyph, nUnicode, nOutGlyphID, nOutGlyphSetID);
+}
+
+sal_Bool
+GlyphSet::LookupCharID (
+ sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ char_list_t::iterator aGlyphSet;
+ sal_Int32 nGlyphSetID;
+
+ // loop thru all the font subsets
+ for (aGlyphSet = maCharList.begin(), nGlyphSetID = 1;
+ aGlyphSet != maCharList.end();
+ ++aGlyphSet, nGlyphSetID++)
+ {
+ // check every subset if it contains the queried unicode char
+ char_map_t::const_iterator aGlyph = (*aGlyphSet).find (nChar);
+ if (aGlyph != (*aGlyphSet).end())
+ {
+ // success: found the unicode char, return the glyphid and the glyphsetid
+ *nOutGlyphSetID = nGlyphSetID;
+ *nOutGlyphID = (*aGlyph).second;
+ return sal_True;
+ }
+ }
+
+ *nOutGlyphSetID = -1;
+ *nOutGlyphID = 0;
+ return sal_False;
+}
+
+sal_Bool
+GlyphSet::LookupGlyphID (
+ sal_uInt32 nGlyph,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ glyph_list_t::iterator aGlyphSet;
+ sal_Int32 nGlyphSetID;
+
+ // loop thru all the font subsets
+ for (aGlyphSet = maGlyphList.begin(), nGlyphSetID = 1;
+ aGlyphSet != maGlyphList.end();
+ ++aGlyphSet, nGlyphSetID++)
+ {
+ // check every subset if it contains the queried unicode char
+ glyph_map_t::const_iterator aGlyph = (*aGlyphSet).find (nGlyph);
+ if (aGlyph != (*aGlyphSet).end())
+ {
+ // success: found the glyph id, return the mapped glyphid and the glyphsetid
+ *nOutGlyphSetID = nGlyphSetID;
+ *nOutGlyphID = (*aGlyph).second;
+ return sal_True;
+ }
+ }
+
+ *nOutGlyphSetID = -1;
+ *nOutGlyphID = 0;
+ return sal_False;
+}
+
+sal_uChar
+GlyphSet::GetAnsiMapping (sal_Unicode nUnicodeChar)
+{
+ static rtl_UnicodeToTextConverter aConverter =
+ rtl_createUnicodeToTextConverter(RTL_TEXTENCODING_MS_1252);
+ static rtl_UnicodeToTextContext aContext =
+ rtl_createUnicodeToTextContext( aConverter );
+
+ sal_Char nAnsiChar;
+ sal_uInt32 nCvtInfo;
+ sal_Size nCvtChars;
+ const sal_uInt32 nCvtFlags = RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR;
+
+ sal_Size nSize = rtl_convertUnicodeToText( aConverter, aContext,
+ &nUnicodeChar, 1, &nAnsiChar, 1,
+ nCvtFlags, &nCvtInfo, &nCvtChars );
+
+ return nSize == 1 ? (sal_uChar)nAnsiChar : (sal_uChar)0;
+}
+
+sal_uChar
+GlyphSet::GetSymbolMapping (sal_Unicode nUnicodeChar)
+{
+ if (0x0000 < nUnicodeChar && nUnicodeChar < 0x0100)
+ return (sal_uChar)nUnicodeChar;
+ if (0xf000 < nUnicodeChar && nUnicodeChar < 0xf100)
+ return (sal_uChar)nUnicodeChar;
+
+ return 0;
+}
+
+void
+GlyphSet::AddNotdef (char_map_t &rCharMap)
+{
+ if (rCharMap.size() == 0)
+ rCharMap[0] = 0;
+}
+
+void
+GlyphSet::AddNotdef (glyph_map_t &rGlyphMap)
+{
+ if (rGlyphMap.size() == 0)
+ rGlyphMap[0] = 0;
+}
+sal_Bool
+GlyphSet::AddCharID (
+ sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ sal_uChar nMappedChar;
+
+ // XXX important: avoid to reencode type1 symbol fonts
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ nMappedChar = GetSymbolMapping (nChar);
+ else
+ nMappedChar = GetAnsiMapping (nChar);
+
+ // create an empty glyphmap that is reserved for iso1252 encoded glyphs
+ // (or -- unencoded -- symbol glyphs) and a second map that takes any other
+ if (maCharList.empty())
+ {
+ char_map_t aMap, aMapp;
+
+ maCharList.push_back (aMap);
+ maCharList.push_back (aMapp);
+ }
+ // if the last map is full, create a new one
+ if ((!nMappedChar) && (maCharList.back().size() == 255))
+ {
+ char_map_t aMap;
+ maCharList.push_back (aMap);
+ }
+
+ // insert a new glyph in the font subset
+ if (nMappedChar)
+ {
+ // always put iso1252 chars into the first map, map them on itself
+ char_map_t& aGlyphSet = maCharList.front();
+ AddNotdef (aGlyphSet);
+
+ aGlyphSet [nChar] = nMappedChar;
+ *nOutGlyphSetID = 1;
+ *nOutGlyphID = nMappedChar;
+ }
+ else
+ {
+ // other chars are just appended to the list
+ char_map_t& aGlyphSet = maCharList.back();
+ AddNotdef (aGlyphSet);
+
+ int nSize = aGlyphSet.size();
+
+ aGlyphSet [nChar] = nSize;
+ *nOutGlyphSetID = maCharList.size();
+ *nOutGlyphID = aGlyphSet [nChar];
+ }
+
+ return sal_True;
+}
+
+sal_Bool
+GlyphSet::AddGlyphID (
+ sal_uInt32 nGlyph,
+ sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ sal_uChar nMappedChar;
+
+ // XXX important: avoid to reencode type1 symbol fonts
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ nMappedChar = GetSymbolMapping (nUnicode);
+ else
+ nMappedChar = GetAnsiMapping (nUnicode);
+
+ // create an empty glyphmap that is reserved for iso1252 encoded glyphs
+ // (or -- unencoded -- symbol glyphs) and a second map that takes any other
+ if (maGlyphList.empty())
+ {
+ glyph_map_t aMap, aMapp;
+
+ maGlyphList.push_back (aMap);
+ maGlyphList.push_back (aMapp);
+ }
+ // if the last map is full, create a new one
+ if ((!nMappedChar) && (maGlyphList.back().size() == 255))
+ {
+ glyph_map_t aMap;
+ maGlyphList.push_back (aMap);
+ }
+
+ // insert a new glyph in the font subset
+ if (nMappedChar)
+ {
+ // always put iso1252 chars into the first map, map them on itself
+ glyph_map_t& aGlyphSet = maGlyphList.front();
+ AddNotdef (aGlyphSet);
+
+ aGlyphSet [nGlyph] = nMappedChar;
+ *nOutGlyphSetID = 1;
+ *nOutGlyphID = nMappedChar;
+ }
+ else
+ {
+ // other chars are just appended to the list
+ glyph_map_t& aGlyphSet = maGlyphList.back();
+ AddNotdef (aGlyphSet);
+
+ int nSize = aGlyphSet.size();
+
+ aGlyphSet [nGlyph] = nSize;
+ *nOutGlyphSetID = maGlyphList.size();
+ *nOutGlyphID = aGlyphSet [nGlyph];
+ }
+
+ return sal_True;
+}
+
+OString
+GlyphSet::GetCharSetName (sal_Int32 nGlyphSetID)
+{
+ if (meBaseType == fonttype::TrueType)
+ {
+ OStringBuffer aSetName( maBaseName.getLength() + 32 );
+ aSetName.append( maBaseName );
+ aSetName.append( "FID" );
+ aSetName.append( mnFontID );
+ aSetName.append( mbVertical ? "VCSet" : "HCSet" );
+ aSetName.append( nGlyphSetID );
+ return aSetName.makeStringAndClear();
+ }
+ else
+ /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */
+ {
+ return maBaseName;
+ }
+}
+
+OString
+GlyphSet::GetGlyphSetName (sal_Int32 nGlyphSetID)
+{
+ if (meBaseType == fonttype::TrueType)
+ {
+ OStringBuffer aSetName( maBaseName.getLength() + 32 );
+ aSetName.append( maBaseName );
+ aSetName.append( "FID" );
+ aSetName.append( mnFontID );
+ aSetName.append( mbVertical ? "VGSet" : "HGSet" );
+ aSetName.append( nGlyphSetID );
+ return aSetName.makeStringAndClear();
+ }
+ else
+ /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */
+ {
+ return maBaseName;
+ }
+}
+
+sal_Int32
+GlyphSet::GetGlyphSetEncoding (sal_Int32 nGlyphSetID)
+{
+ if (meBaseType == fonttype::TrueType)
+ return RTL_TEXTENCODING_DONTKNOW;
+ else
+ {
+ /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ return RTL_TEXTENCODING_SYMBOL;
+ else
+ return nGlyphSetID == 1 ? RTL_TEXTENCODING_MS_1252
+ : RTL_TEXTENCODING_USER_START + nGlyphSetID;
+ }
+}
+
+OString
+GlyphSet::GetGlyphSetEncodingName (rtl_TextEncoding nEnc, const OString &rFontName)
+{
+ if ( nEnc == RTL_TEXTENCODING_MS_1252
+ || nEnc == RTL_TEXTENCODING_ISO_8859_1)
+ {
+ return OString("ISO1252Encoding");
+ }
+ else
+ if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END)
+ {
+ return rFontName
+ + OString("Enc")
+ + OString::valueOf ((sal_Int32)(nEnc - RTL_TEXTENCODING_USER_START));
+ }
+ else
+ {
+ return OString();
+ }
+}
+
+OString
+GlyphSet::GetGlyphSetEncodingName (sal_Int32 nGlyphSetID)
+{
+ return GetGlyphSetEncodingName (GetGlyphSetEncoding(nGlyphSetID), maBaseName);
+}
+
+void
+GlyphSet::PSDefineReencodedFont (osl::File* pOutFile, sal_Int32 nGlyphSetID)
+{
+ // only for ps fonts
+ if ((meBaseType != fonttype::Builtin) && (meBaseType != fonttype::Type1))
+ return;
+
+ sal_Char pEncodingVector [256];
+ sal_Int32 nSize = 0;
+
+ nSize += psp::appendStr ("(", pEncodingVector + nSize);
+ nSize += psp::appendStr (GetReencodedFontName(nGlyphSetID),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (") cvn (", pEncodingVector + nSize);
+ nSize += psp::appendStr (maBaseName.getStr(),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (") cvn ", pEncodingVector + nSize);
+ nSize += psp::appendStr (GetGlyphSetEncodingName(nGlyphSetID),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (" psp_definefont\n",
+ pEncodingVector + nSize);
+
+ psp::WritePS (pOutFile, pEncodingVector);
+}
+
+OString
+GlyphSet::GetReencodedFontName (rtl_TextEncoding nEnc, const OString &rFontName)
+{
+ if ( nEnc == RTL_TEXTENCODING_MS_1252
+ || nEnc == RTL_TEXTENCODING_ISO_8859_1)
+ {
+ return rFontName
+ + OString("-iso1252");
+ }
+ else
+ if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END)
+ {
+ return rFontName
+ + OString("-enc")
+ + OString::valueOf ((sal_Int32)(nEnc - RTL_TEXTENCODING_USER_START));
+ }
+ else
+ {
+ return OString();
+ }
+}
+
+OString
+GlyphSet::GetReencodedFontName (sal_Int32 nGlyphSetID)
+{
+ return GetReencodedFontName (GetGlyphSetEncoding(nGlyphSetID), maBaseName);
+}
+
+void GlyphSet::DrawGlyphs(
+ PrinterGfx& rGfx,
+ const Point& rPoint,
+ const sal_uInt32* pGlyphIds,
+ const sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray )
+{
+ sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+ sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ std::set< sal_Int32 > aGlyphSet;
+
+ // convert unicode to font glyph id and font subset
+ for (int nChar = 0; nChar < nLen; nChar++)
+ {
+ GetGlyphID (pGlyphIds[nChar], pUnicodes[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
+ aGlyphSet.insert (pGlyphSetID[nChar]);
+ }
+
+ // loop over all glyph sets to detect substrings that can be xshown together
+ // without changing the postscript font
+ sal_Int32 *pDeltaSubset = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ sal_uChar *pGlyphSubset = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+
+ std::set< sal_Int32 >::iterator aSet;
+ for (aSet = aGlyphSet.begin(); aSet != aGlyphSet.end(); ++aSet)
+ {
+ Point aPoint = rPoint;
+ sal_Int32 nOffset = 0;
+ sal_Int32 nGlyphs = 0;
+ sal_Int32 nChar;
+
+ // get offset to first glyph
+ for (nChar = 0; (nChar < nLen) && (pGlyphSetID[nChar] != *aSet); nChar++)
+ {
+ nOffset = pDeltaArray [nChar];
+ }
+
+ // loop over all chars to extract those that share the current glyph set
+ for (nChar = 0; nChar < nLen; nChar++)
+ {
+ if (pGlyphSetID[nChar] == *aSet)
+ {
+ pGlyphSubset [nGlyphs] = pGlyphID [nChar];
+ // the offset to the next glyph is determined by the glyph in
+ // front of the next glyph with the same glyphset id
+ // most often, this will be the current glyph
+ while ((nChar + 1) < nLen)
+ {
+ if (pGlyphSetID[nChar + 1] == *aSet)
+ break;
+ else
+ nChar += 1;
+ }
+ pDeltaSubset [nGlyphs] = pDeltaArray[nChar] - nOffset;
+
+ nGlyphs += 1;
+ }
+ }
+
+ // show the text using the PrinterGfx text api
+ aPoint.Move (nOffset, 0);
+
+ OString aGlyphSetName(GetGlyphSetName(*aSet));
+ rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(*aSet));
+ rGfx.PSMoveTo (aPoint);
+ rGfx.PSShowText (pGlyphSubset, nGlyphs, nGlyphs, nGlyphs > 1 ? pDeltaSubset : NULL);
+ }
+}
+
+void
+GlyphSet::DrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ // dispatch to the impl method
+ if (pDeltaArray == NULL)
+ ImplDrawText (rGfx, rPoint, pStr, nLen);
+ else
+ ImplDrawText (rGfx, rPoint, pStr, nLen, pDeltaArray);
+}
+
+void
+GlyphSet::ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen)
+{
+ rGfx.PSMoveTo (rPoint);
+
+ if( mbUseFontEncoding )
+ {
+ OString aPSName( OUStringToOString( rGfx.GetFontMgr().getPSName( mnFontID ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ OString aBytes( OUStringToOString( OUString( pStr, nLen ), mnBaseEncoding ) );
+ rGfx.PSSetFont( aPSName, mnBaseEncoding );
+ rGfx.PSShowText( (const unsigned char*)aBytes.getStr(), nLen, aBytes.getLength() );
+ return;
+ }
+
+ int nChar;
+ sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+ sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+
+ // convert unicode to glyph id and char set (font subset)
+ for (nChar = 0; nChar < nLen; nChar++)
+ GetCharID (pStr[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
+
+ // loop over the string to draw subsequent pieces of chars
+ // with the same postscript font
+ for (nChar = 0; nChar < nLen; /* atend */)
+ {
+ sal_Int32 nGlyphSetID = pGlyphSetID [nChar];
+ sal_Int32 nGlyphs = 1;
+ for (int nNextChar = nChar + 1; nNextChar < nLen; nNextChar++)
+ {
+ if (pGlyphSetID[nNextChar] == nGlyphSetID)
+ nGlyphs++;
+ else
+ break;
+ }
+
+ // show the text using the PrinterGfx text api
+ OString aGlyphSetName(GetCharSetName(nGlyphSetID));
+ rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(nGlyphSetID));
+ rGfx.PSShowText (pGlyphID + nChar, nGlyphs, nGlyphs);
+
+ nChar += nGlyphs;
+ }
+}
+
+void
+GlyphSet::ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ if( mbUseFontEncoding )
+ {
+ OString aPSName( OUStringToOString( rGfx.GetFontMgr().getPSName( mnFontID ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ OString aBytes( OUStringToOString( OUString( pStr, nLen ), mnBaseEncoding ) );
+ rGfx.PSMoveTo( rPoint );
+ rGfx.PSSetFont( aPSName, mnBaseEncoding );
+ rGfx.PSShowText( (const unsigned char*)aBytes.getStr(), nLen, aBytes.getLength(), pDeltaArray );
+ return;
+ }
+
+ sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+ sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ std::set< sal_Int32 > aGlyphSet;
+
+ // convert unicode to font glyph id and font subset
+ for (int nChar = 0; nChar < nLen; nChar++)
+ {
+ GetCharID (pStr[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
+ aGlyphSet.insert (pGlyphSetID[nChar]);
+ }
+
+ // loop over all glyph sets to detect substrings that can be xshown together
+ // without changing the postscript font
+ sal_Int32 *pDeltaSubset = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ sal_uChar *pGlyphSubset = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+
+ std::set< sal_Int32 >::iterator aSet;
+ for (aSet = aGlyphSet.begin(); aSet != aGlyphSet.end(); ++aSet)
+ {
+ Point aPoint = rPoint;
+ sal_Int32 nOffset = 0;
+ sal_Int32 nGlyphs = 0;
+ sal_Int32 nChar;
+
+ // get offset to first glyph
+ for (nChar = 0; (nChar < nLen) && (pGlyphSetID[nChar] != *aSet); nChar++)
+ {
+ nOffset = pDeltaArray [nChar];
+ }
+
+ // loop over all chars to extract those that share the current glyph set
+ for (nChar = 0; nChar < nLen; nChar++)
+ {
+ if (pGlyphSetID[nChar] == *aSet)
+ {
+ pGlyphSubset [nGlyphs] = pGlyphID [nChar];
+ // the offset to the next glyph is determined by the glyph in
+ // front of the next glyph with the same glyphset id
+ // most often, this will be the current glyph
+ while ((nChar + 1) < nLen)
+ {
+ if (pGlyphSetID[nChar + 1] == *aSet)
+ break;
+ else
+ nChar += 1;
+ }
+ pDeltaSubset [nGlyphs] = pDeltaArray[nChar] - nOffset;
+
+ nGlyphs += 1;
+ }
+ }
+
+ // show the text using the PrinterGfx text api
+ aPoint.Move (nOffset, 0);
+
+ OString aGlyphSetName(GetCharSetName(*aSet));
+ rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(*aSet));
+ rGfx.PSMoveTo (aPoint);
+ rGfx.PSShowText (pGlyphSubset, nGlyphs, nGlyphs, nGlyphs > 1 ? pDeltaSubset : NULL);
+ }
+}
+
+sal_Bool
+GlyphSet::PSUploadEncoding(osl::File* pOutFile, PrinterGfx &rGfx)
+{
+ // only for ps fonts
+ if ((meBaseType != fonttype::Builtin) && (meBaseType != fonttype::Type1))
+ return sal_False;
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ return sal_False;
+
+ PrintFontManager &rMgr = rGfx.GetFontMgr();
+
+ // loop thru all the font subsets
+ sal_Int32 nGlyphSetID = 0;
+ char_list_t::iterator aGlyphSet;
+ for (aGlyphSet = maCharList.begin(); aGlyphSet != maCharList.end(); ++aGlyphSet)
+ {
+ ++nGlyphSetID;
+
+ if (nGlyphSetID == 1) // latin1 page uses global reencoding table
+ {
+ PSDefineReencodedFont (pOutFile, nGlyphSetID);
+ continue;
+ }
+ if ((*aGlyphSet).size() == 0) // empty set, doesn't need reencoding
+ {
+ continue;
+ }
+
+ // create reencoding table
+
+ sal_Char pEncodingVector [256];
+ sal_Int32 nSize = 0;
+
+ nSize += psp::appendStr ("/",
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (GetGlyphSetEncodingName(nGlyphSetID),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (" [ ",
+ pEncodingVector + nSize);
+
+ // need a list of glyphs, sorted by glyphid
+ typedef std::map< sal_uInt8, sal_Unicode > ps_mapping_t;
+ typedef ps_mapping_t::value_type ps_value_t;
+ ps_mapping_t aSortedGlyphSet;
+
+ char_map_t::const_iterator aUnsortedGlyph;
+ for (aUnsortedGlyph = (*aGlyphSet).begin();
+ aUnsortedGlyph != (*aGlyphSet).end();
+ ++aUnsortedGlyph)
+ {
+ aSortedGlyphSet.insert(ps_value_t((*aUnsortedGlyph).second,
+ (*aUnsortedGlyph).first));
+ }
+
+ ps_mapping_t::const_iterator aSortedGlyph;
+ // loop thru all the glyphs in the subset
+ for (aSortedGlyph = (aSortedGlyphSet).begin();
+ aSortedGlyph != (aSortedGlyphSet).end();
+ ++aSortedGlyph)
+ {
+ nSize += psp::appendStr ("/",
+ pEncodingVector + nSize);
+
+ std::list< OString > aName( rMgr.getAdobeNameFromUnicode((*aSortedGlyph).second) );
+
+ if( aName.begin() != aName.end() )
+ nSize += psp::appendStr ( aName.front(), pEncodingVector + nSize);
+ else
+ nSize += psp::appendStr (".notdef", pEncodingVector + nSize );
+ nSize += psp::appendStr (" ", pEncodingVector + nSize);
+ // flush line
+ if (nSize >= 70)
+ {
+ nSize += psp::appendStr ("\n", pEncodingVector + nSize);
+ psp::WritePS (pOutFile, pEncodingVector);
+ nSize = 0;
+ }
+ }
+
+ nSize += psp::appendStr ("] def\n", pEncodingVector + nSize);
+ psp::WritePS (pOutFile, pEncodingVector);
+
+ PSDefineReencodedFont (pOutFile, nGlyphSetID);
+ }
+
+ return sal_True;
+}
+
+struct EncEntry
+{
+ sal_uChar aEnc;
+ long aGID;
+
+ EncEntry() : aEnc( 0 ), aGID( 0 ) {}
+
+ bool operator<( const EncEntry& rRight ) const
+ { return aEnc < rRight.aEnc; }
+};
+
+static void CreatePSUploadableFont( TrueTypeFont* pSrcFont, FILE* pTmpFile,
+ const char* pGlyphSetName, int nGlyphCount,
+ /*const*/ sal_uInt16* pRequestedGlyphs, /*const*/ sal_uChar* pEncoding,
+ bool bAllowType42, bool /*bAllowCID*/ )
+{
+ // match the font-subset to the printer capabilities
+ // TODO: allow CFF for capable printers
+ int nTargetMask = FontSubsetInfo::TYPE1_PFA | FontSubsetInfo::TYPE3_FONT;
+ if( bAllowType42 )
+ nTargetMask |= FontSubsetInfo::TYPE42_FONT;
+
+ std::vector< EncEntry > aSorted( nGlyphCount, EncEntry() );
+ for( int i = 0; i < nGlyphCount; i++ )
+ {
+ aSorted[i].aEnc = pEncoding[i];
+ aSorted[i].aGID = pRequestedGlyphs[i];
+ }
+
+ std::stable_sort( aSorted.begin(), aSorted.end() );
+
+ std::vector< sal_uChar > aEncoding( nGlyphCount );
+ std::vector< long > aRequestedGlyphs( nGlyphCount );
+
+ for( int i = 0; i < nGlyphCount; i++ )
+ {
+ aEncoding[i] = aSorted[i].aEnc;
+ aRequestedGlyphs[i] = aSorted[i].aGID;
+ }
+
+ FontSubsetInfo aInfo;
+ aInfo.LoadFont( pSrcFont );
+
+ aInfo.CreateFontSubset( nTargetMask, pTmpFile, pGlyphSetName,
+ &aRequestedGlyphs[0], &aEncoding[0], nGlyphCount, NULL );
+}
+
+sal_Bool
+GlyphSet::PSUploadFont (osl::File& rOutFile, PrinterGfx &rGfx, bool bAllowType42, std::list< OString >& rSuppliedFonts )
+{
+ // only for truetype fonts
+ if (meBaseType != fonttype::TrueType)
+ return sal_False;
+
+ TrueTypeFont *pTTFont;
+ OString aTTFileName (rGfx.GetFontMgr().getFontFileSysPath(mnFontID));
+ int nFace = rGfx.GetFontMgr().getFontFaceNumber(mnFontID);
+ sal_Int32 nSuccess = OpenTTFontFile(aTTFileName.getStr(), nFace < 0 ? 0 : nFace, &pTTFont);
+ if (nSuccess != SF_OK)
+ return sal_False;
+ FILE* pTmpFile = tmpfile();
+ if (pTmpFile == NULL)
+ return sal_False;
+
+ // array of unicode source characters
+ sal_Unicode pUChars[256];
+
+ // encoding vector maps character encoding to the ordinal number
+ // of the glyph in the output file
+ sal_uChar pEncoding[256];
+ sal_uInt16 pTTGlyphMapping[256];
+ const bool bAllowCID = false; // TODO: nPSLanguageLevel>=3
+
+ // loop thru all the font subsets
+ sal_Int32 nCharSetID;
+ char_list_t::iterator aCharSet;
+ for (aCharSet = maCharList.begin(), nCharSetID = 1;
+ aCharSet != maCharList.end();
+ ++aCharSet, nCharSetID++)
+ {
+ if ((*aCharSet).size() == 0)
+ continue;
+
+ // loop thru all the chars in the subset
+ char_map_t::const_iterator aChar;
+ sal_Int32 n = 0;
+ for (aChar = (*aCharSet).begin(); aChar != (*aCharSet).end(); ++aChar)
+ {
+ pUChars [n] = (*aChar).first;
+ pEncoding [n] = (*aChar).second;
+ n++;
+ }
+ // create a mapping from the unicode chars to the char encoding in
+ // source TrueType font
+ MapString (pTTFont, pUChars, (*aCharSet).size(), pTTGlyphMapping, mbVertical);
+
+ // create the current subset
+ OString aCharSetName = GetCharSetName(nCharSetID);
+ fprintf( pTmpFile, "%%%%BeginResource: font %s\n", aCharSetName.getStr() );
+ CreatePSUploadableFont( pTTFont, pTmpFile, aCharSetName.getStr(), (*aCharSet).size(),
+ pTTGlyphMapping, pEncoding, bAllowType42, bAllowCID );
+ fprintf( pTmpFile, "%%%%EndResource\n" );
+ rSuppliedFonts.push_back( aCharSetName );
+ }
+
+ // loop thru all the font glyph subsets
+ sal_Int32 nGlyphSetID;
+ glyph_list_t::iterator aGlyphSet;
+ for (aGlyphSet = maGlyphList.begin(), nGlyphSetID = 1;
+ aGlyphSet != maGlyphList.end();
+ ++aGlyphSet, nGlyphSetID++)
+ {
+ if ((*aGlyphSet).size() == 0)
+ continue;
+
+ // loop thru all the glyphs in the subset
+ glyph_map_t::const_iterator aGlyph;
+ sal_Int32 n = 0;
+ for (aGlyph = (*aGlyphSet).begin(); aGlyph != (*aGlyphSet).end(); ++aGlyph)
+ {
+ pTTGlyphMapping [n] = (*aGlyph).first;
+ pEncoding [n] = (*aGlyph).second;
+ n++;
+ }
+
+ // create the current subset
+ OString aGlyphSetName = GetGlyphSetName(nGlyphSetID);
+ fprintf( pTmpFile, "%%%%BeginResource: font %s\n", aGlyphSetName.getStr() );
+ CreatePSUploadableFont( pTTFont, pTmpFile, aGlyphSetName.getStr(), (*aGlyphSet).size(),
+ pTTGlyphMapping, pEncoding, bAllowType42, bAllowCID );
+ fprintf( pTmpFile, "%%%%EndResource\n" );
+ rSuppliedFonts.push_back( aGlyphSetName );
+ }
+
+ // copy the file into the page header
+ rewind(pTmpFile);
+ fflush(pTmpFile);
+
+ sal_uChar pBuffer[0x2000];
+ sal_uInt64 nIn;
+ sal_uInt64 nOut;
+ do
+ {
+ nIn = fread(pBuffer, 1, sizeof(pBuffer), pTmpFile);
+ rOutFile.write (pBuffer, nIn, nOut);
+ }
+ while ((nIn == nOut) && !feof(pTmpFile));
+
+ // cleanup
+ CloseTTFont (pTTFont);
+ fclose (pTmpFile);
+
+ return sal_True;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/printergfx/glyphset.hxx b/vcl/unx/generic/printergfx/glyphset.hxx
new file mode 100644
index 000000000000..c8b009c91155
--- /dev/null
+++ b/vcl/unx/generic/printergfx/glyphset.hxx
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _PSPRINT_GLYPHSET_HXX_
+#define _PSPRINT_GLYPHSET_HXX_
+
+#include "vcl/fontmanager.hxx"
+
+#include "osl/file.hxx"
+
+#include "rtl/string.hxx"
+
+#include "tools/gen.hxx"
+
+#include <list>
+#include <boost/unordered_map.hpp>
+
+namespace psp {
+
+class PrinterGfx;
+class PrintFontManager;
+
+class GlyphSet
+{
+private:
+
+ sal_Int32 mnFontID;
+ sal_Bool mbVertical;
+ rtl::OString maBaseName;
+ fonttype::type meBaseType;
+ rtl_TextEncoding mnBaseEncoding;
+ bool mbUseFontEncoding;
+
+ typedef boost::unordered_map< sal_Unicode, sal_uInt8 > char_map_t;
+ typedef std::list< char_map_t > char_list_t;
+ typedef boost::unordered_map< sal_uInt32, sal_uInt8 > glyph_map_t;
+ typedef std::list< glyph_map_t > glyph_list_t;
+
+ char_list_t maCharList;
+ glyph_list_t maGlyphList;
+
+ rtl::OString GetGlyphSetName (sal_Int32 nGlyphSetID);
+ rtl::OString GetCharSetName (sal_Int32 nGlyphSetID);
+ sal_Int32 GetGlyphSetEncoding (sal_Int32 nGlyphSetID);
+ rtl::OString GetGlyphSetEncodingName (sal_Int32 nGlyphSetID);
+
+ rtl::OString GetReencodedFontName (sal_Int32 nGlyphSetID);
+ void PSDefineReencodedFont (osl::File* pOutFile,
+ sal_Int32 nGlyphSetID);
+
+ sal_Bool GetCharID (sal_Unicode nChar,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool LookupCharID (sal_Unicode nChar,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool AddCharID (sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID);
+ sal_Bool GetGlyphID (sal_uInt32 nGlyph, sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool LookupGlyphID (sal_uInt32 nGlyph,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool AddGlyphID (sal_uInt32 nGlyph, sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID);
+ void AddNotdef (char_map_t &rCharMap);
+ void AddNotdef (glyph_map_t &rGlyphMap);
+ sal_uChar GetAnsiMapping (sal_Unicode nUnicodeChar);
+ sal_uChar GetSymbolMapping (sal_Unicode nUnicodeChar);
+
+ void ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen);
+ void ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen,
+ const sal_Int32* pDeltaArray);
+
+public:
+
+ GlyphSet ();
+ GlyphSet (sal_Int32 nFontID, sal_Bool bVertical);
+ ~GlyphSet ();
+
+ sal_Int32 GetFontID ();
+ fonttype::type GetFontType ();
+ static rtl::OString
+ GetReencodedFontName (rtl_TextEncoding nEnc,
+ const rtl::OString &rFontName);
+ static rtl::OString
+ GetGlyphSetEncodingName (rtl_TextEncoding nEnc,
+ const rtl::OString &rFontName);
+ sal_Bool IsVertical ();
+
+ sal_Bool SetFont (sal_Int32 nFontID, sal_Bool bVertical);
+
+ void DrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen,
+ const sal_Int32* pDeltaArray = NULL);
+ void DrawGlyphs (PrinterGfx& rGfx,
+ const Point& rPoint,
+ const sal_uInt32* pGlyphIds,
+ const sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray );
+ sal_Bool PSUploadEncoding(osl::File* pOutFile, PrinterGfx &rGfx);
+ sal_Bool PSUploadFont (osl::File& rOutFile, PrinterGfx &rGfx, bool bAsType42, std::list< rtl::OString >& rSuppliedFonts );
+};
+
+
+} /* namespace psp */
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/printergfx/printerjob.cxx b/vcl/unx/generic/printergfx/printerjob.cxx
new file mode 100644
index 000000000000..827b5c7cf269
--- /dev/null
+++ b/vcl/unx/generic/printergfx/printerjob.cxx
@@ -0,0 +1,1212 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#include "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "printerjob.hxx"
+#include "printergfx.hxx"
+#include "vcl/ppdparser.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include "rtl/ustring.hxx"
+#include "rtl/strbuf.hxx"
+#include "rtl/ustrbuf.hxx"
+
+#include "osl/thread.h"
+#include "sal/alloca.h"
+#include <sal/macros.h>
+
+#include <algorithm>
+#include <vector>
+
+using namespace psp;
+
+using ::rtl::OUString;
+using ::rtl::OUStringToOString;
+using ::rtl::OString;
+using ::rtl::OStringBuffer;
+
+// forward declaration
+
+#define nBLOCKSIZE 0x2000
+
+namespace psp
+{
+
+sal_Bool
+AppendPS (FILE* pDst, osl::File* pSrc, sal_uChar* pBuffer,
+ sal_uInt32 nBlockSize = nBLOCKSIZE)
+{
+ if ((pDst == NULL) || (pSrc == NULL))
+ return sal_False;
+
+ if (nBlockSize == 0)
+ nBlockSize = nBLOCKSIZE;
+ if (pBuffer == NULL)
+ pBuffer = (sal_uChar*)alloca (nBlockSize);
+
+ pSrc->setPos (osl_Pos_Absolut, 0);
+
+ sal_uInt64 nIn = 0;
+ sal_uInt64 nOut = 0;
+ do
+ {
+ pSrc->read (pBuffer, nBlockSize, nIn);
+ if (nIn > 0)
+ nOut = fwrite (pBuffer, 1, sal::static_int_cast<sal_uInt32>(nIn), pDst);
+ }
+ while ((nIn > 0) && (nIn == nOut));
+
+ return sal_True;
+}
+
+} // namespace psp
+
+/*
+ * private convenience routines for file handling
+ */
+
+osl::File*
+PrinterJob::CreateSpoolFile (const rtl::OUString& rName, const rtl::OUString& rExtension)
+{
+ osl::File::RC nError = osl::File::E_None;
+ osl::File* pFile = NULL;
+
+ rtl::OUString aFile = rName + rExtension;
+ rtl::OUString aFileURL;
+ nError = osl::File::getFileURLFromSystemPath( aFile, aFileURL );
+ if (nError != osl::File::E_None)
+ return NULL;
+ aFileURL = maSpoolDirName + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("/")) + aFileURL;
+
+ pFile = new osl::File (aFileURL);
+ nError = pFile->open (osl_File_OpenFlag_Read | osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
+ if (nError != osl::File::E_None)
+ {
+ delete pFile;
+ return NULL;
+ }
+
+ pFile->setAttributes (aFileURL,
+ osl_File_Attribute_OwnWrite | osl_File_Attribute_OwnRead);
+ return pFile;
+}
+
+/*
+ * public methods of PrinterJob: for use in PrinterGfx
+ */
+
+void
+PrinterJob::GetScale (double &rXScale, double &rYScale) const
+{
+ rXScale = mfXScale;
+ rYScale = mfYScale;
+}
+
+sal_uInt16
+PrinterJob::GetDepth () const
+{
+ sal_Int32 nLevel = GetPostscriptLevel();
+ sal_Bool bColor = IsColorPrinter ();
+
+ return nLevel > 1 && bColor ? 24 : 8;
+}
+
+sal_uInt16
+PrinterJob::GetPostscriptLevel (const JobData *pJobData) const
+{
+ sal_uInt16 nPSLevel = 2;
+
+ if( pJobData == NULL )
+ pJobData = &m_aLastJobData;
+
+ if( pJobData->m_nPSLevel )
+ nPSLevel = pJobData->m_nPSLevel;
+ else
+ if( pJobData->m_pParser )
+ nPSLevel = pJobData->m_pParser->getLanguageLevel();
+
+ return nPSLevel;
+}
+
+sal_Bool
+PrinterJob::IsColorPrinter () const
+{
+ sal_Bool bColor = sal_False;
+
+ if( m_aLastJobData.m_nColorDevice )
+ bColor = m_aLastJobData.m_nColorDevice == -1 ? sal_False : sal_True;
+ else if( m_aLastJobData.m_pParser )
+ bColor = m_aLastJobData.m_pParser->isColorDevice() ? sal_True : sal_False;
+
+ return bColor;
+}
+
+osl::File*
+PrinterJob::GetDocumentHeader ()
+{
+ return mpJobHeader;
+}
+
+osl::File*
+PrinterJob::GetDocumentTrailer ()
+{
+ return mpJobTrailer;
+}
+
+osl::File*
+PrinterJob::GetCurrentPageHeader ()
+{
+ return maHeaderList.back();
+}
+
+osl::File*
+PrinterJob::GetCurrentPageBody ()
+{
+ return maPageList.back();
+}
+
+/*
+ * public methods of PrinterJob: the actual job / spool handling
+ */
+
+PrinterJob::PrinterJob () :
+ mpJobHeader( NULL ),
+ mpJobTrailer( NULL ),
+ m_bQuickJob( false )
+{
+}
+
+namespace psp
+{
+
+/* check whether the given name points to a directory which is
+ usable for the user */
+sal_Bool
+existsTmpDir (const char* pName)
+{
+ struct stat aFileStatus;
+
+ if (pName == NULL)
+ return sal_False;
+ if (stat(pName, &aFileStatus) != 0)
+ return sal_False;
+ if (! S_ISDIR(aFileStatus.st_mode))
+ return sal_False;
+
+ return access(pName, W_OK | R_OK) == 0 ? sal_True : sal_False;
+}
+
+/* return the username in the given buffer */
+sal_Bool
+getUserName (char* pName, int nSize)
+{
+ struct passwd *pPWEntry;
+ struct passwd aPWEntry;
+ sal_Char pPWBuffer[256];
+
+ sal_Bool bSuccess = sal_False;
+
+#ifdef FREEBSD
+ pPWEntry = getpwuid( getuid());
+#else
+ if (getpwuid_r(getuid(), &aPWEntry, pPWBuffer, sizeof(pPWBuffer), &pPWEntry) != 0)
+ pPWEntry = NULL;
+#endif
+
+ if (pPWEntry != NULL && pPWEntry->pw_name != NULL)
+ {
+ sal_Int32 nLen = strlen(pPWEntry->pw_name);
+ if (nLen > 0 && nLen < nSize)
+ {
+ memcpy (pName, pPWEntry->pw_name, nLen);
+ pName[nLen] = '\0';
+
+ bSuccess = sal_True;
+ }
+ }
+
+ // wipe the passwd off the stack
+ memset (pPWBuffer, 0, sizeof(pPWBuffer));
+
+ return bSuccess;
+}
+
+/* remove all our temporary files, uses external program "rm", since
+ osl functionality is inadequate */
+void
+removeSpoolDir (const rtl::OUString& rSpoolDir)
+{
+ rtl::OUString aSysPath;
+ if( osl::File::E_None != osl::File::getSystemPathFromFileURL( rSpoolDir, aSysPath ) )
+ {
+ // Conversion did not work, as this is quite a dangerous action,
+ // we should abort here ....
+ OSL_FAIL( "psprint: couldn't remove spool directory" );
+ return;
+ }
+ rtl::OString aSysPathByte =
+ rtl::OUStringToOString (aSysPath, osl_getThreadTextEncoding());
+ sal_Char pSystem [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("rm -rf ", pSystem);
+ nChar += psp::appendStr (aSysPathByte.getStr(), pSystem + nChar);
+
+ if (system (pSystem) == -1)
+ OSL_FAIL( "psprint: couldn't remove spool directory" );
+}
+
+/* creates a spool directory with a "pidgin random" value based on
+ current system time */
+rtl::OUString
+createSpoolDir ()
+{
+ TimeValue aCur;
+ osl_getSystemTime( &aCur );
+ sal_Int32 nRand = aCur.Seconds ^ (aCur.Nanosec/1000);
+
+ rtl::OUString aTmpDir;
+ osl_getTempDirURL( &aTmpDir.pData );
+
+ do
+ {
+ rtl::OUStringBuffer aDir( aTmpDir.getLength() + 16 );
+ aDir.append( aTmpDir );
+ aDir.appendAscii( "/psp" );
+ aDir.append(nRand);
+ rtl::OUString aResult = aDir.makeStringAndClear();
+ if( osl::Directory::create( aResult ) == osl::FileBase::E_None )
+ {
+ osl::File::setAttributes( aResult,
+ osl_File_Attribute_OwnWrite
+ | osl_File_Attribute_OwnRead
+ | osl_File_Attribute_OwnExe );
+ return aResult;
+ }
+ nRand++;
+ } while( nRand );
+ return rtl::OUString();
+}
+
+} // namespace psp
+
+PrinterJob::~PrinterJob ()
+{
+ std::list< osl::File* >::iterator pPage;
+ for (pPage = maPageList.begin(); pPage != maPageList.end(); ++pPage)
+ {
+ //(*pPage)->remove();
+ delete *pPage;
+ }
+ for (pPage = maHeaderList.begin(); pPage != maHeaderList.end(); ++pPage)
+ {
+ //(*pPage)->remove();
+ delete *pPage;
+ }
+ // mpJobHeader->remove();
+ delete mpJobHeader;
+ // mpJobTrailer->remove();
+ delete mpJobTrailer;
+
+ // XXX should really call osl::remove routines
+ if( maSpoolDirName.getLength() )
+ removeSpoolDir (maSpoolDirName);
+
+ // osl::Directory::remove (maSpoolDirName);
+}
+
+namespace psp
+{
+
+// get locale invariant, 7bit clean current local time string
+sal_Char*
+getLocalTime(sal_Char* pBuffer)
+{
+ time_t nTime = time (NULL);
+ struct tm aTime;
+ struct tm *pLocalTime = localtime_r (&nTime, &aTime);
+
+ return asctime_r(pLocalTime, pBuffer);
+}
+
+}
+
+static bool isAscii( const rtl::OUString& rStr )
+{
+ const sal_Unicode* pStr = rStr;
+ sal_Int32 nLen = rStr.getLength();
+ for( sal_Int32 i = 0; i < nLen; i++ )
+ if( pStr[i] > 127 )
+ return false;
+ return true;
+}
+
+sal_Bool
+PrinterJob::StartJob (
+ const rtl::OUString& rFileName,
+ int nMode,
+ const rtl::OUString& rJobName,
+ const rtl::OUString& rAppName,
+ const JobData& rSetupData,
+ PrinterGfx* pGraphics,
+ bool bIsQuickJob
+ )
+{
+ m_bQuickJob = bIsQuickJob;
+ mnMaxWidthPt = mnMaxHeightPt = 0;
+ mnLandscapes = mnPortraits = 0;
+ m_pGraphics = pGraphics;
+ InitPaperSize (rSetupData);
+
+ // create file container for document header and trailer
+ maFileName = rFileName;
+ mnFileMode = nMode;
+ maSpoolDirName = createSpoolDir ();
+ maJobTitle = rJobName;
+
+ rtl::OUString aExt(RTL_CONSTASCII_USTRINGPARAM (".ps"));
+ mpJobHeader = CreateSpoolFile (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("psp_head")), aExt);
+ mpJobTrailer = CreateSpoolFile (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("psp_tail")), aExt);
+ if( ! (mpJobHeader && mpJobTrailer) ) // existing files are removed in destructor
+ return sal_False;
+
+ // write document header according to Document Structuring Conventions (DSC)
+ WritePS (mpJobHeader,
+ "%!PS-Adobe-3.0\n"
+ "%%BoundingBox: (atend)\n" );
+
+ rtl::OUString aFilterWS;
+
+ // Creator (this application)
+ aFilterWS = WhitespaceToSpace( rAppName, sal_False );
+ WritePS (mpJobHeader, "%%Creator: (");
+ WritePS (mpJobHeader, aFilterWS);
+ WritePS (mpJobHeader, ")\n");
+
+ // For (user name)
+ sal_Char pUserName[64];
+ if (getUserName(pUserName, sizeof(pUserName)))
+ {
+ WritePS (mpJobHeader, "%%For: (");
+ WritePS (mpJobHeader, pUserName);
+ WritePS (mpJobHeader, ")\n");
+ }
+
+ // Creation Date (locale independent local time)
+ sal_Char pCreationDate [256];
+ WritePS (mpJobHeader, "%%CreationDate: (");
+ getLocalTime(pCreationDate);
+ for( unsigned int i = 0; i < SAL_N_ELEMENTS(pCreationDate); i++ )
+ {
+ if( pCreationDate[i] == '\n' )
+ {
+ pCreationDate[i] = 0;
+ break;
+ }
+ }
+ WritePS (mpJobHeader, pCreationDate );
+ WritePS (mpJobHeader, ")\n");
+
+ // Document Title
+ /* #i74335#
+ * The title should be clean ascii; rJobName however may
+ * contain any Unicode character. So implement the following
+ * algorithm:
+ * use rJobName, if it contains only ascii
+ * use the filename, if it contains only ascii
+ * else omit %%Title
+ */
+ aFilterWS = WhitespaceToSpace( rJobName, sal_False );
+ rtl::OUString aTitle( aFilterWS );
+ if( ! isAscii( aTitle ) )
+ {
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ aTitle = rFileName.getToken( 0, '/', nIndex );
+ aTitle = WhitespaceToSpace( aTitle, sal_False );
+ if( ! isAscii( aTitle ) )
+ aTitle = rtl::OUString();
+ }
+
+ maJobTitle = aFilterWS;
+ if( aTitle.getLength() )
+ {
+ WritePS (mpJobHeader, "%%Title: (");
+ WritePS (mpJobHeader, aTitle);
+ WritePS (mpJobHeader, ")\n");
+ }
+
+ // Language Level
+ sal_Char pLevel[16];
+ sal_Int32 nSz = getValueOf(GetPostscriptLevel(&rSetupData), pLevel);
+ pLevel[nSz++] = '\n';
+ pLevel[nSz ] = '\0';
+ WritePS (mpJobHeader, "%%LanguageLevel: ");
+ WritePS (mpJobHeader, pLevel);
+
+ // Other
+ WritePS (mpJobHeader, "%%DocumentData: Clean7Bit\n");
+ WritePS (mpJobHeader, "%%Pages: (atend)\n");
+ WritePS (mpJobHeader, "%%Orientation: (atend)\n");
+ WritePS (mpJobHeader, "%%PageOrder: Ascend\n");
+ WritePS (mpJobHeader, "%%EndComments\n");
+
+ // write Prolog
+ writeProlog (mpJobHeader, rSetupData);
+
+ // mark last job setup as not set
+ m_aLastJobData.m_pParser = NULL;
+ m_aLastJobData.m_aContext.setParser( NULL );
+
+ return sal_True;
+}
+
+sal_Bool
+PrinterJob::EndJob ()
+{
+ // no pages ? that really means no print job
+ if( maPageList.empty() )
+ return sal_False;
+
+ // write document setup (done here because it
+ // includes the accumulated fonts
+ if( mpJobHeader )
+ writeSetup( mpJobHeader, m_aDocumentJobData );
+ m_pGraphics->OnEndJob();
+ if( ! (mpJobHeader && mpJobTrailer) )
+ return sal_False;
+
+ // write document trailer according to Document Structuring Conventions (DSC)
+ rtl::OStringBuffer aTrailer(512);
+ aTrailer.append( "%%Trailer\n" );
+ aTrailer.append( "%%BoundingBox: 0 0 " );
+ aTrailer.append( (sal_Int32)mnMaxWidthPt );
+ aTrailer.append( " " );
+ aTrailer.append( (sal_Int32)mnMaxHeightPt );
+ if( mnLandscapes > mnPortraits )
+ aTrailer.append("\n%%Orientation: Landscape");
+ else
+ aTrailer.append("\n%%Orientation: Portrait");
+ aTrailer.append( "\n%%Pages: " );
+ aTrailer.append( (sal_Int32)maPageList.size() );
+ aTrailer.append( "\n%%EOF\n" );
+ WritePS (mpJobTrailer, aTrailer.getStr());
+
+ /*
+ * spool the set of files to their final destination, this is U**X dependent
+ */
+
+ FILE* pDestFILE = NULL;
+
+ /* create a destination either as file or as a pipe */
+ sal_Bool bSpoolToFile = maFileName.getLength() > 0 ? sal_True : sal_False;
+ if (bSpoolToFile)
+ {
+ const rtl::OString aFileName = rtl::OUStringToOString (maFileName,
+ osl_getThreadTextEncoding());
+ if( mnFileMode )
+ {
+ int nFile = open( aFileName.getStr(), O_CREAT | O_EXCL | O_RDWR, mnFileMode );
+ if( nFile != -1 )
+ {
+ pDestFILE = fdopen( nFile, "w" );
+ if( pDestFILE == NULL )
+ {
+ close( nFile );
+ unlink( aFileName.getStr() );
+ return sal_False;
+ }
+ }
+ else
+ chmod( aFileName.getStr(), mnFileMode );
+ }
+ if (pDestFILE == NULL)
+ pDestFILE = fopen (aFileName.getStr(), "w");
+
+ if (pDestFILE == NULL)
+ return sal_False;
+ }
+ else
+ {
+ PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get ();
+ pDestFILE = rPrinterInfoManager.startSpool( m_aLastJobData.m_aPrinterName, m_bQuickJob );
+ if (pDestFILE == NULL)
+ return sal_False;
+ }
+
+ /* spool the document parts to the destination */
+
+ sal_uChar pBuffer[ nBLOCKSIZE ];
+
+ AppendPS (pDestFILE, mpJobHeader, pBuffer);
+ mpJobHeader->close();
+
+ sal_Bool bSuccess = sal_True;
+ std::list< osl::File* >::iterator pPageBody;
+ std::list< osl::File* >::iterator pPageHead;
+ for (pPageBody = maPageList.begin(), pPageHead = maHeaderList.begin();
+ pPageBody != maPageList.end() && pPageHead != maHeaderList.end();
+ ++pPageBody, ++pPageHead)
+ {
+ if( *pPageHead )
+ {
+ osl::File::RC nError = (*pPageHead)->open(osl_File_OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ AppendPS (pDestFILE, *pPageHead, pBuffer);
+ (*pPageHead)->close();
+ }
+ }
+ else
+ bSuccess = sal_False;
+ if( *pPageBody )
+ {
+ osl::File::RC nError = (*pPageBody)->open(osl_File_OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ AppendPS (pDestFILE, *pPageBody, pBuffer);
+ (*pPageBody)->close();
+ }
+ }
+ else
+ bSuccess = sal_False;
+ }
+
+ AppendPS (pDestFILE, mpJobTrailer, pBuffer);
+ mpJobTrailer->close();
+
+ /* well done */
+
+ if (bSpoolToFile)
+ fclose (pDestFILE);
+ else
+ {
+ PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get();
+ if (0 == rPrinterInfoManager.endSpool( m_aLastJobData.m_aPrinterName,
+ maJobTitle, pDestFILE, m_aDocumentJobData, true ))
+ {
+ bSuccess = sal_False;
+ }
+ }
+
+ return bSuccess;
+}
+
+sal_Bool
+PrinterJob::AbortJob ()
+{
+ m_pGraphics->OnEndJob();
+ return sal_False;
+}
+
+void
+PrinterJob::InitPaperSize (const JobData& rJobSetup)
+{
+ int nRes = rJobSetup.m_aContext.getRenderResolution ();
+
+ String aPaper;
+ int nWidth, nHeight;
+ rJobSetup.m_aContext.getPageSize (aPaper, nWidth, nHeight);
+
+ int nLeft = 0, nRight = 0, nUpper = 0, nLower = 0;
+ const PPDParser* pParser = rJobSetup.m_aContext.getParser();
+ if (pParser != NULL)
+ pParser->getMargins (aPaper, nLeft, nRight, nUpper, nLower);
+
+ mnResolution = nRes;
+
+ mnWidthPt = nWidth;
+ mnHeightPt = nHeight;
+
+ if( mnWidthPt > mnMaxWidthPt )
+ mnMaxWidthPt = mnWidthPt;
+ if( mnHeightPt > mnMaxHeightPt )
+ mnMaxHeightPt = mnHeightPt;
+
+ mnLMarginPt = nLeft;
+ mnRMarginPt = nRight;
+ mnTMarginPt = nUpper;
+ mnBMarginPt = nLower;
+
+ mfXScale = (double)72.0 / (double)mnResolution;
+ mfYScale = -1.0 * (double)72.0 / (double)mnResolution;
+}
+
+
+sal_Bool
+PrinterJob::StartPage (const JobData& rJobSetup)
+{
+ InitPaperSize (rJobSetup);
+
+ rtl::OUString aPageNo = rtl::OUString::valueOf ((sal_Int32)maPageList.size()+1); // sequential page number must start with 1
+ rtl::OUString aExt = aPageNo + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (".ps"));
+
+ osl::File* pPageHeader = CreateSpoolFile (
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("psp_pghead")), aExt);
+ osl::File* pPageBody = CreateSpoolFile (
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("psp_pgbody")), aExt);
+
+ maHeaderList.push_back (pPageHeader);
+ maPageList.push_back (pPageBody);
+
+ if( ! (pPageHeader && pPageBody) )
+ return sal_False;
+
+ // write page header according to Document Structuring Conventions (DSC)
+ WritePS (pPageHeader, "%%Page: ");
+ WritePS (pPageHeader, aPageNo);
+ WritePS (pPageHeader, " ");
+ WritePS (pPageHeader, aPageNo);
+ WritePS (pPageHeader, "\n");
+
+ if( rJobSetup.m_eOrientation == orientation::Landscape )
+ {
+ WritePS (pPageHeader, "%%PageOrientation: Landscape\n");
+ mnLandscapes++;
+ }
+ else
+ {
+ WritePS (pPageHeader, "%%PageOrientation: Portrait\n");
+ mnPortraits++;
+ }
+
+ sal_Char pBBox [256];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("%%PageBoundingBox: ", pBBox);
+ nChar += psp::getValueOf (mnLMarginPt, pBBox + nChar);
+ nChar += psp::appendStr (" ", pBBox + nChar);
+ nChar += psp::getValueOf (mnBMarginPt, pBBox + nChar);
+ nChar += psp::appendStr (" ", pBBox + nChar);
+ nChar += psp::getValueOf (mnWidthPt - mnRMarginPt, pBBox + nChar);
+ nChar += psp::appendStr (" ", pBBox + nChar);
+ nChar += psp::getValueOf (mnHeightPt - mnTMarginPt, pBBox + nChar);
+ nChar += psp::appendStr ("\n", pBBox + nChar);
+
+ WritePS (pPageHeader, pBBox);
+
+ /* #i7262# #i65491# write setup only before first page
+ * (to %%Begin(End)Setup, instead of %%Begin(End)PageSetup)
+ * don't do this in StartJob since the jobsetup there may be
+ * different.
+ */
+ bool bWriteFeatures = true;
+ if( 1 == maPageList.size() )
+ {
+ m_aDocumentJobData = rJobSetup;
+ bWriteFeatures = false;
+ }
+
+ if ( writePageSetup( pPageHeader, rJobSetup, bWriteFeatures ) )
+ {
+ m_aLastJobData = rJobSetup;
+ return true;
+ }
+
+ return false;
+}
+
+sal_Bool
+PrinterJob::EndPage ()
+{
+ m_pGraphics->OnEndPage();
+
+ osl::File* pPageHeader = maHeaderList.back();
+ osl::File* pPageBody = maPageList.back();
+
+ if( ! (pPageBody && pPageHeader) )
+ return sal_False;
+
+ // copy page to paper and write page trailer according to DSC
+
+ sal_Char pTrailer[256];
+ sal_Int32 nChar = 0;
+ nChar = psp::appendStr ("grestore grestore\n", pTrailer);
+ nChar += psp::appendStr ("showpage\n", pTrailer + nChar);
+ nChar += psp::appendStr ("%%PageTrailer\n\n", pTrailer + nChar);
+ WritePS (pPageBody, pTrailer);
+
+ // this page is done for now, close it to avoid having too many open fd's
+
+ pPageHeader->close();
+ pPageBody->close();
+
+ return sal_True;
+}
+
+sal_uInt32
+PrinterJob::GetErrorCode ()
+{
+ /* TODO */
+ return 0;
+}
+
+struct less_ppd_key : public ::std::binary_function<double, double, bool>
+{
+ bool operator()(const PPDKey* left, const PPDKey* right)
+ { return left->getOrderDependency() < right->getOrderDependency(); }
+};
+
+static bool writeFeature( osl::File* pFile, const PPDKey* pKey, const PPDValue* pValue, bool bUseIncluseFeature )
+{
+ if( ! pKey || ! pValue )
+ return true;
+
+ OStringBuffer aFeature(256);
+ aFeature.append( "[{\n" );
+ if( bUseIncluseFeature )
+ aFeature.append( "%%IncludeFeature:" );
+ else
+ aFeature.append( "%%BeginFeature:" );
+ aFeature.append( " *" );
+ aFeature.append( OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US ) );
+ aFeature.append( ' ' );
+ aFeature.append( OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US ) );
+ if( !bUseIncluseFeature )
+ {
+ aFeature.append( '\n' );
+ aFeature.append( OUStringToOString( pValue->m_aValue, RTL_TEXTENCODING_ASCII_US ) );
+ aFeature.append( "\n%%EndFeature" );
+ }
+ aFeature.append( "\n} stopped cleartomark\n" );
+ sal_uInt64 nWritten = 0;
+ return pFile->write( aFeature.getStr(), aFeature.getLength(), nWritten )
+ || nWritten != (sal_uInt64)aFeature.getLength() ? false : true;
+}
+
+bool PrinterJob::writeFeatureList( osl::File* pFile, const JobData& rJob, bool bDocumentSetup )
+{
+ bool bSuccess = true;
+
+ // emit features ordered to OrderDependency
+ // ignore features that are set to default
+
+ // sanity check
+ if( rJob.m_pParser == rJob.m_aContext.getParser() &&
+ rJob.m_pParser &&
+ ( m_aLastJobData.m_pParser == rJob.m_pParser || m_aLastJobData.m_pParser == NULL )
+ )
+ {
+ int i;
+ int nKeys = rJob.m_aContext.countValuesModified();
+ ::std::vector< const PPDKey* > aKeys( nKeys );
+ for( i = 0; i < nKeys; i++ )
+ aKeys[i] = rJob.m_aContext.getModifiedKey( i );
+ ::std::sort( aKeys.begin(), aKeys.end(), less_ppd_key() );
+
+ for( i = 0; i < nKeys && bSuccess; i++ )
+ {
+ const PPDKey* pKey = aKeys[i];
+ bool bEmit = false;
+ if( bDocumentSetup )
+ {
+ if( pKey->getSetupType() == PPDKey::DocumentSetup )
+ bEmit = true;
+ }
+ if( pKey->getSetupType() == PPDKey::PageSetup ||
+ pKey->getSetupType() == PPDKey::AnySetup )
+ bEmit = true;
+ if( bEmit )
+ {
+ const PPDValue* pValue = rJob.m_aContext.getValue( pKey );
+ if( pValue
+ && pValue->m_eType == eInvocation
+ && ( m_aLastJobData.m_pParser == NULL
+ || m_aLastJobData.m_aContext.getValue( pKey ) != pValue
+ || bDocumentSetup
+ )
+ )
+ {
+ // try to avoid PS level 2 feature commands if level is set to 1
+ if( GetPostscriptLevel( &rJob ) == 1 )
+ {
+ bool bHavePS2 =
+ ( pValue->m_aValue.SearchAscii( "<<" ) != STRING_NOTFOUND )
+ ||
+ ( pValue->m_aValue.SearchAscii( ">>" ) != STRING_NOTFOUND );
+ if( bHavePS2 )
+ continue;
+ }
+ bSuccess = writeFeature( pFile, pKey, pValue, PrinterInfoManager::get().getUseIncludeFeature() );
+ }
+ }
+ }
+ }
+ else
+ bSuccess = false;
+
+ return bSuccess;
+}
+
+bool PrinterJob::writePageSetup( osl::File* pFile, const JobData& rJob, bool bWriteFeatures )
+{
+ bool bSuccess = true;
+
+ WritePS (pFile, "%%BeginPageSetup\n%\n");
+ if ( bWriteFeatures )
+ bSuccess = writeFeatureList( pFile, rJob, false );
+ WritePS (pFile, "%%EndPageSetup\n");
+
+ sal_Char pTranslate [128];
+ sal_Int32 nChar = 0;
+
+ if( rJob.m_eOrientation == orientation::Portrait )
+ {
+ nChar = psp::appendStr ("gsave\n[", pTranslate);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mfXScale, 5);
+ nChar += psp::appendStr (" 0 0 ", pTranslate + nChar);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mfYScale, 5);
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOf (mnRMarginPt, pTranslate + nChar);
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOf (mnHeightPt-mnTMarginPt,
+ pTranslate + nChar);
+ nChar += psp::appendStr ("] concat\ngsave\n",
+ pTranslate + nChar);
+ }
+ else
+ {
+ nChar = psp::appendStr ("gsave\n", pTranslate);
+ nChar += psp::appendStr ("[ 0 ", pTranslate + nChar);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, -mfYScale, 5);
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mfXScale, 5);
+ nChar += psp::appendStr (" 0 ", pTranslate + nChar );
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mnLMarginPt, 5 );
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOf (mnBMarginPt, pTranslate + nChar );
+ nChar += psp::appendStr ("] concat\ngsave\n",
+ pTranslate + nChar);
+ }
+
+ WritePS (pFile, pTranslate);
+
+ return bSuccess;
+}
+
+void PrinterJob::writeJobPatch( osl::File* pFile, const JobData& rJobData )
+{
+ if( ! PrinterInfoManager::get().getUseJobPatch() )
+ return;
+
+ const PPDKey* pKey = NULL;
+
+ if( rJobData.m_pParser )
+ pKey = rJobData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "JobPatchFile" ) ) );
+ if( ! pKey )
+ return;
+
+ // order the patch files
+ // according to PPD spec the JobPatchFile options must be int
+ // and should be emitted in order
+ std::list< sal_Int32 > patch_order;
+ int nValueCount = pKey->countValues();
+ for( int i = 0; i < nValueCount; i++ )
+ {
+ const PPDValue* pVal = pKey->getValue( i );
+ patch_order.push_back( pVal->m_aOption.ToInt32() );
+ if( patch_order.back() == 0 && ! pVal->m_aOption.EqualsAscii( "0" ) )
+ {
+ WritePS( pFile, "% Warning: left out JobPatchFile option \"" );
+ OString aOption = OUStringToOString( pVal->m_aOption, RTL_TEXTENCODING_ASCII_US );
+ WritePS( pFile, aOption.getStr() );
+ WritePS( pFile,
+ "\"\n% as it violates the PPD spec;\n"
+ "% JobPatchFile options need to be numbered for ordering.\n" );
+ }
+ }
+
+ patch_order.sort();
+ patch_order.unique();
+
+ while( patch_order.begin() != patch_order.end() )
+ {
+ // note: this discards patch files not adhering to the "int" scheme
+ // as there won't be a value for them
+ writeFeature( pFile, pKey, pKey->getValue( OUString::valueOf( patch_order.front() ) ), false );
+ patch_order.pop_front();
+ }
+}
+
+bool PrinterJob::writeProlog (osl::File* pFile, const JobData& rJobData )
+{
+ WritePS( pFile, "%%BeginProlog\n" );
+
+ // JobPatchFile feature needs to be emitted at begin of prolog
+ writeJobPatch( pFile, rJobData );
+
+ static const sal_Char pProlog[] = {
+ "%%BeginResource: procset PSPrint-Prolog 1.0 0\n"
+ "/ISO1252Encoding [\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle\n"
+ "/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash\n"
+ "/zero /one /two /three /four /five /six /seven\n"
+ "/eight /nine /colon /semicolon /less /equal /greater /question\n"
+ "/at /A /B /C /D /E /F /G\n"
+ "/H /I /J /K /L /M /N /O\n"
+ "/P /Q /R /S /T /U /V /W\n"
+ "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n"
+ "/grave /a /b /c /d /e /f /g\n"
+ "/h /i /j /k /l /m /n /o\n"
+ "/p /q /r /s /t /u /v /w\n"
+ "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n"
+ "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n"
+ "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n"
+ "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n"
+ "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n"
+ "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n"
+ "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n"
+ "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n"
+ "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n"
+ "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
+ "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n"
+ "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n"
+ "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n"
+ "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n"
+ "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
+ "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n"
+ "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n"
+ "\n"
+ "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n"
+ "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n"
+ "currentdict end exch pop definefont pop } def\n"
+ "\n"
+ "/pathdict dup 8 dict def load begin\n"
+ "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n"
+ "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n"
+ "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n"
+ "eq 3 1 roll exch } def\n"
+ "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n"
+ "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n"
+ "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n"
+ "for 256 div exch pop exch { neg } if } def\n"
+ "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n"
+ "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n"
+ "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n"
+ "\n"
+ "systemdict /languagelevel known not {\n"
+ "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n"
+ "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n"
+ "roll show moveto 0 rmoveto } for pop pop } def\n"
+ "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n"
+ "rlineto closepath } def\n"
+ "/rectfill { rectangle fill } def\n"
+ "/rectstroke { rectangle stroke } def } if\n"
+ "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n"
+ "setlinewidth false charpath stroke setlinewidth } def\n"
+ "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n"
+ "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n"
+ "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n"
+ "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n"
+ "\n"
+ "/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n"
+ "/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n"
+ "/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n"
+ "/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n"
+ "/psp_imagedict {\n"
+ "/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n"
+ "/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n"
+ "def 7 dict dup\n"
+ "/ImageType 1 put dup\n"
+ "/Width 7 -1 roll put dup\n"
+ "/Height 5 index put dup\n"
+ "/BitsPerComponent 4 index psp_bitspercomponent put dup\n"
+ "/Decode 5 -1 roll psp_decodearray put dup\n"
+ "/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n"
+ "/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n"
+ "} def\n"
+ "%%EndResource\n"
+ "%%EndProlog\n"
+ };
+ static const sal_Char pSO52CompatProlog[] = {
+ "%%BeginResource: procset PSPrint-Prolog 1.0 0\n"
+ "/ISO1252Encoding [\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright\n"
+ "/parenleft /parenright /asterisk /plus /comma /minus /period /slash\n"
+ "/zero /one /two /three /four /five /six /seven\n"
+ "/eight /nine /colon /semicolon /less /equal /greater /question\n"
+ "/at /A /B /C /D /E /F /G\n"
+ "/H /I /J /K /L /M /N /O\n"
+ "/P /Q /R /S /T /U /V /W\n"
+ "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n"
+ "/grave /a /b /c /d /e /f /g\n"
+ "/h /i /j /k /l /m /n /o\n"
+ "/p /q /r /s /t /u /v /w\n"
+ "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n"
+ "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n"
+ "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n"
+ "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n"
+ "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n"
+ "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n"
+ "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n"
+ "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n"
+ "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n"
+ "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
+ "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n"
+ "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n"
+ "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n"
+ "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n"
+ "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
+ "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n"
+ "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n"
+ "\n"
+ "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n"
+ "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n"
+ "currentdict end exch pop definefont pop } def\n"
+ "\n"
+ "/pathdict dup 8 dict def load begin\n"
+ "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n"
+ "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n"
+ "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n"
+ "eq 3 1 roll exch } def\n"
+ "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n"
+ "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n"
+ "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n"
+ "for 256 div exch pop exch { neg } if } def\n"
+ "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n"
+ "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n"
+ "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n"
+ "\n"
+ "systemdict /languagelevel known not {\n"
+ "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n"
+ "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n"
+ "roll show moveto 0 rmoveto } for pop pop } def\n"
+ "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n"
+ "rlineto closepath } def\n"
+ "/rectfill { rectangle fill } def\n"
+ "/rectstroke { rectangle stroke } def } if\n"
+ "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n"
+ "setlinewidth false charpath stroke setlinewidth } def\n"
+ "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n"
+ "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n"
+ "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n"
+ "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n"
+ "\n"
+ "/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n"
+ "/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n"
+ "/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n"
+ "/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n"
+ "/psp_imagedict {\n"
+ "/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n"
+ "/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n"
+ "def 7 dict dup\n"
+ "/ImageType 1 put dup\n"
+ "/Width 7 -1 roll put dup\n"
+ "/Height 5 index put dup\n"
+ "/BitsPerComponent 4 index psp_bitspercomponent put dup\n"
+ "/Decode 5 -1 roll psp_decodearray put dup\n"
+ "/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n"
+ "/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n"
+ "} def\n"
+ "%%EndResource\n"
+ "%%EndProlog\n"
+ };
+ WritePS (pFile, m_pGraphics && m_pGraphics->getStrictSO52Compatibility() ? pSO52CompatProlog : pProlog);
+
+ return true;
+}
+
+bool PrinterJob::writeSetup( osl::File* pFile, const JobData& rJob )
+{
+ WritePS (pFile, "%%BeginSetup\n%\n");
+
+ // download fonts
+ std::list< rtl::OString > aFonts[2];
+ m_pGraphics->writeResources( pFile, aFonts[0], aFonts[1] );
+
+ for( int i = 0; i < 2; i++ )
+ {
+ if( !aFonts[i].empty() )
+ {
+ std::list< rtl::OString >::const_iterator it = aFonts[i].begin();
+ rtl::OStringBuffer aLine( 256 );
+ if( i == 0 )
+ aLine.append( "%%DocumentSuppliedResources: font " );
+ else
+ aLine.append( "%%DocumentNeededResources: font " );
+ aLine.append( *it );
+ aLine.append( "\n" );
+ WritePS ( pFile, aLine.getStr() );
+ while( (++it) != aFonts[i].end() )
+ {
+ aLine.setLength(0);
+ aLine.append( "%%+ font " );
+ aLine.append( *it );
+ aLine.append( "\n" );
+ WritePS ( pFile, aLine.getStr() );
+ }
+ }
+ }
+
+ bool bSuccess = true;
+ // in case of external print dialog the number of copies is prepended
+ // to the job, let us not complicate things by emitting our own copy count
+ bool bExternalDialog = PrinterInfoManager::get().checkFeatureToken( GetPrinterName(), "external_dialog" );
+ if( ! bExternalDialog && rJob.m_nCopies > 1 )
+ {
+ // setup code
+ ByteString aLine( "/#copies " );
+ aLine += ByteString::CreateFromInt32( rJob.m_nCopies );
+ aLine += " def\n";
+ sal_uInt64 nWritten = 0;
+ bSuccess = pFile->write( aLine.GetBuffer(), aLine.Len(), nWritten )
+ || nWritten != aLine.Len() ? false : true;
+
+ if( bSuccess && GetPostscriptLevel( &rJob ) >= 2 )
+ WritePS (pFile, "<< /NumCopies null /Policies << /NumCopies 1 >> >> setpagedevice\n" );
+ }
+
+ bool bFeatureSuccess = writeFeatureList( pFile, rJob, true );
+
+ WritePS (pFile, "%%EndSetup\n");
+
+ return bSuccess && bFeatureSuccess;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/printergfx/psheader.ps b/vcl/unx/generic/printergfx/psheader.ps
new file mode 100644
index 000000000000..6a0e350d9ddc
--- /dev/null
+++ b/vcl/unx/generic/printergfx/psheader.ps
@@ -0,0 +1,368 @@
+%*************************************************************************
+%
+% 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.
+%
+%*************************************************************************
+
+%
+%
+% readpath
+%
+% The intention of readpath is to save disk space since the vcl clip region routines
+% produce a huge amount of lineto/moveto commands
+%
+% The principal idea is to maintain the current point on stack and to provide only deltas
+% in the command. These deltas are added to the current point. The new point is used for
+% the lineto and moveto command and saved on stack for the next command.
+%
+% pathdict implements binary/hex representation of lineto and moveto commands.
+% The command consists of a 1byte opcode to switch between lineto and moveto and the size
+% of the following delta-x and delta-y values. The opcode is read with /rcmd, the two
+% coordinates are read with /rhex. The whole command is executed with /xcmd
+%
+%
+
+/pathdict dup 8 dict def load
+begin
+
+ % the command is of the bit format cxxyy
+ % with c=0 meaning lineto
+ % c=1 meaning moveto
+ % xx is a 2bit value for the number of bytes for x position
+ % yy is the same for y, values are off by one: 00 means 1; 11 means 4 !
+ % the command has been added to 'A' to be always in the ascii character
+ % range. the command is followed by 2*xx + 2*yy hexchars.
+ % '~' denotes the special case of EOD
+ /rcmd {
+ {
+ currentfile 1 string readstring % s bool
+ pop % s
+ 0 get % s[0]
+ % --- check wether s[0] is CR, LF ...
+ dup 32 gt % s > ' ' ? then read on
+ { exit }
+ { pop }
+ ifelse
+ }
+ loop
+
+ dup 126 eq { pop exit } if % -- Exit loop if cmd is '~'
+ 65 sub % cmd=s[0]-'A'
+ % -- Separate yy bits
+ dup 16#3 and 1 add % cmd yy
+ % -- Separate xx bits
+ exch % yy cmd
+ dup 16#C and -2 bitshift
+ 16#3 and 1 add exch % yy xx cmd
+ % -- Separate command bit
+ 16#10 and 16#10 eq % yy xx bool
+ 3 1 roll exch % bool xx yy
+ } def
+
+ % length rhex -- reads a signed hex value of given length
+ % the left most bit of char 0 is considered as the sign (0 means '+', 1 means '-')
+ % the rest of the bits is considered to be the abs value. Please note that this
+ % does not match the C binary representation of integers
+ /rhex {
+ dup 1 sub exch % l-1 l
+ currentfile exch string readhexstring % l-1 substring[l] bool
+ pop
+ dup 0 get dup % l-1 s s[0] s[0]
+ % -- Extract the sign
+ 16#80 and 16#80 eq dup % l-1 s s[0] sign=- sign=-
+ % -- Mask out the sign bit and put value back
+ 3 1 roll % l-1 s sign=- s[0] sign=-
+ { 16#7f and } if % l-1 s sign=- +s[0]
+ 2 index 0 % l-1 s sign=- +s[0] s 0
+ 3 -1 roll put % l-1 s sign=- s 0 +s[0]
+ % -- Read loop: add to prev sum, mul with 256
+ 3 1 roll 0 % sign=- l-1 s Sum=0
+ 0 1 5 -1 roll % sign=- s Sum=0 0 1 l-1
+ { % sign=- s Sum idx
+ 2 index exch % sign=- s Sum s idx
+ get % sign=- s Sum s[idx]
+ add 256 mul % sign=- s Sum=(s[idx]+Sum)*256
+ }
+ for
+ % -- mul was once too often, weave in the sign
+ 256 div % sign=- s Sum/256
+ exch pop % sign=- Sum/256
+ exch { neg } if % (sign=- ? -Sum : Sum)
+ } def
+
+ % execute a single command, the former x and y position is already on stack
+ % only offsets are read from cmdstring
+ /xcmd { % x y
+ rcmd % x y bool wx wy
+ exch rhex % x y bool wy Dx
+ exch rhex % x y bool Dx Dy
+ exch 5 -1 roll % y bool Dy Dx x
+ add exch % y bool X Dy
+ 4 -1 roll add % bool X Y
+ 1 index 1 index % bool X Y X Y
+ 5 -1 roll % X Y X Y bool
+ { moveto }
+ { lineto }
+ ifelse % X Y
+ } def
+end
+
+/readpath
+{
+ 0 0 % push initial-x initial-y
+ pathdict begin
+ { xcmd } loop
+ end
+ pop pop % pop final-x final-y
+} def
+
+%
+%
+% if languagelevel is not in the systemdict then its level 1 interpreter:
+% provide compatibility routines
+%
+%
+
+systemdict /languagelevel known not
+{
+ % string numarray xxshow -
+ % does only work for single byte fonts
+ /xshow {
+ exch dup % a s s
+ length 0 1 % a s l(s) 1 1
+ 3 -1 roll 1 sub % a s 0 1 l(s)-1
+ { % a s idx
+ dup % a s idx idx
+ % -- extract the delta offset
+ 3 index exch get % a s idx a[idx]
+ % -- extract the character
+ exch % a s a[idx] idx
+ 2 index exch get % a s a[idx] s[idx]
+ % -- create a tmp string for show
+ 1 string dup 0 % a s a[idx] s[idx] s1 s1 0
+ 4 -1 roll % a s a[idx] s1 s1 0 s[idx]
+ put % a s a[idx] s1
+ % -- store the current point
+ currentpoint 3 -1 roll % a s a[idx] x y s1
+ % -- draw the character
+ show % a s a[idx] x y
+ % -- move to the offset
+ moveto 0 rmoveto % a s
+ }
+ for
+ pop pop % -
+ } def
+
+ % x y width height rectfill
+ % x y width height rectshow
+ % in contrast to the languagelevel 2 operator
+ % they use and change the currentpath
+ /rectangle {
+ 4 -2 roll % width height x y
+ moveto % width height
+ 1 index 0 rlineto % width height % rmoveto(width, 0)
+ 0 exch rlineto % width % rmoveto(0, height)
+ neg 0 rlineto % - % rmoveto(-width, 0)
+ closepath
+ } def
+
+ /rectfill { rectangle fill } def
+ /rectstroke { rectangle stroke } def
+}
+if
+
+% -- small test program
+% 75 75 moveto /Times-Roman findfont 12 scalefont setfont
+% <292a2b2c2d2e2f30313233343536373839>
+% [5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 5] xshow <21>[0] xshow
+% showpage
+
+%
+%
+% shortcuts for image header with compression
+%
+%
+
+/psp_lzwfilter {
+ currentfile /ASCII85Decode filter /LZWDecode filter
+} def
+/psp_ascii85filter {
+ currentfile /ASCII85Decode filter
+} def
+/psp_lzwstring {
+ psp_lzwfilter 1024 string readstring
+} def
+/psp_ascii85string {
+ psp_ascii85filter 1024 string readstring
+} def
+/psp_imagedict {
+ /psp_bitspercomponent {
+ 3 eq
+ { 1 }
+ { 8 }
+ ifelse
+ } def
+ /psp_decodearray {
+ [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get
+ } def
+
+ 7 dict dup
+ /ImageType 1 put dup
+ /Width 7 -1 roll put dup
+ /Height 5 index put dup
+ /BitsPerComponent 4 index
+ psp_bitspercomponent put dup
+ /Decode 5 -1 roll
+ psp_decodearray put dup
+ /ImageMatrix [1 0 0 1 0 0] dup
+ 5 8 -1 roll put put dup
+ /DataSource 4 -1 roll
+ 1 eq
+ { psp_lzwfilter }
+ { psp_ascii85filter }
+ ifelse put
+} def
+
+
+%
+%
+% font encoding and reencoding
+%
+%
+
+/ISO1252Encoding [
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle
+ /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash
+ /zero /one /two /three /four /five /six /seven
+ /eight /nine /colon /semicolon /less /equal /greater /question
+ /at /A /B /C /D /E /F /G
+ /H /I /J /K /L /M /N /O
+ /P /Q /R /S /T /U /V /W
+ /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore
+ /grave /a /b /c /d /e /f /g
+ /h /i /j /k /l /m /n /o
+ /p /q /r /s /t /u /v /w
+ /x /y /z /braceleft /bar /braceright /asciitilde /unused
+ /Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl
+ /circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused
+ /unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash
+ /tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis
+ /space /exclamdown /cent /sterling /currency /yen /brokenbar /section
+ /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron
+ /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered
+ /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown
+ /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla
+ /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis
+ /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply
+ /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls
+ /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla
+ /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis
+ /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide
+ /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis
+] def
+
+% /fontname /encoding psp_findfont
+/psp_findfont {
+ exch dup % encoding fontname fontname
+ findfont % encoding fontname
+ dup length dict
+ begin
+ {
+ 1 index /FID ne
+ { def }
+ { pop pop }
+ ifelse
+ } forall
+ /Encoding 3 -1 roll def
+ currentdict
+ end
+ /psp_reencodedfont exch definefont
+} def
+
+% bshow shows a text in artificial bold
+% this is achieved by first showing the text
+% then stroking its outline over it with
+% the linewidth set to the second parameter
+% usage: (string) num bshow
+
+/bshow {
+ currentlinewidth % save current linewidth
+ 3 1 roll % move it to the last stack position
+ currentpoint % save the current point
+ 3 index % copy the string to show
+ show % show it
+ moveto % move to the original coordinates again
+ setlinewidth % set the linewidth
+ false charpath % create the outline path of the shown string
+ stroke % and stroke it
+ setlinewidth % reset the stored linewidth
+} def
+
+% bxshow shows a text with a delta array in artificial bold
+% that is it does what bshow does for show
+% usage: (string) [deltaarray] num bxshow
+
+/bxshow {
+ currentlinewidth % save linewidth
+ 4 1 roll % move it to the last stack position
+ setlinewidth % set the new linewidth
+ exch % exchange string and delta array
+ dup
+ length % get length of string
+ 1 sub % prepare parameters for {} for
+ 0 1
+ 3 -1 roll
+ {
+ 1 string % create a string object length 1
+ 2 index % get the text
+ 2 index % get charpos (for index variable)
+ get % have char value at charpos
+ 1 index % prepare string for put
+ exch
+ 0
+ exch
+ put % put into string of length 1
+ dup % duplicate the it
+ currentpoint % save current position
+ 3 -1 roll % prepare show
+ show % show the character
+ moveto % move back to beginning
+ currentpoint % save current position
+ 3 -1 roll % prepare outline path of character
+ false charpath
+ stroke % stroke it
+ moveto % move back
+ % now move to next point
+ 2 index % get advance array
+ exch % get charpos
+ get % get advance element
+ 0 rmoveto % advance current position
+ } for
+ pop pop % remove string and delta array
+ setlinewidth % restore linewidth
+} def
diff --git a/vcl/unx/generic/printergfx/psputil.cxx b/vcl/unx/generic/printergfx/psputil.cxx
new file mode 100644
index 000000000000..9a5de44960e6
--- /dev/null
+++ b/vcl/unx/generic/printergfx/psputil.cxx
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 "psputil.hxx"
+
+#include "tools/debug.hxx"
+
+namespace psp {
+
+/*
+ * string convenience routines
+ */
+
+sal_Int32
+getHexValueOf (sal_Int32 nValue, sal_Char* pBuffer)
+{
+ const static sal_Char pHex [0x10] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ pBuffer[0] = pHex [(nValue & 0xF0) >> 4];
+ pBuffer[1] = pHex [(nValue & 0x0F) ];
+
+ return 2;
+}
+
+sal_Int32
+getAlignedHexValueOf (sal_Int32 nValue, sal_Char* pBuffer)
+{
+ // get sign
+ sal_Bool bNegative = nValue < 0;
+ nValue = bNegative ? -nValue : nValue;
+
+ // get required buffer size, must be a multiple of two
+ sal_Int32 nPrecision;
+ if (nValue < 0x80)
+ nPrecision = 2;
+ else
+ if (nValue < 0x8000)
+ nPrecision = 4;
+ else
+ if (nValue < 0x800000)
+ nPrecision = 6;
+ else
+ nPrecision = 8;
+
+ // convert the int into its hex representation, write it into the buffer
+ sal_Int32 nRet = nPrecision;
+ while (nPrecision)
+ {
+ nPrecision -= getHexValueOf (nValue % 256, pBuffer + nPrecision - 2 );
+ nValue /= 256;
+ }
+
+ // set sign bit
+ if (bNegative)
+ {
+ switch (pBuffer[0])
+ {
+ case '0' : pBuffer[0] = '8'; break;
+ case '1' : pBuffer[0] = '9'; break;
+ case '2' : pBuffer[0] = 'A'; break;
+ case '3' : pBuffer[0] = 'B'; break;
+ case '4' : pBuffer[0] = 'C'; break;
+ case '5' : pBuffer[0] = 'D'; break;
+ case '6' : pBuffer[0] = 'E'; break;
+ case '7' : pBuffer[0] = 'F'; break;
+ default: OSL_FAIL("Already a signed value");
+ }
+ }
+
+ // report precision
+ return nRet;
+}
+
+
+sal_Int32
+getValueOf (sal_Int32 nValue, sal_Char* pBuffer)
+{
+ sal_Int32 nChar = 0;
+ if (nValue < 0)
+ {
+ pBuffer [nChar++] = '-';
+ nValue *= -1;
+ }
+ else
+ if (nValue == 0)
+ {
+ pBuffer [nChar++] = '0';
+ return nChar;
+ }
+
+ sal_Char pInvBuffer [32];
+ sal_Int32 nInvChar = 0;
+ while (nValue > 0)
+ {
+ pInvBuffer [nInvChar++] = '0' + nValue % 10;
+ nValue /= 10;
+ }
+ while (nInvChar > 0)
+ {
+ pBuffer [nChar++] = pInvBuffer [--nInvChar];
+ }
+
+ return nChar;
+}
+
+sal_Int32
+appendStr (const sal_Char* pSrc, sal_Char* pDst)
+{
+ sal_Int32 nBytes = strlen (pSrc);
+ strncpy (pDst, pSrc, nBytes + 1);
+
+ return nBytes;
+}
+
+sal_Int32
+appendStr (const sal_Char* pSrc, sal_Char* pDst, sal_Int32 nBytes)
+{
+ strncpy (pDst, pSrc, nBytes);
+ pDst [nBytes] = '\0';
+ return nBytes;
+}
+
+/*
+ * copy strings to file
+ */
+
+sal_Bool
+WritePS (osl::File* pFile, const sal_Char* pString)
+{
+ sal_uInt64 nInLength = rtl_str_getLength (pString);
+ sal_uInt64 nOutLength = 0;
+
+ if (nInLength > 0 && pFile)
+ pFile->write (pString, nInLength, nOutLength);
+
+ return nInLength == nOutLength;
+}
+
+sal_Bool
+WritePS (osl::File* pFile, const sal_Char* pString, sal_uInt64 nInLength)
+{
+ sal_uInt64 nOutLength = 0;
+
+ if (nInLength > 0 && pFile)
+ pFile->write (pString, nInLength, nOutLength);
+
+ return nInLength == nOutLength;
+}
+
+sal_Bool
+WritePS (osl::File* pFile, const rtl::OString &rString)
+{
+ sal_uInt64 nInLength = rString.getLength();
+ sal_uInt64 nOutLength = 0;
+
+ if (nInLength > 0 && pFile)
+ pFile->write (rString, nInLength, nOutLength);
+
+ return nInLength == nOutLength;
+}
+
+sal_Bool
+WritePS (osl::File* pFile, const rtl::OUString &rString)
+{
+ return WritePS (pFile, rtl::OUStringToOString(rString, RTL_TEXTENCODING_ASCII_US));
+}
+
+/*
+ * cache converter for use in postscript drawing routines
+ */
+
+ConverterFactory::ConverterFactory()
+{
+}
+
+ConverterFactory::~ConverterFactory ()
+{
+ for( std::map< rtl_TextEncoding, rtl_UnicodeToTextConverter >::const_iterator it = m_aConverters.begin(); it != m_aConverters.end(); ++it )
+ rtl_destroyUnicodeToTextConverter (it->second);
+}
+
+rtl_UnicodeToTextConverter
+ConverterFactory::Get (rtl_TextEncoding nEncoding)
+{
+ if (rtl_isOctetTextEncoding( nEncoding ))
+ {
+ std::map< rtl_TextEncoding, rtl_UnicodeToTextConverter >::const_iterator it =
+ m_aConverters.find( nEncoding );
+ rtl_UnicodeToTextConverter aConverter;
+ if (it == m_aConverters.end())
+ {
+ aConverter = rtl_createUnicodeToTextConverter (nEncoding);
+ m_aConverters[nEncoding] = aConverter;
+ }
+ else
+ aConverter = it->second;
+ return aConverter;
+ }
+ return NULL;
+}
+
+// wrapper for rtl_convertUnicodeToText that handles the usual cases for
+// textconversion in drawtext
+sal_Size
+ConverterFactory::Convert (const sal_Unicode *pText, int nTextLen,
+ sal_uChar *pBuffer, sal_Size nBufferSize, rtl_TextEncoding nEncoding)
+{
+ const sal_uInt32 nCvtFlags = RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK ;
+ sal_uInt32 nCvtInfo;
+ sal_Size nCvtChars;
+
+ rtl_UnicodeToTextConverter aConverter = Get (nEncoding);
+ rtl_UnicodeToTextContext aContext = rtl_createUnicodeToTextContext (aConverter);
+
+ sal_Size nSize = rtl_convertUnicodeToText (aConverter, aContext,
+ pText, nTextLen, (sal_Char*)pBuffer, nBufferSize,
+ nCvtFlags, &nCvtInfo, &nCvtChars);
+
+ rtl_destroyUnicodeToTextContext (aConverter, aContext);
+
+ return nSize;
+}
+
+ConverterFactory*
+GetConverterFactory ()
+{
+ static ConverterFactory* pCvt = NULL;
+
+ if (pCvt == NULL)
+ pCvt = new ConverterFactory;
+
+ return pCvt;
+}
+
+
+} /* namespace psp */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/printergfx/psputil.hxx b/vcl/unx/generic/printergfx/psputil.hxx
new file mode 100644
index 000000000000..878fd9c7791a
--- /dev/null
+++ b/vcl/unx/generic/printergfx/psputil.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _PSPRINT_PRINTERUTIL_HXX_
+#define _PSPRINT_PRINTERUTIL_HXX_
+
+#include "osl/file.hxx"
+
+#include "rtl/ustring.hxx"
+#include "rtl/string.hxx"
+#include "rtl/tencinfo.h"
+#include "rtl/textcvt.h"
+
+#include <map>
+
+namespace psp {
+
+/*
+ * string convenience routines
+ * sizeof(pBuffer) must be at least 2 Bytes, 0x00 <= nValue <= 0xFF,
+ * effective buffer of get*ValueOf() is NOT NULL-terminated
+ */
+sal_Int32 getHexValueOf (sal_Int32 nValue, sal_Char* pBuffer);
+sal_Int32 getAlignedHexValueOf (sal_Int32 nValue, sal_Char* pBuffer);
+sal_Int32 getValueOf (sal_Int32 nValue, sal_Char* pBuffer);
+sal_Int32 appendStr (const sal_Char* pSrc, sal_Char* pDst);
+sal_Int32 appendStr (const sal_Char* pSrc, sal_Char* pDst, sal_Int32 nBytes);
+
+sal_Bool WritePS (osl::File* pFile, const sal_Char* pString);
+sal_Bool WritePS (osl::File* pFile, const sal_Char* pString, sal_uInt64 nInLength);
+sal_Bool WritePS (osl::File* pFile, const rtl::OString &rString);
+sal_Bool WritePS (osl::File* pFile, const rtl::OUString &rString);
+
+class ConverterFactory
+{
+
+public:
+ ConverterFactory();
+ ~ConverterFactory();
+ rtl_UnicodeToTextConverter Get (rtl_TextEncoding nEncoding);
+ sal_Size Convert (const sal_Unicode *pText, int nTextLen,
+ sal_uChar *pBuffer, sal_Size nBufferSize,
+ rtl_TextEncoding nEncoding);
+private:
+
+ std::map< rtl_TextEncoding, rtl_UnicodeToTextConverter > m_aConverters;
+};
+
+ConverterFactory* GetConverterFactory ();
+
+} /* namespace psp */
+
+#endif /* _PSPRINT_PRINTERUTIL_HXX_ */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/printergfx/text_gfx.cxx b/vcl/unx/generic/printergfx/text_gfx.cxx
new file mode 100644
index 000000000000..263e0b4c7995
--- /dev/null
+++ b/vcl/unx/generic/printergfx/text_gfx.cxx
@@ -0,0 +1,865 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <math.h>
+
+#include "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "printergfx.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/helper.hxx"
+
+#include "osl/thread.h"
+
+#include "sal/alloca.h"
+
+using namespace psp ;
+
+namespace psp {
+/*
+ container for a font and its helper fonts:
+ 1st font is the font substitute e.g. helvetica substitutes arial on the printer
+ 2nd is the font itself
+ 3rd is a fallback font, usually a font with unicode glyph repertoir (e.g. andale)
+ symbol fonts (adobe-fontspecific) may need special glyphmapping
+ (symbol page vc. latin page)
+*/
+class Font3
+{
+ private:
+
+ #define Font3Size 3
+
+ fontID mpFont [Font3Size];
+ bool mbSymbol;
+
+ public:
+
+ fontID GetFont (int nIdx) const
+ { return nIdx < Font3Size ? mpFont[nIdx] : -1 ; }
+ bool IsSymbolFont () const
+ { return mbSymbol; }
+
+ Font3 (const PrinterGfx &rGfx);
+ ~Font3 () {}
+};
+
+Font3::Font3(const PrinterGfx &rGfx)
+{
+ mpFont[0] = rGfx.getFontSubstitute();
+ mpFont[1] = rGfx.GetFontID();
+ mpFont[2] = rGfx.getFallbackID();
+ // mpFont[2] = rGfx.GetFontID();
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ mbSymbol = mpFont[1] != -1 ?
+ rMgr.getFontEncoding(mpFont[1]) == RTL_TEXTENCODING_SYMBOL : false;
+}
+
+} // namespace psp
+
+static int getVerticalDeltaAngle( sal_Unicode nChar )
+{
+ int nAngle = 0;
+ if( ( nChar >= 0x1100 && nChar < 0x11fa ) ||
+ ( nChar >= 0x3000 && nChar < 0xfb00 ) ||
+ ( nChar >= 0xfe20 && nChar < 0xfe70 ) ||
+ ( nChar >= 0xff00 && nChar < 0xff64 )
+ )
+ {
+ /* #i52932# remember:
+ nChar == 0x2010 || nChar == 0x2015
+ nChar == 0x2016 || nChar == 0x2026
+
+ are nAngle = 0 also, but already handled in the first if
+ */
+ if( ( nChar >= 0x3008 && nChar < 0x3019 && nChar != 0x3012 ) ||
+ nChar == 0xff3b || nChar == 0xff3d ||
+ (nChar >= 0xff6b && nChar < 0xff64 ) ||
+ nChar == 0xffe3
+ )
+ nAngle = 0;
+ else if( nChar == 0x30fc )
+ nAngle = -900;
+ else
+ nAngle = 900;
+ }
+ return nAngle;
+}
+
+void
+PrinterGfx::PSUploadPS1Font (sal_Int32 nFontID)
+{
+ std::list< sal_Int32 >::iterator aFont;
+ // already in the document header ?
+ for (aFont = maPS1Font.begin(); aFont != maPS1Font.end(); ++aFont )
+ if( nFontID == *aFont )
+ return;
+
+ // no occurrenc yet, mark for download
+ // add the fontid to the list
+ maPS1Font.push_back (nFontID);
+}
+
+/*
+ * implement text handling printer routines,
+ */
+
+sal_uInt16
+PrinterGfx::SetFont(
+ sal_Int32 nFontID,
+ sal_Int32 nHeight,
+ sal_Int32 nWidth,
+ sal_Int32 nAngle,
+ bool bVertical,
+ bool bArtItalic,
+ bool bArtBold
+ )
+{
+ // font and encoding will be set by drawText again immediately
+ // before PSShowText
+ mnFontID = nFontID;
+ maVirtualStatus.maFont = rtl::OString();
+ maVirtualStatus.maEncoding = RTL_TEXTENCODING_DONTKNOW;
+ maVirtualStatus.mnTextHeight = nHeight;
+ maVirtualStatus.mnTextWidth = nWidth;
+ maVirtualStatus.mbArtItalic = bArtItalic;
+ maVirtualStatus.mbArtBold = bArtBold;
+ mnTextAngle = nAngle;
+ mbTextVertical = bVertical;
+
+ return 0;
+}
+
+sal_uInt16
+PrinterGfx::SetFallbackFont ( sal_Int32 nFontID )
+{
+ mnFallbackID = nFontID;
+ return 0;
+}
+
+void PrinterGfx::drawGlyphs(
+ const Point& rPoint,
+ sal_uInt32* pGlyphIds,
+ sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ sal_Int32* pDeltaArray
+ )
+{
+
+ // draw the string
+ // search for a glyph set matching the set font
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); ++aIter)
+ if ( ((*aIter).GetFontID() == mnFontID)
+ && ((*aIter).IsVertical() == mbTextVertical))
+ {
+ (*aIter).DrawGlyphs (*this, rPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray);
+ break;
+ }
+
+ // not found ? create a new one
+ if (aIter == maPS3Font.end())
+ {
+ maPS3Font.push_back (GlyphSet(mnFontID, mbTextVertical));
+ maPS3Font.back().DrawGlyphs (*this, rPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray);
+ }
+}
+
+void PrinterGfx::DrawGlyphs(
+ const Point& rPoint,
+ sal_GlyphId* pGlyphIds,
+ sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ sal_Int32* pDeltaArray
+ )
+{
+ if( nLen <= 0 )
+ return;
+
+ if ( !mrFontMgr.isFontDownloadingAllowed( mnFontID ) )
+ {
+ LicenseWarning(rPoint, pUnicodes, nLen, pDeltaArray);
+ return;
+ }
+
+ if( mrFontMgr.getFontType( mnFontID ) != fonttype::TrueType )
+ {
+ DrawText( rPoint, pUnicodes, nLen, pDeltaArray );
+ return;
+ }
+
+ // move and rotate the user coordinate system
+ // avoid the gsave/grestore for the simple cases since it allows
+ // reuse of the current font if it hasn't changed
+ sal_Int32 nCurrentTextAngle = mnTextAngle;
+ Point aPoint( rPoint );
+
+ if (nCurrentTextAngle != 0)
+ {
+ PSGSave ();
+ PSTranslate (rPoint);
+ PSRotate (nCurrentTextAngle);
+ mnTextAngle = 0;
+ aPoint = Point( 0, 0 );
+ }
+
+ if( mbTextVertical )
+ {
+ // vertical glyphs can have an additional rotation ... sigh.
+ // so break up text in chunks of normal glyphs and print out
+ // specially rotated glyphs extra
+ sal_uInt32* pTempGlyphIds = (sal_uInt32*)alloca(sizeof(sal_Int32)*nLen);
+ sal_Int32* pTempDelta = (sal_Int32*)alloca(sizeof(sal_Int32)*nLen);
+ sal_Unicode* pTempUnicodes = (sal_Unicode*)alloca(sizeof(sal_Unicode)*nLen);
+ sal_Int16 nTempLen = 0;
+ sal_Int32 nTempFirstDelta = 0;
+ Point aRotPoint;
+ sal_Int32 nTextHeight = maVirtualStatus.mnTextHeight;
+ sal_Int32 nTextWidth = maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ sal_Int32 nAscend = mrFontMgr.getFontAscend( mnFontID );
+ sal_Int32 nDescend = mrFontMgr.getFontDescend( mnFontID );
+
+ nDescend = nDescend * nTextHeight / 1000;
+ nAscend = nAscend * nTextHeight / 1000;
+
+ for( sal_Int16 i = 0; i < nLen; i++ )
+ {
+ const sal_GlyphId nRot = pGlyphIds[i] & GF_ROTMASK;
+ if( nRot == GF_NONE )
+ {
+ pTempUnicodes[nTempLen] = pUnicodes[i];
+ pTempGlyphIds[nTempLen] = pGlyphIds[i];
+ if( nTempLen > 0 )
+ pTempDelta[nTempLen-1] = pDeltaArray[i-1]-nTempFirstDelta;
+ else
+ {
+ // the first element in pDeltaArray shows
+ // the offset of the second character
+ // so if the first glyph is normal
+ // then we do not need to move the delta indices
+ // else we have to move them down by one and
+ // recalculate aPoint and all deltas
+ if( i != 0 )
+ nTempFirstDelta = pDeltaArray[ i-1 ];
+ }
+ nTempLen++;
+ }
+ else
+ {
+ sal_Int32 nOffset = i > 0 ? pDeltaArray[i-1] : 0;
+ sal_Int32 nRotAngle = 0;
+ switch( nRot )
+ {
+ case GF_ROTR:
+ nRotAngle = 2700;
+ aRotPoint = Point( -nAscend*nTextWidth/nTextHeight, -nDescend*nTextWidth/nTextHeight - nOffset );
+ break;
+ case GF_VERT:
+ nRotAngle = 1800;
+ aRotPoint = Point( -nOffset, (nAscend+nDescend) );
+ break;
+ case GF_ROTL:
+ nRotAngle = 900;
+ aRotPoint = Point( -nDescend*nTextWidth/nTextHeight, nOffset + nAscend*nTextWidth/nTextHeight );
+ break;
+ }
+ sal_GlyphId nRotGlyphId = pGlyphIds[i];
+ sal_Unicode nRotUnicode = pUnicodes[i];
+ sal_Int32 nRotDelta = 0;
+
+ // transform matrix to new individual direction
+ PSGSave ();
+ GraphicsStatus aSaveStatus = maVirtualStatus;
+ if( nRot != 2 ) // switch font aspect
+ {
+ maVirtualStatus.mnTextWidth = nTextHeight;
+ maVirtualStatus.mnTextHeight = nTextWidth;
+ }
+ if( aPoint.X() || aPoint.Y() )
+ PSTranslate( aPoint );
+ PSRotate (nRotAngle);
+ // draw the rotated glyph
+ drawGlyphs( aRotPoint, &nRotGlyphId, &nRotUnicode, 1, &nRotDelta );
+
+ // restore previous state
+ maVirtualStatus = aSaveStatus;
+ PSGRestore();
+ }
+ }
+
+ pGlyphIds = pTempGlyphIds;
+ pUnicodes = pTempUnicodes;
+ pDeltaArray = pTempDelta;
+ nLen = nTempLen;
+
+ aPoint.X() += nTempFirstDelta;
+ }
+
+ if( nLen > 0 )
+ drawGlyphs( aPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray );
+
+ // restore the user coordinate system
+ if (nCurrentTextAngle != 0)
+ {
+ PSGRestore ();
+ mnTextAngle = nCurrentTextAngle;
+ }
+}
+
+void
+PrinterGfx::DrawText (
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ fontID nRestoreFont = mnFontID;
+
+ // setup font[substitutes] and map the string into the symbol area in case of
+ // symbol font
+ Font3 aFont(*this);
+ sal_Unicode *pEffectiveStr;
+ if ( aFont.IsSymbolFont() )
+ {
+ pEffectiveStr = (sal_Unicode*)alloca(nLen * sizeof(pStr[0]));
+ for (int i = 0; i < nLen; i++)
+ pEffectiveStr[i] = pStr[i] < 256 ? pStr[i] + 0xF000 : pStr[i];
+ }
+ else
+ {
+ pEffectiveStr = const_cast<sal_Unicode*>(pStr);
+ }
+
+ fontID *pFontMap = (fontID*) alloca(nLen * sizeof(fontID));
+ sal_Int32 *pCharWidth = (sal_Int32*) alloca(nLen * sizeof(sal_Int32));
+
+ for( int n = 0; n < nLen; n++ )
+ {
+ CharacterMetric aBBox;
+ pFontMap[n] = getCharMetric (aFont, pEffectiveStr[n], &aBBox);
+ pCharWidth[n] = getCharWidth (mbTextVertical, pEffectiveStr[n], &aBBox);
+ }
+
+ // setup a new delta array, use virtual resolution of 1000
+ sal_Int32* pNewDeltaArray = (sal_Int32*)alloca( sizeof( sal_Int32 )*nLen );
+ if ( pDeltaArray != 0)
+ {
+ for (int i = 0; i < nLen - 1; i++)
+ pNewDeltaArray[i] = 1000 * pDeltaArray[i];
+ pNewDeltaArray[nLen - 1] = 0;
+ }
+ else
+ {
+ pNewDeltaArray[0] = pCharWidth[0];
+ for (int i = 1; i < nLen; i++)
+ pNewDeltaArray[i] = pNewDeltaArray[i-1] + pCharWidth[i];
+ }
+
+ // move and rotate the user coordinate system
+ // avoid the gsave/grestore for the simple cases since it allows
+ // reuse of the current font if it hasn't changed
+ sal_Int32 nCurrentTextAngle = mnTextAngle;
+ sal_Int32 nCurrentPointX;
+ sal_Int32 nCurrentPointY;
+
+ if (nCurrentTextAngle != 0)
+ {
+ PSGSave ();
+ PSTranslate (rPoint);
+ PSRotate (nCurrentTextAngle);
+ mnTextAngle = 0;
+
+ nCurrentPointX = 0;
+ nCurrentPointY = 0;
+ }
+ else
+ {
+ nCurrentPointX = rPoint.X();
+ nCurrentPointY = rPoint.Y();
+ }
+
+ // draw the string
+ sal_Int32 nDelta = 0;
+ for (int nTo = 0; nTo < nLen; )
+ {
+ int nFrom = nTo;
+ fontID nFont = pFontMap[ nFrom ];
+
+ while ((nTo < nLen) && (nFont == pFontMap[nTo]))
+ {
+ pNewDeltaArray[ nTo ] = (sal_Int32)(((0.5 + pNewDeltaArray[ nTo ]) / 1000.0) - nDelta);
+ nTo++ ;
+ }
+
+ SetFont( nFont,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ mnTextAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold
+ );
+
+ if (mbTextVertical)
+ {
+ drawVerticalizedText(
+ Point(nCurrentPointX + nDelta, nCurrentPointY),
+ pEffectiveStr + nFrom, nTo - nFrom,
+ pNewDeltaArray + nFrom );
+ }
+ else
+ {
+ drawText(
+ Point(nCurrentPointX + nDelta, nCurrentPointY),
+ pEffectiveStr + nFrom, nTo - nFrom,
+ pDeltaArray == NULL ? NULL : pNewDeltaArray + nFrom );
+ }
+ nDelta += pNewDeltaArray[ nTo - 1 ];
+ }
+
+ // restore the user coordinate system
+ if (nCurrentTextAngle != 0)
+ {
+ PSGRestore ();
+ mnTextAngle = nCurrentTextAngle;
+ }
+
+ // restore the original font settings
+ SetFont( nRestoreFont,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ mnTextAngle, mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold
+ );
+}
+
+void PrinterGfx::drawVerticalizedText(
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ sal_Int32* pDelta = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) );
+
+ int nTextScale = maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ int nNormalAngle = mnTextAngle;
+ int nDeltaAngle, nLastPos = 0;
+
+ double fSin = sin( -2.0*M_PI*nNormalAngle/3600 );
+ double fCos = cos( -2.0*M_PI*nNormalAngle/3600 );
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ PrintFontInfo aInfo;
+ rMgr.getFontInfo( mnFontID, aInfo );
+
+ bool* pGsubFlags = (bool*)alloca( nLen * sizeof(bool) );
+ rMgr.hasVerticalSubstitutions( mnFontID, pStr, nLen, pGsubFlags );
+
+ Point aPoint( rPoint );
+ for( int i = 0; i < nLen; )
+ {
+ while( ( nDeltaAngle = getVerticalDeltaAngle( pStr[i] ) ) == 0 && i < nLen )
+ i++;
+ if( i <= nLen && i > nLastPos )
+ {
+ for( int n = nLastPos; n < i; n++ )
+ pDelta[n] = pDeltaArray[n] - (aPoint.X() - rPoint.X() );
+
+ SetFont( mnFontID,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ nNormalAngle, mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+ drawText( aPoint, pStr + nLastPos, i - nLastPos, pDelta + nLastPos );
+
+ aPoint.X() = (sal_Int32)(rPoint.X() + ((double)pDeltaArray[i-1] * fCos));
+ aPoint.Y() = (sal_Int32)(rPoint.Y() + ((double)pDeltaArray[i-1] * fSin));
+ }
+ if( i < nLen )
+ {
+ int nOldWidth = maVirtualStatus.mnTextWidth;
+ int nOldHeight = maVirtualStatus.mnTextHeight;
+ SetFont( mnFontID,
+ nTextScale,
+ maVirtualStatus.mnTextHeight,
+ nNormalAngle + nDeltaAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+
+ double nA = nTextScale * aInfo.m_nAscend / 1000.0;
+ double nD = nTextScale * aInfo.m_nDescend / 1000.0;
+ double fStretch = (double)maVirtualStatus.mnTextWidth / maVirtualStatus.mnTextHeight;
+ if( !pGsubFlags[i] )
+ nD *= fStretch;
+
+ Point aPos( aPoint );
+ switch( nDeltaAngle )
+ {
+ case +900:
+ aPos.X() += (sal_Int32)(+nA * fCos + nD * fSin);
+ aPos.Y() += (sal_Int32)(-nA * fSin + nD * fCos);
+ break;
+ case -900:
+ aPos.X() += (sal_Int32)(+nA * fSin + nD * fCos);
+ aPos.Y() += (sal_Int32)(-(nTextScale*fStretch - nD) * fCos);
+ break;
+ }
+ drawText( aPos, pStr+i, 1, NULL );
+ if( i < nLen-1 && pDeltaArray )
+ {
+ aPoint.X() = (sal_Int32)(rPoint.X() + ((double)pDeltaArray[i] * fCos));
+ aPoint.Y() = (sal_Int32)(rPoint.Y() + ((double)pDeltaArray[i] * fSin));
+ }
+
+ // swap text width/height again
+ SetFont( mnFontID,
+ nOldHeight,
+ nOldWidth,
+ nNormalAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+ }
+ i++;
+ nLastPos = i;
+ }
+ mnTextAngle = nNormalAngle;
+}
+
+void
+PrinterGfx::LicenseWarning(const Point& rPoint, const sal_Unicode* pStr,
+ sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ // treat it like a builtin font in case a user has that font also in the
+ // printer. This is not so unlikely as it may seem; no print embedding
+ // licensed fonts are often used (or so they say) in companies:
+ // they are installed on displays and printers, but get not embedded in
+ // they are installed on displays and printers, but get not embedded in
+ // print files or documents because they are not licensed for use outside
+ // the company.
+ rtl::OString aMessage( "The font " );
+ aMessage += rtl::OUStringToOString( mrFontMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US );
+ aMessage += " could not be downloaded\nbecause its license does not allow for that";
+ PSComment( aMessage.getStr() );
+
+ rtl::OString aFontName = rtl::OUStringToOString(
+ mrFontMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ PSSetFont (aFontName, RTL_TEXTENCODING_ISO_8859_1);
+
+ sal_Size nSize = 4 * nLen;
+ sal_uChar* pBuffer = (sal_uChar*)alloca (nSize* sizeof(sal_uChar));
+
+ ConverterFactory* pCvt = GetConverterFactory ();
+ nSize = pCvt->Convert (pStr, nLen, pBuffer, nSize, RTL_TEXTENCODING_ISO_8859_1);
+
+ PSMoveTo (rPoint);
+ PSShowText (pBuffer, nLen, nSize, pDeltaArray);
+}
+
+void
+PrinterGfx::drawText(
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ if (!(nLen > 0))
+ return;
+
+ fonttype::type eType = mrFontMgr.getFontType (mnFontID);
+
+ if (eType == fonttype::Type1)
+ PSUploadPS1Font (mnFontID);
+
+ if ( eType == fonttype::TrueType
+ && !mrFontMgr.isFontDownloadingAllowed(mnFontID))
+ {
+ LicenseWarning(rPoint, pStr, nLen, pDeltaArray);
+ return;
+ }
+
+ if( mrFontMgr.getUseOnlyFontEncoding( mnFontID ) )
+ {
+ GlyphSet aGSet( mnFontID, mbTextVertical );
+ aGSet.DrawText( *this, rPoint, pStr, nLen, pDeltaArray );
+ return;
+ }
+
+ // search for a glyph set matching the set font
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); ++aIter)
+ if ( ((*aIter).GetFontID() == mnFontID)
+ && ((*aIter).IsVertical() == mbTextVertical))
+ {
+ (*aIter).DrawText (*this, rPoint, pStr, nLen, pDeltaArray);
+ break;
+ }
+
+ // not found ? create a new one
+ if (aIter == maPS3Font.end())
+ {
+ maPS3Font.push_back (GlyphSet(mnFontID, mbTextVertical));
+ maPS3Font.back().DrawText (*this, rPoint, pStr, nLen, pDeltaArray);
+ }
+}
+
+int
+PrinterGfx::getCharWidth (sal_Bool b_vert, sal_Unicode n_char, CharacterMetric *p_bbox)
+{
+ b_vert = b_vert && (getVerticalDeltaAngle(n_char) != 0);
+ int w = b_vert ? p_bbox->height : p_bbox->width;
+ w *= maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ return w;
+}
+
+fontID
+PrinterGfx::getCharMetric (const Font3 &rFont, sal_Unicode n_char, CharacterMetric *p_bbox)
+{
+ p_bbox->width = -1;
+ p_bbox->height = -1;
+
+ for (fontID n = 0; n < 3; n++)
+ {
+ fontID n_font = rFont.GetFont(n);
+ if (n_font != -1)
+ {
+ if( mbStrictSO52Compatibility )
+ {
+ fonttype::type eType = mrFontMgr.getFontType( n_font );
+ if( (eType == fonttype::Builtin || eType == fonttype::Type1) )
+ {
+ // note: any character exchanged here MUST also be changed
+ // in the compatibility ISO encoding vector in the prolog
+ // in printerjob.cxx
+ sal_Unicode aRepl = 0;
+ if( n_char == 0x2d )
+ aRepl = 0x2212;
+ else if( n_char == 0x27 )
+ aRepl = 0x2019;
+ /*
+ additional characters that may need backwards compatibility:
+ ISO5589 StdEnc Unicode suggested n_char -> aRepl
+ 0264 0302 0x00B4 0x00B4 (acute) -> 0x2019 (quiteright)
+ 0246 - 0x00A6 0x00A6 (brokenbar) -> 0x007C (bar)
+ 0225 0267 0x0095 0x0095 () -> 0x2022 (bullet)
+ 0140 0301 0x0060 0x0060 (grave) -> ?
+ */
+ if( aRepl )
+ {
+ mrFontMgr.getMetrics( n_font, aRepl, aRepl, p_bbox );
+ if (p_bbox->width >= 0 && p_bbox->height >= 0)
+ return n_font;
+ }
+ }
+ }
+ mrFontMgr.getMetrics( n_font, n_char, n_char, p_bbox );
+ }
+ if (p_bbox->width >= 0 && p_bbox->height >= 0)
+ return n_font;
+ }
+ if (n_char != '?')
+ return getCharMetric (rFont, '?', p_bbox);
+
+ return rFont.GetFont(0) != -1 ? rFont.GetFont(0) : rFont.GetFont(1);
+}
+
+fontID
+PrinterGfx::getFontSubstitute () const
+{
+ if( mpFontSubstitutes )
+ {
+ ::boost::unordered_map< fontID, fontID >::const_iterator it =
+ mpFontSubstitutes->find( mnFontID );
+ if( it != mpFontSubstitutes->end() )
+ return it->second;
+ }
+
+ return -1;
+}
+
+sal_Int32
+PrinterGfx::GetCharWidth (sal_Unicode nFrom, sal_Unicode nTo, long *pWidthArray)
+{
+ Font3 aFont(*this);
+ if (aFont.IsSymbolFont() && (nFrom < 256) && (nTo < 256))
+ {
+ nFrom += 0xF000;
+ nTo += 0xF000;
+ }
+
+ for( int n = 0; n < (nTo - nFrom + 1); n++ )
+ {
+ CharacterMetric aBBox;
+ getCharMetric (aFont, n + nFrom, &aBBox);
+ pWidthArray[n] = getCharWidth (mbTextVertical, n + nFrom, &aBBox);
+ }
+
+ // returned metrics have postscript precision
+ return 1000;
+}
+
+const ::std::list< KernPair >& PrinterGfx::getKernPairs( bool bVertical ) const
+{
+ /*
+ * Note: this is only a 80% solution: if a font is only
+ * partially substituted in a string due to missing glyphs
+ * the results may not be perfect; the more so the more the
+ * substitution differs from the original metricwise. But
+ * vcl only asks for KernPairs for each font once and NOT
+ * in a string context this is the best we can do.
+ * In future the kerning should be done on a per string basis.
+ */
+ fontID nFont = mnFontID;
+ if( mpFontSubstitutes )
+ {
+ ::boost::unordered_map< fontID, fontID >::const_iterator it =
+ mpFontSubstitutes->find( mnFontID );
+ if( it != mpFontSubstitutes->end() )
+ nFont = it->second;
+ }
+ return mrFontMgr.getKernPairs( nFont, bVertical );
+}
+
+/*
+ * advanced glyph handling
+ */
+
+sal_Bool
+PrinterGfx::GetGlyphBoundRect (sal_Unicode /*c*/, Rectangle& /*rOutRect*/)
+{
+ return 0;
+}
+
+sal_uInt32
+PrinterGfx::GetGlyphOutline (sal_Unicode /*c*/,
+ sal_uInt16 **/*ppPolySizes*/, Point **/*ppPoints*/, sal_uInt8 **/*ppFlags*/)
+{
+ return 0;
+}
+
+/*
+ * spool the converted truetype fonts to the page header after the page body is
+ * complete
+ * for Type1 fonts spool additional reencoding vectors that are necessary to access the
+ * whole font
+ */
+
+void
+PrinterGfx::OnEndPage ()
+{
+}
+
+void
+PrinterGfx::OnEndJob ()
+{
+ maPS3Font.clear();
+ maPS1Font.clear();
+}
+
+void
+PrinterGfx::writeResources( osl::File* pFile, std::list< rtl::OString >& rSuppliedFonts, std::list< rtl::OString >& rNeededFonts )
+{
+ // write all type 1 fonts
+ std::list< sal_Int32 >::iterator aFont;
+ // already in the document header ?
+ for (aFont = maPS1Font.begin(); aFont != maPS1Font.end(); ++aFont)
+ {
+ const rtl::OString& rSysPath (mrFontMgr.getFontFileSysPath(*aFont) );
+ rtl::OUString aUNCPath;
+ osl::File::getFileURLFromSystemPath (OStringToOUString (rSysPath, osl_getThreadTextEncoding()), aUNCPath);
+ osl::File aFontFile (aUNCPath);
+
+ // provide the pfb or pfa font as a (pfa-)font resource
+ rtl::OString aPostScriptName =
+ rtl::OUStringToOString ( mrFontMgr.getPSName(*aFont),
+ RTL_TEXTENCODING_ASCII_US );
+
+ WritePS (pFile, "%%BeginResource: font ");
+ WritePS (pFile, aPostScriptName.getStr());
+ WritePS (pFile, "\n");
+
+ osl::File::RC nError = aFontFile.open(osl_File_OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ convertPfbToPfa (aFontFile, *pFile);
+ aFontFile.close ();
+
+ pFile->setPos(osl_Pos_Current, -1);
+ char lastchar = '\n';
+ sal_uInt64 uBytes(1);
+ pFile->read((void *)(&lastchar), uBytes, uBytes);
+ if (lastchar != '\n')
+ WritePS (pFile, "\n");
+ }
+ WritePS (pFile, "%%EndResource\n");
+ rSuppliedFonts.push_back( aPostScriptName );
+ }
+
+ // write glyphsets and reencodings
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); ++aIter)
+ {
+ if (aIter->GetFontType() == fonttype::TrueType)
+ {
+ aIter->PSUploadFont (*pFile, *this, mbUploadPS42Fonts ? true : false, rSuppliedFonts );
+ }
+ else
+ // ( aIter->GetFontType() == fonttype::Type1
+ // || aIter->GetFontType() == fonttype::Builtin )
+ {
+ aIter->PSUploadEncoding (pFile, *this);
+ if( aIter->GetFontType() == fonttype::Builtin )
+ rNeededFonts.push_back(
+ rtl::OUStringToOString(
+ mrFontMgr.getPSName( aIter->GetFontID() ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ }
+ }
+}
+
+bool PrinterGfx::getStrictSO52Compatibility() const
+{
+ return mbStrictSO52Compatibility;
+}
+
+void PrinterGfx::setStrictSO52Compatibility( bool bCompat)
+{
+ mbStrictSO52Compatibility = bCompat;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/window/FWS.cxx b/vcl/unx/generic/window/FWS.cxx
new file mode 100644
index 000000000000..a90f76af90c2
--- /dev/null
+++ b/vcl/unx/generic/window/FWS.cxx
@@ -0,0 +1,282 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include "FWS.hxx"
+
+static Atom fwsIconAtom;
+
+static Atom FWS_CLIENT;
+static Atom FWS_COMM_WINDOW;
+static Atom FWS_PROTOCOLS;
+static Atom FWS_STACK_UNDER;
+static Atom FWS_PARK_ICONS;
+static Atom FWS_PASS_ALL_INPUT;
+static Atom FWS_PASSES_INPUT;
+static Atom FWS_HANDLES_FOCUS;
+
+static Atom FWS_REGISTER_WINDOW;
+static Atom FWS_STATE_CHANGE;
+static Atom FWS_UNSEEN_STATE;
+static Atom FWS_NORMAL_STATE;
+static Atom WM_PROTOCOLS;
+static Atom WM_CHANGE_STATE;
+
+static Bool fwsStackUnder;
+static Bool fwsParkIcons;
+static Bool fwsPassesInput;
+static Bool fwsHandlesFocus;
+
+static Window fwsCommWindow;
+
+/*************************************<->***********************************
+ *
+ * WMSupportsFWS() -
+ *
+ * Initialize our atoms and determine if the current window manager is
+ * providing FWS extension support.
+ *
+ *************************************<->***********************************/
+
+Bool
+WMSupportsFWS (Display *display, int screen)
+{
+ unsigned int i;
+ Atom protocol;
+ Atom propType;
+ int propFormat;
+ unsigned long propItems;
+ unsigned long propBytesAfter;
+ unsigned char *propData;
+ char propName[64];
+
+ FWS_CLIENT = XInternAtom(display, "_SUN_FWS_CLIENT", False);
+ FWS_COMM_WINDOW = XInternAtom(display, "_SUN_FWS_COMM_WINDOW", False);
+ FWS_PROTOCOLS = XInternAtom(display, "_SUN_FWS_PROTOCOLS", False);
+ FWS_STACK_UNDER = XInternAtom(display, "_SUN_FWS_STACK_UNDER", False);
+ FWS_PARK_ICONS = XInternAtom(display, "_SUN_FWS_PARK_ICONS", False);
+ FWS_PASS_ALL_INPUT = XInternAtom(display, "_SUN_FWS_PASS_ALL_INPUT", False);
+ FWS_PASSES_INPUT = XInternAtom(display, "_SUN_FWS_PASSES_INPUT", False);
+ FWS_HANDLES_FOCUS = XInternAtom(display, "_SUN_FWS_HANDLES_FOCUS", False);
+ FWS_REGISTER_WINDOW= XInternAtom(display, "_SUN_FWS_REGISTER_WINDOW",False);
+ FWS_STATE_CHANGE = XInternAtom(display, "_SUN_FWS_STATE_CHANGE", False);
+ FWS_UNSEEN_STATE = XInternAtom(display, "_SUN_FWS_UNSEEN_STATE", False);
+ FWS_NORMAL_STATE = XInternAtom(display, "_SUN_FWS_NORMAL_STATE", False);
+ WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", False);
+ WM_CHANGE_STATE = XInternAtom(display, "WM_CHANGE_STATE", False);
+
+ snprintf (propName, sizeof(propName), "_SUN_FWS_NEXT_ICON_%d", screen);
+ fwsIconAtom = XInternAtom(display, propName, False);
+
+ if (XGetWindowProperty (display, DefaultRootWindow (display),
+ FWS_COMM_WINDOW, 0, 1,
+ False, AnyPropertyType, &propType,
+ &propFormat, &propItems,
+ &propBytesAfter, &propData) != Success)
+ return False;
+
+ if (propFormat != 32 ||
+ propItems != 1 ||
+ propBytesAfter != 0)
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Bad FWS_COMM_WINDOW property on root window.\n");
+ #endif
+ XFree (propData);
+ return False;
+ }
+
+ fwsCommWindow = *(Window *) propData;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Using fwsCommWindow = 0x%lx.\n", fwsCommWindow);
+ #endif
+ XFree (propData);
+
+
+ if (XGetWindowProperty (display, DefaultRootWindow (display),
+ FWS_PROTOCOLS, 0, 10,
+ False, AnyPropertyType, &propType,
+ &propFormat, &propItems,
+ &propBytesAfter, &propData) != Success)
+ {
+ return False;
+ }
+
+ if (propFormat != 32 ||
+ propBytesAfter != 0)
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Bad FWS_PROTOCOLS property on root window.\n");
+ #endif
+ XFree (propData);
+ return False;
+ }
+
+ for (i = 0; i < propItems; ++i)
+ {
+ protocol = ((Atom *) propData)[i];
+ if (protocol == FWS_STACK_UNDER)
+ {
+ fwsStackUnder = True;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Using fwsStackUnder.\n");
+ #endif
+ }
+ else
+ if (protocol == FWS_PARK_ICONS)
+ {
+ fwsParkIcons = True;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Using fwsParkIcons.\n");
+ #endif
+ }
+ else
+ if (protocol == FWS_PASSES_INPUT)
+ {
+ fwsPassesInput = True;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Using fwsPassesInput.\n");
+ #endif
+ }
+ else
+ if (protocol == FWS_HANDLES_FOCUS)
+ {
+ fwsHandlesFocus = True;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Using fwsHandlesFocus.\n");
+ #endif
+ }
+ }
+
+ XFree (propData);
+ return True;
+}
+
+/*************************************<->***********************************
+ *
+ * newHandler() -
+ *
+ * Handle X errors (temporarily) to record the occurrence of BadWindow
+ * errors without crashing. Used to detect the FWS_COMM_WINDOW root window
+ * property containing an old or obsolete window id.
+ *
+ *************************************<->***********************************/
+
+extern "C" {
+
+static Bool badWindowFound;
+static int (* oldHandler) (Display *, XErrorEvent *);
+
+static int
+newHandler (Display *display, XErrorEvent *xerror)
+{
+ if (xerror->error_code != BadWindow)
+ (*oldHandler)(display, xerror);
+ else
+ badWindowFound = True;
+
+ return 0;
+}
+
+}
+
+/*************************************<->***********************************
+ *
+ * RegisterFwsWindow() -
+ *
+ * Send a client message to the FWS_COMM_WINDOW indicating the existance
+ * of a new FWS client window. Be careful to avoid BadWindow errors on
+ * the XSendEvent in case the FWS_COMM_WINDOW root window property had
+ * old/obsolete junk in it.
+ *
+ *************************************<->***********************************/
+
+Bool
+RegisterFwsWindow (Display *display, Window window)
+{
+ XClientMessageEvent msg;
+
+ msg.type = ClientMessage;
+ msg.window = fwsCommWindow;
+ msg.message_type = FWS_REGISTER_WINDOW;
+ msg.format = 32;
+ msg.data.l[0] = window;
+
+ XSync (display, False);
+ badWindowFound = False;
+ oldHandler = XSetErrorHandler (newHandler);
+
+ XSendEvent (display, fwsCommWindow, False, NoEventMask,
+ (XEvent *) &msg);
+ XSync (display, False);
+
+ XSetErrorHandler (oldHandler);
+ #if OSL_DEBUG_LEVEL > 1
+ if (badWindowFound)
+ fprintf (stderr, "No FWS client window to register with.\n");
+ #endif
+
+ return !badWindowFound;
+}
+
+/*************************************<->***********************************
+ *
+ * AddFwsProtocols -
+ *
+ * Add the FWS protocol atoms to the WMProtocols property for the window.
+ *
+ *************************************<->***********************************/
+
+void
+AddFwsProtocols (Display *display, Window window)
+{
+ #define MAX_FWS_PROTOS 10
+
+ Atom fwsProtocols[ MAX_FWS_PROTOS ];
+ int nProtos = 0;
+
+ fwsProtocols[ nProtos++ ] = FWS_CLIENT;
+ fwsProtocols[ nProtos++ ] = FWS_STACK_UNDER;
+ fwsProtocols[ nProtos++ ] = FWS_STATE_CHANGE;
+ fwsProtocols[ nProtos++ ] = FWS_PASS_ALL_INPUT;
+ XChangeProperty (display, window, WM_PROTOCOLS,
+ XA_ATOM, 32, PropModeAppend,
+ (unsigned char *) fwsProtocols, nProtos);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/window/FWS.hxx b/vcl/unx/generic/window/FWS.hxx
new file mode 100644
index 000000000000..36b4b16a9214
--- /dev/null
+++ b/vcl/unx/generic/window/FWS.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _FOREIGN_WINDOW_SYSTEM_HXX
+#define _FOREIGN_WINDOW_SYSTEM_HXX
+
+#include <X11/Xlib.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Initialize our atoms and determine if the current window manager is
+ * providing FWS extension support.
+ */
+
+Bool
+WMSupportsFWS (Display *display, int screen);
+
+/* Send a client message to the FWS_COMM_WINDOW indicating the existance
+ * of a new FWS client window. Be careful to avoid BadWindow errors on
+ * the XSendEvent in case the FWS_COMM_WINDOW root window property had
+ * old/obsolete junk in it.
+ */
+
+Bool
+RegisterFwsWindow (Display *display, Window window);
+
+/* Add the FWS protocol atoms to the WMProtocols property for the window.
+ */
+
+void
+AddFwsProtocols (Display *display, Window window);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+#endif // _FOREIGN_WINDOW_SYSTEM_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/window/salframe.cxx b/vcl/unx/generic/window/salframe.cxx
new file mode 100644
index 000000000000..1fdfc02c3916
--- /dev/null
+++ b/vcl/unx/generic/window/salframe.cxx
@@ -0,0 +1,4567 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <unistd.h>
+
+#include "tools/debug.hxx"
+
+#include "sal/alloca.h"
+
+#include "vcl/floatwin.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/keycodes.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/settings.hxx"
+
+#include <tools/prex.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include "FWS.hxx"
+#include <X11/extensions/shape.h>
+#if !defined(SOLARIS) && !defined(AIX)
+#include <X11/extensions/dpms.h>
+#endif
+#include <tools/postx.h>
+
+#include "unx/salunx.h"
+#include "unx/saldata.hxx"
+#include "unx/saldisp.hxx"
+#include "unx/salgdi.h"
+#include "unx/salframe.h"
+#include "unx/soicon.hxx"
+#include "unx/dtint.hxx"
+#include "unx/sm.hxx"
+#include "unx/wmadaptor.hxx"
+#include "unx/salprn.h"
+#include "unx/salbmp.h"
+#include "unx/i18n_ic.hxx"
+#include "unx/i18n_keysym.hxx"
+#include "unx/i18n_status.hxx"
+
+#include "salinst.hxx"
+#include "sallayout.hxx"
+
+#include <sal/macros.h>
+#include <com/sun/star/uno/Exception.hpp>
+
+#include <algorithm>
+
+#ifndef Button6
+# define Button6 6
+#endif
+#ifndef Button7
+# define Button7 7
+#endif
+
+using namespace vcl_sal;
+using namespace vcl;
+
+// -=-= #defines -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#define CLIENT_EVENTS StructureNotifyMask \
+ | SubstructureNotifyMask \
+ | KeyPressMask \
+ | KeyReleaseMask \
+ | ButtonPressMask \
+ | ButtonReleaseMask \
+ | PointerMotionMask \
+ | EnterWindowMask \
+ | LeaveWindowMask \
+ | FocusChangeMask \
+ | ExposureMask \
+ | VisibilityChangeMask \
+ | PropertyChangeMask \
+ | ColormapChangeMask
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+static XLIB_Window hPresentationWindow = None, hPresFocusWindow = None;
+static ::std::list< XLIB_Window > aPresentationReparentList;
+static int nVisibleFloats = 0;
+
+X11SalFrame* X11SalFrame::s_pSaveYourselfFrame = NULL;
+
+// -=-= C++ statics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static void doReparentPresentationDialogues( SalDisplay* pDisplay )
+{
+ pDisplay->GetXLib()->PushXErrorLevel( true );
+ while( aPresentationReparentList.begin() != aPresentationReparentList.end() )
+ {
+ int x, y;
+ XLIB_Window aRoot, aChild;
+ unsigned int w, h, bw, d;
+ XGetGeometry( pDisplay->GetDisplay(),
+ aPresentationReparentList.front(),
+ &aRoot,
+ &x, &y, &w, &h, &bw, &d );
+ XTranslateCoordinates( pDisplay->GetDisplay(),
+ hPresentationWindow,
+ aRoot,
+ x, y,
+ &x, &y,
+ &aChild );
+ XReparentWindow( pDisplay->GetDisplay(),
+ aPresentationReparentList.front(),
+ aRoot,
+ x, y );
+ aPresentationReparentList.pop_front();
+ }
+ if( hPresFocusWindow )
+ XSetInputFocus( pDisplay->GetDisplay(), hPresFocusWindow, PointerRoot, CurrentTime );
+ XSync( pDisplay->GetDisplay(), False );
+ pDisplay->GetXLib()->PopXErrorLevel();
+}
+
+// -=-= SalFrame / X11SalFrame =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+bool X11SalFrame::IsOverrideRedirect() const
+{
+ return
+ ((nStyle_ & SAL_FRAME_STYLE_INTRO) && !pDisplay_->getWMAdaptor()->supportsSplash())
+ ||
+ (!( nStyle_ & ~SAL_FRAME_STYLE_DEFAULT ) && !pDisplay_->getWMAdaptor()->supportsFullScreen())
+ ;
+}
+
+bool X11SalFrame::IsFloatGrabWindow() const
+{
+ static const char* pDisableGrab = getenv( "SAL_DISABLE_FLOATGRAB" );
+
+ return
+ ( ( !pDisableGrab || !*pDisableGrab ) &&
+ (
+ (nStyle_ & SAL_FRAME_STYLE_FLOAT) &&
+ ! (nStyle_ & SAL_FRAME_STYLE_TOOLTIP) &&
+ ! (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION)
+ )
+ );
+}
+
+void X11SalFrame::setXEmbedInfo()
+{
+ if( m_bXEmbed )
+ {
+ long aInfo[2];
+ aInfo[0] = 1; // XEMBED protocol version
+ aInfo[1] = (bMapped_ ? 1 : 0); // XEMBED_MAPPED
+ XChangeProperty( pDisplay_->GetDisplay(),
+ mhWindow,
+ pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO ),
+ pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO ),
+ 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(aInfo),
+ SAL_N_ELEMENTS(aInfo) );
+ }
+}
+
+void X11SalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
+{
+ XEvent aEvent;
+
+ rtl_zeroMemory( &aEvent, sizeof(aEvent) );
+ aEvent.xclient.window = mhForeignParent;
+ aEvent.xclient.type = ClientMessage;
+ aEvent.xclient.message_type = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED );
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = i_nTimeCode ? i_nTimeCode : CurrentTime;
+ aEvent.xclient.data.l[1] = 3; // XEMBED_REQUEST_FOCUS
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+
+ GetDisplay()->GetXLib()->PushXErrorLevel( true );
+ XSendEvent( pDisplay_->GetDisplay(),
+ mhForeignParent,
+ False, NoEventMask, &aEvent );
+ XSync( pDisplay_->GetDisplay(), False );
+ GetDisplay()->GetXLib()->PopXErrorLevel();
+}
+
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::Init( sal_uLong nSalFrameStyle, int nScreen, SystemParentData* pParentData, bool bUseGeometry )
+{
+ if( nScreen < 0 || nScreen >= GetDisplay()->GetScreenCount() )
+ nScreen = GetDisplay()->GetDefaultScreenNumber();
+ if( mpParent )
+ nScreen = mpParent->m_nScreen;
+
+ m_nScreen = nScreen;
+ nStyle_ = nSalFrameStyle;
+ XWMHints Hints;
+ Hints.flags = InputHint;
+ Hints.input = (nSalFrameStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) ? False : True;
+
+ int x = 0, y = 0;
+ unsigned int w = 500, h = 500;
+ XSetWindowAttributes Attributes;
+
+ int nAttrMask = CWBorderPixel
+ | CWBackPixmap
+ | CWColormap
+ | CWOverrideRedirect
+ | CWEventMask
+ ;
+ Attributes.border_pixel = 0;
+ Attributes.background_pixmap = None;
+ Attributes.colormap = GetDisplay()->GetColormap( m_nScreen ).GetXColormap();
+ Attributes.override_redirect = False;
+ Attributes.event_mask = CLIENT_EVENTS;
+
+ const SalVisual& rVis = GetDisplay()->GetVisual( m_nScreen );
+ XLIB_Window aFrameParent = pParentData ? pParentData->aWindow : GetDisplay()->GetRootWindow( m_nScreen );
+ XLIB_Window aClientLeader = None;
+
+ if( bUseGeometry )
+ {
+ x = maGeometry.nX;
+ y = maGeometry.nY;
+ w = maGeometry.nWidth;
+ h = maGeometry.nHeight;
+ }
+
+ if( (nSalFrameStyle & SAL_FRAME_STYLE_FLOAT) &&
+ ! (nSalFrameStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION)
+ )
+ {
+ if( nShowState_ == SHOWSTATE_UNKNOWN )
+ {
+ w = 10;
+ h = 10;
+ }
+ Attributes.override_redirect = True;
+ }
+ else if( (nSalFrameStyle & SAL_FRAME_STYLE_SYSTEMCHILD ) )
+ {
+ DBG_ASSERT( mpParent, "SAL_FRAME_STYLE_SYSTEMCHILD window without parent" );
+ if( mpParent )
+ {
+ aFrameParent = mpParent->mhWindow;
+ // FIXME: since with SAL_FRAME_STYLE_SYSTEMCHILD
+ // multiple X11SalFrame objects can have the same shell window
+ // dispatching events in saldisp.cxx is unclear (the first frame)
+ // wins. HTH this correctly is unclear yet
+ // for the time being, treat set the shell window to own window
+ // like for a normal frame
+ // mhShellWindow = mpParent->GetShellWindow();
+ }
+ }
+ else if( pParentData )
+ {
+ // plugin parent may be killed unexpectedly by
+ // plugging process; ignore XErrors in that case
+ GetDisplay()->setHaveSystemChildFrame();
+
+ nStyle_ |= SAL_FRAME_STYLE_PLUG;
+ Attributes.override_redirect = True;
+ if( pParentData->nSize >= sizeof(SystemParentData) )
+ m_bXEmbed = pParentData->bXEmbedSupport;
+
+ int x_ret, y_ret;
+ unsigned int bw, d;
+ XLIB_Window aRoot, aParent;
+
+ XGetGeometry( GetXDisplay(), pParentData->aWindow,
+ &aRoot, &x_ret, &y_ret, &w, &h, &bw, &d );
+ mhForeignParent = pParentData->aWindow;
+
+ mhShellWindow = aParent = mhForeignParent;
+ XLIB_Window* pChildren;
+ unsigned int nChildren;
+ bool bBreak = false;
+ do
+ {
+ XQueryTree( GetDisplay()->GetDisplay(), mhShellWindow,
+ &aRoot, &aParent, &pChildren, &nChildren );
+ XFree( pChildren );
+ if( aParent != aRoot )
+ mhShellWindow = aParent;
+ int nCount = 0;
+ Atom* pProps = XListProperties( GetDisplay()->GetDisplay(),
+ mhShellWindow,
+ &nCount );
+ for( int i = 0; i < nCount && ! bBreak; ++i )
+ bBreak = (pProps[i] == XA_WM_HINTS);
+ if( pProps )
+ XFree( pProps );
+ } while( aParent != aRoot && ! bBreak );
+
+ // check if this is really one of our own frames
+ // do not change the input mask in that case
+ const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
+ std::list< SalFrame* >::const_iterator it = rFrames.begin();
+ while( it != rFrames.end() && mhForeignParent != static_cast<const X11SalFrame*>(*it)->GetWindow() )
+ ++it;
+
+ if( it == rFrames.end() )
+ {
+ XSelectInput( GetDisplay()->GetDisplay(), mhForeignParent, StructureNotifyMask | FocusChangeMask );
+ XSelectInput( GetDisplay()->GetDisplay(), mhShellWindow, StructureNotifyMask | FocusChangeMask );
+ }
+ }
+ else
+ {
+ if( ! bUseGeometry )
+ {
+ Size aScreenSize( GetDisplay()->getDataForScreen( m_nScreen ).m_aSize );
+ w = aScreenSize.Width();
+ h = aScreenSize.Height();
+ if( nSalFrameStyle & SAL_FRAME_STYLE_SIZEABLE &&
+ nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE )
+ {
+ // fill in holy default values brought to us by product management
+ if( aScreenSize.Width() >= 800 )
+ w = 785;
+ if( aScreenSize.Width() >= 1024 )
+ w = 920;
+
+ if( aScreenSize.Height() >= 600 )
+ h = 550;
+ if( aScreenSize.Height() >= 768 )
+ h = 630;
+ if( aScreenSize.Height() >= 1024 )
+ h = 875;
+ }
+ if( ! mpParent )
+ {
+ // find the last document window (if any)
+ const X11SalFrame* pFrame = NULL;
+ const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
+ std::list< SalFrame* >::const_iterator it = rFrames.begin();
+ while( it != rFrames.end() )
+ {
+ pFrame = static_cast< const X11SalFrame* >(*it);
+ if( ! ( pFrame->mpParent
+ || pFrame->mbFullScreen
+ || ! ( pFrame->nStyle_ & SAL_FRAME_STYLE_SIZEABLE )
+ || ! pFrame->GetUnmirroredGeometry().nWidth
+ || ! pFrame->GetUnmirroredGeometry().nHeight
+ )
+ )
+ break;
+ ++it;
+ }
+
+ if( it != rFrames.end() )
+ {
+ // set a document position and size
+ // the first frame gets positioned by the window manager
+ const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
+ x = rGeom.nX;
+ y = rGeom.nY;
+ if( x+(int)w+40 <= (int)aScreenSize.Width() &&
+ y+(int)h+40 <= (int)aScreenSize.Height()
+ )
+ {
+ y += 40;
+ x += 40;
+ }
+ else
+ {
+ x = 10; // leave some space for decoration
+ y = 20;
+ }
+ }
+ else if( GetDisplay()->IsXinerama() )
+ {
+ // place frame on same screen as mouse pointer
+ XLIB_Window aRoot, aChild;
+ int root_x = 0, root_y = 0, lx, ly;
+ unsigned int mask;
+ XQueryPointer( GetXDisplay(),
+ GetDisplay()->GetRootWindow( m_nScreen ),
+ &aRoot, &aChild,
+ &root_x, &root_y, &lx, &ly, &mask );
+ const std::vector< Rectangle >& rScreens = GetDisplay()->GetXineramaScreens();
+ for( unsigned int i = 0; i < rScreens.size(); i++ )
+ if( rScreens[i].IsInside( Point( root_x, root_y ) ) )
+ {
+ x = rScreens[i].Left();
+ y = rScreens[i].Top();
+ break;
+ }
+ }
+ }
+ }
+ Attributes.win_gravity = pDisplay_->getWMAdaptor()->getInitWinGravity();
+ nAttrMask |= CWWinGravity;
+ if( mpParent )
+ {
+ Attributes.save_under = True;
+ nAttrMask |= CWSaveUnder;
+ }
+ if( IsOverrideRedirect() )
+ Attributes.override_redirect = True;
+ // default icon
+ if( (nStyle_ & SAL_FRAME_STYLE_INTRO) == 0 )
+ {
+ bool bOk=false;
+ try
+ {
+ bOk=SelectAppIconPixmap( pDisplay_, m_nScreen,
+ mnIconID != 1 ? mnIconID :
+ (mpParent ? mpParent->mnIconID : 1), 32,
+ Hints.icon_pixmap, Hints.icon_mask );
+ }
+ catch( com::sun::star::uno::Exception& )
+ {
+ // can happen - no ucb during early startup
+ }
+ if( bOk )
+ {
+ Hints.flags |= IconPixmapHint;
+ if( Hints.icon_mask )
+ Hints.flags |= IconMaskHint;
+ }
+ }
+
+ // find the top level frame of the transience hierarchy
+ X11SalFrame* pFrame = this;
+ while( pFrame->mpParent )
+ pFrame = pFrame->mpParent;
+ if( (pFrame->nStyle_ & SAL_FRAME_STYLE_PLUG ) )
+ {
+ // if the top level window is a plugin window,
+ // then we should place us in the same window group as
+ // the parent application (or none if there is no window group
+ // hint in the parent).
+ if( pFrame->GetShellWindow() )
+ {
+ XWMHints* pWMHints = XGetWMHints( pDisplay_->GetDisplay(),
+ pFrame->GetShellWindow() );
+ if( pWMHints )
+ {
+ if( (pWMHints->flags & WindowGroupHint) )
+ {
+ Hints.flags |= WindowGroupHint;
+ Hints.window_group = pWMHints->window_group;
+ }
+ XFree( pWMHints );
+ }
+ }
+ }
+ else
+ {
+ Hints.flags |= WindowGroupHint;
+ Hints.window_group = pFrame->GetShellWindow();
+ // note: for a normal document window this will produce None
+ // as the window is not yet created and the shell window is
+ // initialized to None. This must be corrected after window creation.
+ aClientLeader = GetDisplay()->GetDrawable( m_nScreen );
+ }
+ }
+
+ nShowState_ = SHOWSTATE_UNKNOWN;
+ bViewable_ = sal_True;
+ bMapped_ = sal_False;
+ nVisibility_ = VisibilityFullyObscured;
+ mhWindow = XCreateWindow( GetXDisplay(),
+ aFrameParent,
+ x, y,
+ w, h,
+ 0,
+ rVis.GetDepth(),
+ InputOutput,
+ rVis.GetVisual(),
+ nAttrMask,
+ &Attributes );
+ // FIXME: see above: fake shell window for now to own window
+ if( pParentData == NULL )
+ {
+ mhShellWindow = mhWindow;
+ }
+
+ // correct window group if necessary
+ if( (Hints.flags & WindowGroupHint) == WindowGroupHint )
+ {
+ if( Hints.window_group == None )
+ Hints.window_group = GetShellWindow();
+ }
+
+ maGeometry.nX = x;
+ maGeometry.nY = y;
+ maGeometry.nWidth = w;
+ maGeometry.nHeight = h;
+ updateScreenNumber();
+
+ XSync( GetXDisplay(), False );
+ setXEmbedInfo();
+
+ XLIB_Time nUserTime = (nStyle_ & (SAL_FRAME_STYLE_OWNERDRAWDECORATION | SAL_FRAME_STYLE_TOOLWINDOW) ) == 0 ?
+ pDisplay_->GetLastUserEventTime() : 0;
+ pDisplay_->getWMAdaptor()->setUserTime( this, nUserTime );
+
+ if( ! pParentData && ! IsChildWindow() && ! Attributes.override_redirect )
+ {
+ XSetWMHints( GetXDisplay(), mhWindow, &Hints );
+ // WM Protocols && internals
+ Atom a[4];
+ int n = 0;
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_DELETE_WINDOW );
+ if( pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING ) )
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING );
+ if( ! s_pSaveYourselfFrame && ! mpParent)
+ {
+ // at all times have only one frame with SaveYourself
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_SAVE_YOURSELF );
+ s_pSaveYourselfFrame = this;
+ }
+ if( (nSalFrameStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_TAKE_FOCUS );
+ XSetWMProtocols( GetXDisplay(), GetShellWindow(), a, n );
+
+ // force wm class hint
+ mnExtStyle = ~0;
+ if (mpParent)
+ m_sWMClass = mpParent->m_sWMClass;
+ SetExtendedFrameStyle( 0 );
+
+ XSizeHints* pHints = XAllocSizeHints();
+ pHints->flags = PWinGravity | PPosition;
+ pHints->win_gravity = GetDisplay()->getWMAdaptor()->getPositionWinGravity();
+ pHints->x = 0;
+ pHints->y = 0;
+ if( mbFullScreen )
+ {
+ pHints->flags |= PMaxSize | PMinSize;
+ pHints->max_width = w+100;
+ pHints->max_height = h+100;
+ pHints->min_width = w;
+ pHints->min_height = h;
+ }
+ XSetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints );
+ XFree (pHints);
+
+ // set PID and WM_CLIENT_MACHINE
+ pDisplay_->getWMAdaptor()->setClientMachine( this );
+ pDisplay_->getWMAdaptor()->setPID( this );
+
+ // set client leader
+ if( aClientLeader )
+ {
+ XChangeProperty( GetXDisplay(),
+ mhWindow,
+ pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_CLIENT_LEADER),
+ XA_WINDOW,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&aClientLeader,
+ 1
+ );
+ }
+#define DECOFLAGS (SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE)
+ int nDecoFlags = WMAdaptor::decoration_All;
+ if( (nStyle_ & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN) ||
+ (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION)
+ )
+ nDecoFlags = 0;
+ else if( (nStyle_ & DECOFLAGS ) != DECOFLAGS || (nStyle_ & SAL_FRAME_STYLE_TOOLWINDOW) )
+ {
+ if( nStyle_ & DECOFLAGS )
+ // if any decoration, then show a border
+ nDecoFlags = WMAdaptor::decoration_Border;
+ else
+ nDecoFlags = 0;
+
+ if( ! mpParent && (nStyle_ & DECOFLAGS) )
+ // don't add a min button if window should be decorationless
+ nDecoFlags |= WMAdaptor::decoration_MinimizeBtn;
+ if( nStyle_ & SAL_FRAME_STYLE_CLOSEABLE )
+ nDecoFlags |= WMAdaptor::decoration_CloseBtn;
+ if( nStyle_ & SAL_FRAME_STYLE_SIZEABLE )
+ {
+ nDecoFlags |= WMAdaptor::decoration_Resize;
+ if( ! (nStyle_ & SAL_FRAME_STYLE_TOOLWINDOW) )
+ nDecoFlags |= WMAdaptor::decoration_MaximizeBtn;
+ }
+ if( nStyle_ & SAL_FRAME_STYLE_MOVEABLE )
+ nDecoFlags |= WMAdaptor::decoration_Title;
+ }
+
+ WMAdaptor::WMWindowType eType = WMAdaptor::windowType_Normal;
+ if( nStyle_ & SAL_FRAME_STYLE_INTRO )
+ eType = WMAdaptor::windowType_Splash;
+ if( (nStyle_ & SAL_FRAME_STYLE_DIALOG) && hPresentationWindow == None )
+ eType = WMAdaptor::windowType_ModelessDialogue;
+ if( nStyle_ & SAL_FRAME_STYLE_TOOLWINDOW )
+ eType = WMAdaptor::windowType_Utility;
+ if( nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION )
+ eType = WMAdaptor::windowType_Toolbar;
+ if( (nStyle_ & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN)
+ && GetDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ eType = WMAdaptor::windowType_Dock;
+
+ GetDisplay()->getWMAdaptor()->
+ setFrameTypeAndDecoration( this,
+ eType,
+ nDecoFlags,
+ hPresentationWindow ? NULL : mpParent );
+
+ if( (nStyle_ & (SAL_FRAME_STYLE_DEFAULT |
+ SAL_FRAME_STYLE_OWNERDRAWDECORATION|
+ SAL_FRAME_STYLE_FLOAT |
+ SAL_FRAME_STYLE_INTRO |
+ SAL_FRAME_STYLE_PARTIAL_FULLSCREEN) )
+ == SAL_FRAME_STYLE_DEFAULT )
+ pDisplay_->getWMAdaptor()->maximizeFrame( this, true, true );
+ }
+
+ m_nWorkArea = GetDisplay()->getWMAdaptor()->getCurrentWorkArea();
+
+ // Pointer
+ SetPointer( POINTER_ARROW );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+X11SalFrame::X11SalFrame( SalFrame *pParent, sal_uLong nSalFrameStyle, SystemParentData* pSystemParent )
+{
+ X11SalData* pSalData = GetX11SalData();
+
+ // initialize frame geometry
+ memset( &maGeometry, 0, sizeof(maGeometry) );
+
+ mpParent = static_cast< X11SalFrame* >( pParent );
+
+ mbTransientForRoot = false;
+
+ pDisplay_ = pSalData->GetDisplay();
+ // insert frame in framelist
+ pDisplay_->registerFrame( this );
+
+ mhWindow = None;
+ mhShellWindow = None;
+ mhStackingWindow = None;
+ mhForeignParent = None;
+ mhBackgroundPixmap = None;
+ m_bSetFocusOnMap = false;
+
+ pGraphics_ = NULL;
+ pFreeGraphics_ = NULL;
+
+ hCursor_ = None;
+ nCaptured_ = 0;
+
+ nReleaseTime_ = 0;
+ nKeyCode_ = 0;
+ nKeyState_ = 0;
+ nCompose_ = -1;
+ mbSendExtKeyModChange = false;
+ mnExtKeyMod = 0;
+
+ nShowState_ = SHOWSTATE_UNKNOWN;
+ nWidth_ = 0;
+ nHeight_ = 0;
+ nStyle_ = 0;
+ mnExtStyle = 0;
+ bAlwaysOnTop_ = sal_False;
+
+ // set bViewable_ to sal_True: hack GetClientSize to report something
+ // different to 0/0 before first map
+ bViewable_ = sal_True;
+ bMapped_ = sal_False;
+ bDefaultPosition_ = sal_True;
+ nVisibility_ = VisibilityFullyObscured;
+ m_nWorkArea = 0;
+ mbInShow = sal_False;
+ m_bXEmbed = false;
+
+ nScreenSaversTimeout_ = 0;
+
+ mpInputContext = NULL;
+ mbInputFocus = False;
+
+ maAlwaysOnTopRaiseTimer.SetTimeoutHdl( LINK( this, X11SalFrame, HandleAlwaysOnTopRaise ) );
+ maAlwaysOnTopRaiseTimer.SetTimeout( 100 );
+
+ meWindowType = WMAdaptor::windowType_Normal;
+ mnDecorationFlags = WMAdaptor::decoration_All;
+ mbMaximizedVert = false;
+ mbMaximizedHorz = false;
+ mbShaded = false;
+ mbFullScreen = false;
+
+ mnIconID = 1; // ICON_DEFAULT
+
+ m_pClipRectangles = NULL;
+ m_nCurClipRect = 0;
+ m_nMaxClipRect = 0;
+
+ if( mpParent )
+ mpParent->maChildren.push_back( this );
+
+ Init( nSalFrameStyle, GetDisplay()->GetDefaultScreenNumber(), pSystemParent );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::passOnSaveYourSelf()
+{
+ if( this == s_pSaveYourselfFrame )
+ {
+ // pass on SaveYourself
+ const X11SalFrame* pFrame = NULL;
+ const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
+ std::list< SalFrame* >::const_iterator it = rFrames.begin();
+ while( it != rFrames.end() )
+ {
+ pFrame = static_cast< const X11SalFrame* >(*it);
+ if( ! ( IsChildWindow() || pFrame->mpParent )
+ && pFrame != s_pSaveYourselfFrame )
+ break;
+ ++it;
+ }
+
+ s_pSaveYourselfFrame = (it != rFrames.end() ) ? const_cast<X11SalFrame*>(pFrame) : NULL;
+ if( s_pSaveYourselfFrame )
+ {
+ Atom a[4];
+ int n = 0;
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_DELETE_WINDOW );
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_SAVE_YOURSELF );
+ if( pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING ) )
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING );
+ XSetWMProtocols( GetXDisplay(), s_pSaveYourselfFrame->GetShellWindow(), a, n );
+ }
+ }
+}
+
+X11SalFrame::~X11SalFrame()
+{
+ notifyDelete();
+
+ if( m_pClipRectangles )
+ {
+ delete [] m_pClipRectangles;
+ m_pClipRectangles = NULL;
+ m_nCurClipRect = m_nMaxClipRect = 0;
+ }
+
+ if( mhBackgroundPixmap )
+ {
+ XSetWindowBackgroundPixmap( GetXDisplay(), GetWindow(), None );
+ XFreePixmap( GetXDisplay(), mhBackgroundPixmap );
+ }
+
+ if( mhStackingWindow )
+ aPresentationReparentList.remove( mhStackingWindow );
+
+ // remove from parent's list
+ if( mpParent )
+ mpParent->maChildren.remove( this );
+
+ // deregister on SalDisplay
+ pDisplay_->deregisterFrame( this );
+
+ // unselect all events, some may be still in the queue anyway
+ if( ! IsSysChildWindow() )
+ XSelectInput( GetXDisplay(), GetShellWindow(), 0 );
+ XSelectInput( GetXDisplay(), GetWindow(), 0 );
+
+ ShowFullScreen( sal_False, 0 );
+
+ if( bMapped_ )
+ Show( sal_False );
+
+ if( mpInputContext )
+ {
+ mpInputContext->UnsetICFocus( this );
+ mpInputContext->Unmap( this );
+ delete mpInputContext;
+ }
+
+ if( GetWindow() == hPresentationWindow )
+ {
+ hPresentationWindow = None;
+ doReparentPresentationDialogues( GetDisplay() );
+ }
+
+ if( pGraphics_ )
+ {
+ pGraphics_->DeInit();
+ delete pGraphics_;
+ }
+
+ if( pFreeGraphics_ )
+ {
+ pFreeGraphics_->DeInit();
+ delete pFreeGraphics_;
+ }
+
+
+ XDestroyWindow( GetXDisplay(), mhWindow );
+
+ /*
+ * check if there is only the status frame left
+ * if so, free it
+ */
+ if( ! GetDisplay()->getFrames().empty() && I18NStatus::exists() )
+ {
+ SalFrame* pStatusFrame = I18NStatus::get().getStatusFrame();
+ std::list< SalFrame* >::const_iterator sit = GetDisplay()->getFrames().begin();
+ if( pStatusFrame
+ && *sit == pStatusFrame
+ && ++sit == GetDisplay()->getFrames().end() )
+ vcl::I18NStatus::free();
+ }
+
+ passOnSaveYourSelf();
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
+{
+ if( nStyle != mnExtStyle && ! IsChildWindow() )
+ {
+ mnExtStyle = nStyle;
+ updateWMClass();
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetBackgroundBitmap( SalBitmap* pBitmap )
+{
+ if( mhBackgroundPixmap )
+ {
+ XSetWindowBackgroundPixmap( GetXDisplay(), GetWindow(), None );
+ XFreePixmap( GetXDisplay(), mhBackgroundPixmap );
+ mhBackgroundPixmap = None;
+ }
+ if( pBitmap )
+ {
+ X11SalBitmap* pBM = static_cast<X11SalBitmap*>(pBitmap);
+ Size aSize = pBM->GetSize();
+ if( aSize.Width() && aSize.Height() )
+ {
+ mhBackgroundPixmap =
+ XCreatePixmap( GetXDisplay(),
+ GetWindow(),
+ aSize.Width(),
+ aSize.Height(),
+ GetDisplay()->GetVisual( m_nScreen ).GetDepth() );
+ if( mhBackgroundPixmap )
+ {
+ SalTwoRect aTwoRect;
+ aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
+ aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width();
+ aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height();
+ pBM->ImplDraw( mhBackgroundPixmap,
+ m_nScreen,
+ GetDisplay()->GetVisual( m_nScreen ).GetDepth(),
+ aTwoRect, GetDisplay()->GetCopyGC( m_nScreen ) );
+ XSetWindowBackgroundPixmap( GetXDisplay(), GetWindow(), mhBackgroundPixmap );
+ }
+ }
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+const SystemChildData* X11SalFrame::GetSystemData() const
+{
+ X11SalFrame *pFrame = const_cast<X11SalFrame*>(this);
+ pFrame->maSystemChildData.nSize = sizeof( SystemChildData );
+ pFrame->maSystemChildData.pDisplay = GetXDisplay();
+ pFrame->maSystemChildData.aWindow = pFrame->GetWindow();
+ pFrame->maSystemChildData.pSalFrame = pFrame;
+ pFrame->maSystemChildData.pWidget = NULL;
+ pFrame->maSystemChildData.pVisual = GetDisplay()->GetVisual( m_nScreen ).GetVisual();
+ pFrame->maSystemChildData.nScreen = m_nScreen;
+ pFrame->maSystemChildData.nDepth = GetDisplay()->GetVisual( m_nScreen ).GetDepth();
+ pFrame->maSystemChildData.aColormap = GetDisplay()->GetColormap( m_nScreen ).GetXColormap();
+ pFrame->maSystemChildData.pAppContext = NULL;
+ pFrame->maSystemChildData.aShellWindow = pFrame->GetShellWindow();
+ pFrame->maSystemChildData.pShellWidget = NULL;
+ return &maSystemChildData;
+}
+
+SalGraphics *X11SalFrame::GetGraphics()
+{
+ if( pGraphics_ )
+ return NULL;
+
+ if( pFreeGraphics_ )
+ {
+ pGraphics_ = pFreeGraphics_;
+ pFreeGraphics_ = NULL;
+ }
+ else
+ {
+ pGraphics_ = new X11SalGraphics();
+ pGraphics_->Init( this, GetWindow(), m_nScreen );
+ }
+
+ return pGraphics_;
+}
+
+void X11SalFrame::ReleaseGraphics( SalGraphics *pGraphics )
+{
+ DBG_ASSERT( pGraphics == pGraphics_, "SalFrame::ReleaseGraphics pGraphics!=pGraphics_" );
+
+ if( pGraphics != pGraphics_ )
+ return;
+
+ pFreeGraphics_ = pGraphics_;
+ pGraphics_ = NULL;
+}
+
+void X11SalFrame::updateGraphics( bool bClear )
+{
+ Drawable aDrawable = bClear ? None : GetWindow();
+ if( pGraphics_ )
+ pGraphics_->SetDrawable( aDrawable, m_nScreen );
+ if( pFreeGraphics_ )
+ pFreeGraphics_->SetDrawable( aDrawable, m_nScreen );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::Enable( sal_Bool /*bEnable*/ )
+{
+ // NYI: enable/disable frame
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetIcon( sal_uInt16 nIcon )
+{
+ if ( ! IsChildWindow() )
+ {
+ // 0 == default icon -> #1
+ if ( nIcon == 0 )
+ nIcon = 1;
+
+ mnIconID = nIcon;
+
+ XIconSize *pIconSize = NULL;
+ int nSizes = 0;
+ int iconSize = 32;
+ if ( XGetIconSizes( GetXDisplay(), GetDisplay()->GetRootWindow( m_nScreen ), &pIconSize, &nSizes ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "X11SalFrame::SetIcon(): found %d IconSizes:\n", nSizes);
+#endif
+
+ const int ourLargestIconSize = 48;
+ bool bFoundIconSize = false;
+
+ int i;
+ for( i=0; i<nSizes; i++)
+ {
+ // select largest supported icon
+
+ // Note: olwm/olvwm reports a huge max icon size of
+ // 160x160 pixels; always choosing the max as the
+ // preferred icon size is apparently wrong under olvwm
+ // - so we keep the safe default |iconSize| when we see
+ // unreasonable large max icon sizes (> twice of our
+ // largest available icon) reported by XGetIconSizes.
+ if( pIconSize[i].max_width > iconSize
+ && pIconSize[i].max_width <= 2*ourLargestIconSize )
+ {
+ iconSize = pIconSize[i].max_width;
+ bFoundIconSize = true;
+ }
+ iconSize = pIconSize[i].max_width;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "min: %d, %d\nmax: %d, %d\ninc: %d, %d\n\n",
+ pIconSize[i].min_width, pIconSize[i].min_height,
+ pIconSize[i].max_width, pIconSize[i].max_height,
+ pIconSize[i].width_inc, pIconSize[i].height_inc);
+#endif
+ }
+
+ if ( !bFoundIconSize )
+ {
+ // Unless someone has fixed olwm/olvwm, we have rejected
+ // the max icon size from |XGetIconSizes()|. Provide a
+ // better icon size default value, in case our window manager
+ // is olwm/olvwm.
+ const String& rWM( pDisplay_->getWMAdaptor()->getWindowManagerName() );
+
+ if ( rWM.EqualsAscii( "Olwm" ) )
+ iconSize = 48;
+ }
+
+ XFree( pIconSize );
+ }
+ else
+ {
+ const String& rWM( pDisplay_->getWMAdaptor()->getWindowManagerName() );
+ if( rWM.EqualsAscii( "KWin" ) ) // assume KDE is running
+ iconSize = 48;
+ static bool bGnomeIconSize = false;
+ static bool bGnomeChecked = false;
+ if( ! bGnomeChecked )
+ {
+ bGnomeChecked=true;
+ int nCount = 0;
+ Atom* pProps = XListProperties( GetXDisplay(),
+ GetDisplay()->GetRootWindow( m_nScreen ),
+ &nCount );
+ for( int i = 0; i < nCount && !bGnomeIconSize; i++ )
+ {
+ char* pName = XGetAtomName( GetXDisplay(), pProps[i] );
+ if( !strcmp( pName, "GNOME_PANEL_DESKTOP_AREA" ) )
+ bGnomeIconSize = true;
+ if( pName )
+ XFree( pName );
+ }
+ if( pProps )
+ XFree( pProps );
+ }
+ if( bGnomeIconSize )
+ iconSize = 48;
+ }
+
+ XWMHints Hints;
+ Hints.flags = 0;
+ XWMHints *pHints = XGetWMHints( GetXDisplay(), GetShellWindow() );
+ if( pHints )
+ {
+ memcpy(&Hints, pHints, sizeof( XWMHints ));
+ XFree( pHints );
+ }
+ pHints = &Hints;
+
+ sal_Bool bOk = SelectAppIconPixmap( GetDisplay(), m_nScreen,
+ nIcon, iconSize,
+ pHints->icon_pixmap, pHints->icon_mask );
+ if ( !bOk )
+ {
+ // load default icon (0)
+ bOk = SelectAppIconPixmap( GetDisplay(), m_nScreen,
+ 0, iconSize,
+ pHints->icon_pixmap, pHints->icon_mask );
+ }
+ if( bOk )
+ {
+ pHints->flags |= IconPixmapHint;
+ if( pHints->icon_mask )
+ pHints->flags |= IconMaskHint;
+
+ XSetWMHints( GetXDisplay(), GetShellWindow(), pHints );
+ }
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetMaxClientSize( long nWidth, long nHeight )
+{
+ if( ! IsChildWindow() )
+ {
+ if( GetShellWindow() && (nStyle_ & (SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) != SAL_FRAME_STYLE_FLOAT )
+ {
+ XSizeHints* pHints = XAllocSizeHints();
+ long nSupplied = 0;
+ XGetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints,
+ &nSupplied
+ );
+ pHints->max_width = nWidth;
+ pHints->max_height = nHeight;
+ pHints->flags |= PMaxSize;
+ XSetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints );
+ XFree( pHints );
+ }
+ }
+}
+
+void X11SalFrame::SetMinClientSize( long nWidth, long nHeight )
+{
+ if( ! IsChildWindow() )
+ {
+ if( GetShellWindow() && (nStyle_ & (SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) != SAL_FRAME_STYLE_FLOAT )
+ {
+ XSizeHints* pHints = XAllocSizeHints();
+ long nSupplied = 0;
+ XGetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints,
+ &nSupplied
+ );
+ pHints->min_width = nWidth;
+ pHints->min_height = nHeight;
+ pHints->flags |= PMinSize;
+ XSetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints );
+ XFree( pHints );
+ }
+ }
+}
+
+// Show + Pos (x,y,z) + Size (width,height)
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::Show( sal_Bool bVisible, sal_Bool bNoActivate )
+{
+ if( ( bVisible && bMapped_ )
+ || ( !bVisible && !bMapped_ ) )
+ return;
+
+ // HACK: this is a workaround for (at least) kwin
+ // even though transient frames should be kept above their parent
+ // this does not necessarily hold true for DOCK type windows
+ // so artificially set ABOVE and remove it again on hide
+ if( mpParent && (mpParent->nStyle_ & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN ) && pDisplay_->getWMAdaptor()->isLegacyPartialFullscreen())
+ pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bVisible );
+
+ bMapped_ = bVisible;
+ bViewable_ = bVisible;
+ setXEmbedInfo();
+ if( bVisible )
+ {
+ mbInShow = sal_True;
+ if( ! (nStyle_ & SAL_FRAME_STYLE_INTRO) )
+ {
+ // hide all INTRO frames
+ const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it);
+ // look for intro bit map; if present, hide it
+ if( pFrame->nStyle_ & SAL_FRAME_STYLE_INTRO )
+ {
+ if( pFrame->bMapped_ )
+ const_cast<X11SalFrame*>(pFrame)->Show( sal_False );
+ }
+ }
+ }
+
+ // update NET_WM_STATE which may have been deleted due to earlier Show(sal_False)
+ if( nShowState_ == SHOWSTATE_HIDDEN )
+ GetDisplay()->getWMAdaptor()->frameIsMapping( this );
+
+ /*
+ * Actually this is rather exotic and currently happens only in conjunction
+ * with the basic dialogue editor,
+ * which shows a frame and instantly hides it again. After that the
+ * editor window is shown and the WM takes this as an opportunity
+ * to show our hidden transient frame also. So Show( sal_False ) must
+ * withdraw the frame AND delete the WM_TRANSIENT_FOR property.
+ * In case the frame is shown again, the transient hint must be restored here.
+ */
+ if( ! IsChildWindow()
+ && ! IsOverrideRedirect()
+ && ! IsFloatGrabWindow()
+ && mpParent
+ )
+ {
+ GetDisplay()->getWMAdaptor()->changeReferenceFrame( this, mpParent );
+ }
+
+ // #i45160# switch to desktop where a dialog with parent will appear
+ if( mpParent && mpParent->m_nWorkArea != m_nWorkArea )
+ GetDisplay()->getWMAdaptor()->switchToWorkArea( mpParent->m_nWorkArea );
+
+ if( IsFloatGrabWindow() &&
+ mpParent &&
+ nVisibleFloats == 0 &&
+ ! GetDisplay()->GetCaptureFrame() )
+ {
+ /* #i39420#
+ * outsmart KWin's "focus strictly under mouse" mode
+ * which insists on taking the focus from the document
+ * to the new float. Grab focus to parent frame BEFORE
+ * showing the float (cannot grab it to the float
+ * before show).
+ */
+ XGrabPointer( GetXDisplay(),
+ mpParent->GetWindow(),
+ True,
+ PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ mpParent ? mpParent->GetCursor() : None,
+ CurrentTime
+ );
+ }
+
+ XLIB_Time nUserTime = 0;
+ if( ! bNoActivate && (nStyle_ & (SAL_FRAME_STYLE_OWNERDRAWDECORATION)) == 0 )
+ nUserTime = pDisplay_->GetLastUserEventTime( true );
+ GetDisplay()->getWMAdaptor()->setUserTime( this, nUserTime );
+ if( ! bNoActivate && (nStyle_ & SAL_FRAME_STYLE_TOOLWINDOW) )
+ m_bSetFocusOnMap = true;
+
+ // actually map the window
+ if( m_bXEmbed )
+ askForXEmbedFocus( 0 );
+ else
+ {
+ if( GetWindow() != GetShellWindow() && ! IsSysChildWindow() )
+ {
+ if( IsChildWindow() )
+ XMapWindow( GetXDisplay(), GetShellWindow() );
+ XSelectInput( GetXDisplay(), GetShellWindow(), CLIENT_EVENTS );
+ }
+ if( nStyle_ & SAL_FRAME_STYLE_FLOAT )
+ XMapRaised( GetXDisplay(), GetWindow() );
+ else
+ XMapWindow( GetXDisplay(), GetWindow() );
+ }
+ XSelectInput( GetXDisplay(), GetWindow(), CLIENT_EVENTS );
+
+ if( maGeometry.nWidth > 0
+ && maGeometry.nHeight > 0
+ && ( nWidth_ != (int)maGeometry.nWidth
+ || nHeight_ != (int)maGeometry.nHeight ) )
+ {
+ nWidth_ = maGeometry.nWidth;
+ nHeight_ = maGeometry.nHeight;
+ }
+
+ XSync( GetXDisplay(), False );
+
+ if( IsFloatGrabWindow() )
+ {
+ /*
+ * Sawfish and twm can be switched to enter-exit focus behaviour. In this case
+ * we must grab the pointer else the dumb WM will put the focus to the
+ * override-redirect float window. The application window will be deactivated
+ * which causes that the floats are destroyed, so the user can never click on
+ * a menu because it vanishes as soon as he enters it.
+ */
+ nVisibleFloats++;
+ if( nVisibleFloats == 1 && ! GetDisplay()->GetCaptureFrame() )
+ {
+ /* #i39420# now move grab to the new float window */
+ XGrabPointer( GetXDisplay(),
+ GetWindow(),
+ True,
+ PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ mpParent ? mpParent->GetCursor() : None,
+ CurrentTime
+ );
+ }
+ }
+ CallCallback( SALEVENT_RESIZE, NULL );
+
+ /*
+ * sometimes a message box/dialogue is brought up when a frame is not mapped
+ * the corresponding TRANSIENT_FOR hint is then set to the root window
+ * so that the dialogue shows in all cases. Correct it here if the
+ * frame is shown afterwards.
+ */
+ if( ! IsChildWindow()
+ && ! IsOverrideRedirect()
+ && ! IsFloatGrabWindow()
+ )
+ {
+ for( std::list< X11SalFrame* >::const_iterator it = maChildren.begin();
+ it != maChildren.end(); ++it )
+ {
+ if( (*it)->mbTransientForRoot )
+ GetDisplay()->getWMAdaptor()->changeReferenceFrame( *it, this );
+ }
+ }
+ /*
+ * leave SHOWSTATE_UNKNOWN as this indicates first mapping
+ * and is only reset int HandleSizeEvent
+ */
+ if( nShowState_ != SHOWSTATE_UNKNOWN )
+ nShowState_ = SHOWSTATE_NORMAL;
+
+ /*
+ * plugged windows don't necessarily get the
+ * focus on show because the parent may already be mapped
+ * and have the focus. So try to set the focus
+ * to the child on Show(sal_True)
+ */
+ if( (nStyle_ & SAL_FRAME_STYLE_PLUG) && ! m_bXEmbed )
+ XSetInputFocus( GetXDisplay(),
+ GetWindow(),
+ RevertToParent,
+ CurrentTime );
+
+ if( mpParent )
+ {
+ // push this frame so it will be in front of its siblings
+ // only necessary for insane transient behaviour of Dtwm/olwm
+ mpParent->maChildren.remove( this );
+ mpParent->maChildren.push_front(this);
+ }
+ }
+ else
+ {
+ if( getInputContext() )
+ getInputContext()->Unmap( this );
+
+ if( ! IsChildWindow() )
+ {
+ /* FIXME: Is deleting the property really necessary ? It hurts
+ * owner drawn windows at least.
+ */
+ if( mpParent && ! (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ XDeleteProperty( GetXDisplay(), GetShellWindow(), GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::WM_TRANSIENT_FOR ) );
+ XWithdrawWindow( GetXDisplay(), GetShellWindow(), m_nScreen );
+ }
+ else if( ! m_bXEmbed )
+ XUnmapWindow( GetXDisplay(), GetWindow() );
+
+ nShowState_ = SHOWSTATE_HIDDEN;
+ if( IsFloatGrabWindow() && nVisibleFloats )
+ {
+ nVisibleFloats--;
+ if( nVisibleFloats == 0 && ! GetDisplay()->GetCaptureFrame() )
+ XUngrabPointer( GetXDisplay(),
+ CurrentTime );
+ }
+ // flush here; there may be a very seldom race between
+ // the display connection used for clipboard and our connection
+ Flush();
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::ToTop( sal_uInt16 nFlags )
+{
+ if( ( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
+ && ! ( nStyle_ & SAL_FRAME_STYLE_FLOAT )
+ && nShowState_ != SHOWSTATE_HIDDEN
+ && nShowState_ != SHOWSTATE_UNKNOWN
+ )
+ {
+ GetDisplay()->getWMAdaptor()->frameIsMapping( this );
+ if( GetWindow() != GetShellWindow() && ! IsSysChildWindow() )
+ XMapWindow( GetXDisplay(), GetShellWindow() );
+ XMapWindow( GetXDisplay(), GetWindow() );
+ }
+
+ XLIB_Window aToTopWindow = IsSysChildWindow() ? GetWindow() : GetShellWindow();
+ if( ! (nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY) )
+ {
+ XRaiseWindow( GetXDisplay(), aToTopWindow );
+ if( ! GetDisplay()->getWMAdaptor()->isTransientBehaviourAsExpected() )
+ for( std::list< X11SalFrame* >::const_iterator it = maChildren.begin();
+ it != maChildren.end(); ++it )
+ (*it)->ToTop( nFlags & ~SAL_FRAME_TOTOP_GRABFOCUS );
+ }
+
+ if( ( ( nFlags & SAL_FRAME_TOTOP_GRABFOCUS ) || ( nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY ) )
+ && bMapped_ )
+ {
+ if( m_bXEmbed )
+ askForXEmbedFocus( 0 );
+ else
+ XSetInputFocus( GetXDisplay(), aToTopWindow, RevertToParent, CurrentTime );
+ }
+}
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::GetWorkArea( Rectangle& rWorkArea )
+{
+ rWorkArea = pDisplay_->getWMAdaptor()->getWorkArea( 0 );
+}
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::GetClientSize( long &rWidth, long &rHeight )
+{
+ if( ! bViewable_ )
+ {
+ rWidth = rHeight = 0;
+ return;
+ }
+
+ rWidth = maGeometry.nWidth;
+ rHeight = maGeometry.nHeight;
+
+ if( !rWidth || !rHeight )
+ {
+ XWindowAttributes aAttrib;
+
+ XGetWindowAttributes( GetXDisplay(), GetWindow(), &aAttrib );
+
+ maGeometry.nWidth = rWidth = aAttrib.width;
+ maGeometry.nHeight = rHeight = aAttrib.height;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetWindowGravity (int nGravity) const
+{
+ if( ! IsChildWindow() )
+ {
+ XSizeHints* pHint = XAllocSizeHints();
+ long nFlag;
+
+ XGetWMNormalHints (GetXDisplay(), GetShellWindow(), pHint, &nFlag);
+ pHint->flags |= PWinGravity;
+ pHint->win_gravity = nGravity;
+
+ XSetWMNormalHints (GetXDisplay(), GetShellWindow(), pHint);
+ XSync (GetXDisplay(), False);
+
+ XFree (pHint);
+ }
+}
+
+void X11SalFrame::Center( )
+{
+ int nX, nY, nScreenWidth, nScreenHeight;
+ int nRealScreenWidth, nRealScreenHeight;
+ int nScreenX = 0, nScreenY = 0;
+
+ const Size& aScreenSize = GetDisplay()->getDataForScreen( m_nScreen ).m_aSize;
+ nScreenWidth = aScreenSize.Width();
+ nScreenHeight = aScreenSize.Height();
+ nRealScreenWidth = nScreenWidth;
+ nRealScreenHeight = nScreenHeight;
+
+ if( GetDisplay()->IsXinerama() )
+ {
+ // get xinerama screen we are on
+ // if there is a parent, use its center for screen determination
+ // else use the pointer
+ XLIB_Window aRoot, aChild;
+ int root_x, root_y, x, y;
+ unsigned int mask;
+ if( mpParent )
+ {
+ root_x = mpParent->maGeometry.nX + mpParent->maGeometry.nWidth/2;
+ root_y = mpParent->maGeometry.nY + mpParent->maGeometry.nHeight/2;
+ }
+ else
+ XQueryPointer( GetXDisplay(),
+ GetShellWindow(),
+ &aRoot, &aChild,
+ &root_x, &root_y,
+ &x, &y,
+ &mask );
+ const std::vector< Rectangle >& rScreens = GetDisplay()->GetXineramaScreens();
+ for( unsigned int i = 0; i < rScreens.size(); i++ )
+ if( rScreens[i].IsInside( Point( root_x, root_y ) ) )
+ {
+ nScreenX = rScreens[i].Left();
+ nScreenY = rScreens[i].Top();
+ nRealScreenWidth = rScreens[i].GetWidth();
+ nRealScreenHeight = rScreens[i].GetHeight();
+ break;
+ }
+ }
+
+ if( mpParent )
+ {
+ X11SalFrame* pFrame = mpParent;
+ while( pFrame->mpParent )
+ pFrame = pFrame->mpParent;
+ if( pFrame->maGeometry.nWidth < 1 || pFrame->maGeometry.nHeight < 1 )
+ {
+ Rectangle aRect;
+ pFrame->GetPosSize( aRect );
+ pFrame->maGeometry.nX = aRect.Left();
+ pFrame->maGeometry.nY = aRect.Top();
+ pFrame->maGeometry.nWidth = aRect.GetWidth();
+ pFrame->maGeometry.nHeight = aRect.GetHeight();
+ }
+
+ if( pFrame->nStyle_ & SAL_FRAME_STYLE_PLUG )
+ {
+ XLIB_Window aRoot;
+ unsigned int bw, depth;
+ XGetGeometry( GetXDisplay(),
+ pFrame->GetShellWindow(),
+ &aRoot,
+ &nScreenX, &nScreenY,
+ (unsigned int*)&nScreenWidth,
+ (unsigned int*)&nScreenHeight,
+ &bw, &depth );
+ }
+ else
+ {
+ nScreenX = pFrame->maGeometry.nX;
+ nScreenY = pFrame->maGeometry.nY;
+ nScreenWidth = pFrame->maGeometry.nWidth;
+ nScreenHeight = pFrame->maGeometry.nHeight;
+ }
+ }
+
+ if( mpParent && mpParent->nShowState_ == SHOWSTATE_NORMAL )
+ {
+ if( maGeometry.nWidth >= mpParent->maGeometry.nWidth &&
+ maGeometry.nHeight >= mpParent->maGeometry.nHeight )
+ {
+ nX = nScreenX + 40;
+ nY = nScreenY + 40;
+ }
+ else
+ {
+ // center the window relative to the top level frame
+ nX = (nScreenWidth - (int)maGeometry.nWidth ) / 2 + nScreenX;
+ nY = (nScreenHeight - (int)maGeometry.nHeight) / 2 + nScreenY;
+ }
+ }
+ else
+ {
+ // center the window relative to screen
+ nX = (nRealScreenWidth - (int)maGeometry.nWidth ) / 2 + nScreenX;
+ nY = (nRealScreenHeight - (int)maGeometry.nHeight) / 2 + nScreenY;
+ }
+ nX = nX < 0 ? 0 : nX;
+ nY = nY < 0 ? 0 : nY;
+
+ bDefaultPosition_ = False;
+ if( mpParent )
+ {
+ nX -= mpParent->maGeometry.nX;
+ nY -= mpParent->maGeometry.nY;
+ }
+
+ Point aPoint(nX, nY);
+ SetPosSize( Rectangle( aPoint, Size( maGeometry.nWidth, maGeometry.nHeight ) ) );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::updateScreenNumber()
+{
+ if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
+ {
+ Point aPoint( maGeometry.nX, maGeometry.nY );
+ const std::vector<Rectangle>& rScreenRects( GetDisplay()->GetXineramaScreens() );
+ size_t nScreens = rScreenRects.size();
+ for( size_t i = 0; i < nScreens; i++ )
+ {
+ if( rScreenRects[i].IsInside( aPoint ) )
+ {
+ maGeometry.nScreenNumber = static_cast<unsigned int>(i);
+ break;
+ }
+ }
+ }
+ else
+ maGeometry.nScreenNumber = static_cast<unsigned int>(m_nScreen);
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
+{
+ if( nStyle_ & SAL_FRAME_STYLE_PLUG )
+ return;
+
+ // relative positioning in X11SalFrame::SetPosSize
+ Rectangle aPosSize( Point( maGeometry.nX, maGeometry.nY ), Size( maGeometry.nWidth, maGeometry.nHeight ) );
+ aPosSize.Justify();
+
+ if( ! ( nFlags & SAL_FRAME_POSSIZE_X ) )
+ {
+ nX = aPosSize.Left();
+ if( mpParent )
+ nX -= mpParent->maGeometry.nX;
+ }
+ if( ! ( nFlags & SAL_FRAME_POSSIZE_Y ) )
+ {
+ nY = aPosSize.Top();
+ if( mpParent )
+ nY -= mpParent->maGeometry.nY;
+ }
+ if( ! ( nFlags & SAL_FRAME_POSSIZE_WIDTH ) )
+ nWidth = aPosSize.GetWidth();
+ if( ! ( nFlags & SAL_FRAME_POSSIZE_HEIGHT ) )
+ nHeight = aPosSize.GetHeight();
+
+ aPosSize = Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
+
+ if( ! ( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) ) )
+ {
+ if( bDefaultPosition_ )
+ {
+ maGeometry.nWidth = aPosSize.GetWidth();
+ maGeometry.nHeight = aPosSize.GetHeight();
+ Center();
+ }
+ else
+ SetSize( Size( nWidth, nHeight ) );
+ }
+ else
+ SetPosSize( aPosSize );
+
+ bDefaultPosition_ = False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::SetAlwaysOnTop( sal_Bool bOnTop )
+{
+ if( ! IsOverrideRedirect() )
+ {
+ bAlwaysOnTop_ = bOnTop;
+ pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bOnTop );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#define _FRAMESTATE_MASK_GEOMETRY \
+ (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y | \
+ SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT)
+#define _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY \
+ (SAL_FRAMESTATE_MASK_MAXIMIZED_X | SAL_FRAMESTATE_MASK_MAXIMIZED_Y | \
+ SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT)
+
+void X11SalFrame::SetWindowState( const SalFrameState *pState )
+{
+ if (pState == NULL)
+ return;
+
+ // Request for position or size change
+ if (pState->mnMask & _FRAMESTATE_MASK_GEOMETRY)
+ {
+ Rectangle aPosSize;
+ bool bDoAdjust = false;
+
+ /* #i44325#
+ * if maximized, set restore size and guess maximized size from last time
+ * in state change below maximize window
+ */
+ if( ! IsChildWindow() &&
+ (pState->mnMask & SAL_FRAMESTATE_MASK_STATE) &&
+ (pState->mnState & SAL_FRAMESTATE_MAXIMIZED) &&
+ (pState->mnMask & _FRAMESTATE_MASK_GEOMETRY) == _FRAMESTATE_MASK_GEOMETRY &&
+ (pState->mnMask & _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY) == _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY
+ )
+ {
+ XSizeHints* pHints = XAllocSizeHints();
+ long nSupplied = 0;
+ XGetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints,
+ &nSupplied );
+ pHints->flags |= PPosition | PWinGravity;
+ pHints->x = pState->mnX;
+ pHints->y = pState->mnY;
+ pHints->win_gravity = pDisplay_->getWMAdaptor()->getPositionWinGravity();
+ XSetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints );
+ XFree( pHints );
+
+ XMoveResizeWindow( GetXDisplay(), GetShellWindow(),
+ pState->mnX, pState->mnY,
+ pState->mnWidth, pState->mnHeight );
+ // guess maximized geometry from last time
+ maGeometry.nX = pState->mnMaximizedX;
+ maGeometry.nY = pState->mnMaximizedY;
+ maGeometry.nWidth = pState->mnMaximizedWidth;
+ maGeometry.nHeight = pState->mnMaximizedHeight;
+ updateScreenNumber();
+ }
+ else
+ {
+ // initialize with current geometry
+ if ((pState->mnMask & _FRAMESTATE_MASK_GEOMETRY) != _FRAMESTATE_MASK_GEOMETRY)
+ GetPosSize (aPosSize);
+
+ // change requested properties
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_X)
+ {
+ aPosSize.setX (pState->mnX);
+ }
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_Y)
+ {
+ aPosSize.setY (pState->mnY);
+ }
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH)
+ {
+ long nWidth = pState->mnWidth > 0 ? pState->mnWidth - 1 : 0;
+ aPosSize.setWidth (nWidth);
+ bDoAdjust = true;
+ }
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT)
+ {
+ int nHeight = pState->mnHeight > 0 ? pState->mnHeight - 1 : 0;
+ aPosSize.setHeight (nHeight);
+ bDoAdjust = true;
+ }
+
+ const Size& aScreenSize = pDisplay_->getDataForScreen( m_nScreen ).m_aSize;
+ const WMAdaptor *pWM = GetDisplay()->getWMAdaptor();
+
+ if( bDoAdjust && aPosSize.GetWidth() <= aScreenSize.Width()
+ && aPosSize.GetHeight() <= aScreenSize.Height() )
+ {
+ SalFrameGeometry aGeom = maGeometry;
+
+ if( ! (nStyle_ & ( SAL_FRAME_STYLE_FLOAT | SAL_FRAME_STYLE_PLUG ) ) &&
+ mpParent &&
+ aGeom.nLeftDecoration == 0 &&
+ aGeom.nTopDecoration == 0 )
+ {
+ aGeom = mpParent->maGeometry;
+ if( aGeom.nLeftDecoration == 0 &&
+ aGeom.nTopDecoration == 0 )
+ {
+ aGeom.nLeftDecoration = 5;
+ aGeom.nTopDecoration = 20;
+ aGeom.nRightDecoration = 5;
+ aGeom.nBottomDecoration = 5;
+ }
+ }
+
+ // adjust position so that frame fits onto screen
+ if( aPosSize.Right()+(long)aGeom.nRightDecoration > aScreenSize.Width()-1 )
+ aPosSize.Move( (long)aScreenSize.Width() - (long)aPosSize.Right() - (long)aGeom.nRightDecoration, 0 );
+ if( aPosSize.Bottom()+(long)aGeom.nBottomDecoration > aScreenSize.Height()-1 )
+ aPosSize.Move( 0, (long)aScreenSize.Height() - (long)aPosSize.Bottom() - (long)aGeom.nBottomDecoration );
+ if( aPosSize.Left() < (long)aGeom.nLeftDecoration )
+ aPosSize.Move( (long)aGeom.nLeftDecoration - (long)aPosSize.Left(), 0 );
+ if( aPosSize.Top() < (long)aGeom.nTopDecoration )
+ aPosSize.Move( 0, (long)aGeom.nTopDecoration - (long)aPosSize.Top() );
+ }
+
+ // resize with new args
+ if (pWM->supportsICCCMPos())
+ {
+ if( mpParent )
+ aPosSize.Move( -mpParent->maGeometry.nX,
+ -mpParent->maGeometry.nY );
+ SetPosSize( aPosSize );
+ bDefaultPosition_ = False;
+ }
+ else
+ SetPosSize( 0, 0, aPosSize.GetWidth(), aPosSize.GetHeight(), SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+ }
+ }
+
+ // request for status change
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_STATE)
+ {
+ if (pState->mnState & SAL_FRAMESTATE_MAXIMIZED)
+ {
+ nShowState_ = SHOWSTATE_NORMAL;
+ if( ! (pState->mnState & (SAL_FRAMESTATE_MAXIMIZED_HORZ|SAL_FRAMESTATE_MAXIMIZED_VERT) ) )
+ Maximize();
+ else
+ {
+ bool bHorz = (pState->mnState & SAL_FRAMESTATE_MAXIMIZED_HORZ) ? true : false;
+ bool bVert = (pState->mnState & SAL_FRAMESTATE_MAXIMIZED_VERT) ? true : false;
+ GetDisplay()->getWMAdaptor()->maximizeFrame( this, bHorz, bVert );
+ }
+ maRestorePosSize.Left() = pState->mnX;
+ maRestorePosSize.Top() = pState->mnY;
+ maRestorePosSize.Right() = maRestorePosSize.Left() + pState->mnWidth;
+ maRestorePosSize.Right() = maRestorePosSize.Left() + pState->mnHeight;
+ }
+ else if( mbMaximizedHorz || mbMaximizedVert )
+ GetDisplay()->getWMAdaptor()->maximizeFrame( this, false, false );
+
+ if (pState->mnState & SAL_FRAMESTATE_MINIMIZED)
+ {
+ if (nShowState_ == SHOWSTATE_UNKNOWN)
+ nShowState_ = SHOWSTATE_NORMAL;
+ Minimize();
+ }
+ if (pState->mnState & SAL_FRAMESTATE_NORMAL)
+ {
+ if (nShowState_ != SHOWSTATE_NORMAL)
+ Restore();
+ }
+ if (pState->mnState & SAL_FRAMESTATE_ROLLUP)
+ GetDisplay()->getWMAdaptor()->shade( this, true );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+sal_Bool X11SalFrame::GetWindowState( SalFrameState* pState )
+{
+ if( SHOWSTATE_MINIMIZED == nShowState_ )
+ pState->mnState = SAL_FRAMESTATE_MINIMIZED;
+ else
+ pState->mnState = SAL_FRAMESTATE_NORMAL;
+
+ Rectangle aPosSize;
+ if( maRestorePosSize.IsEmpty() )
+ GetPosSize( aPosSize );
+ else
+ aPosSize = maRestorePosSize;
+
+ if( mbMaximizedHorz )
+ pState->mnState |= SAL_FRAMESTATE_MAXIMIZED_HORZ;
+ if( mbMaximizedVert )
+ pState->mnState |= SAL_FRAMESTATE_MAXIMIZED_VERT;
+ if( mbShaded )
+ pState->mnState |= SAL_FRAMESTATE_ROLLUP;
+
+ pState->mnX = aPosSize.Left();
+ pState->mnY = aPosSize.Top();
+ pState->mnWidth = aPosSize.GetWidth();
+ pState->mnHeight = aPosSize.GetHeight();
+
+ pState->mnMask = _FRAMESTATE_MASK_GEOMETRY | SAL_FRAMESTATE_MASK_STATE;
+
+
+ if (! maRestorePosSize.IsEmpty() )
+ {
+ GetPosSize( aPosSize );
+ pState->mnState |= SAL_FRAMESTATE_MAXIMIZED;
+ pState->mnMaximizedX = aPosSize.Left();
+ pState->mnMaximizedY = aPosSize.Top();
+ pState->mnMaximizedWidth = aPosSize.GetWidth();
+ pState->mnMaximizedHeight = aPosSize.GetHeight();
+ pState->mnMask |= _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY;
+ }
+
+ return sal_True;
+}
+
+// ----------------------------------------------------------------------------
+// get a screenshot of the current frame including window manager decoration
+SalBitmap* X11SalFrame::SnapShot()
+{
+ Display* pDisplay = GetXDisplay();
+
+ // make sure the frame has been reparented and all paint timer have been
+ // expired
+ do
+ {
+ XSync(pDisplay, False);
+ Application::Reschedule ();
+ }
+ while (XPending(pDisplay));
+ TimeValue aVal;
+ aVal.Seconds = 0;
+ aVal.Nanosec = 50000000;
+ osl_waitThread( &aVal );
+ do
+ {
+ XSync(pDisplay, False);
+ Application::Reschedule ();
+ }
+ while (XPending(pDisplay));
+
+ // get the most outer window, usually the window manager decoration
+ Drawable hWindow = None;
+ if (IsOverrideRedirect())
+ hWindow = GetDrawable();
+ else
+ if (hPresentationWindow != None)
+ hWindow = hPresentationWindow;
+ else
+ hWindow = GetStackingWindow();
+
+ // query the contents of the window
+ if (hWindow != None)
+ {
+ X11SalBitmap *pBmp = new X11SalBitmap;
+ if (pBmp->SnapShot (pDisplay, hWindow))
+ return pBmp;
+ else
+ delete pBmp;
+ }
+
+ return NULL;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// native menu implementation - currently empty
+void X11SalFrame::DrawMenuBar()
+{
+}
+
+void X11SalFrame::SetMenu( SalMenu* )
+{
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::GetPosSize( Rectangle &rPosSize )
+{
+ if( maGeometry.nWidth < 1 || maGeometry.nHeight < 1 )
+ {
+ const Size& aScreenSize = pDisplay_->getDataForScreen( m_nScreen ).m_aSize;
+ long w = aScreenSize.Width() - maGeometry.nLeftDecoration - maGeometry.nRightDecoration;
+ long h = aScreenSize.Height() - maGeometry.nTopDecoration - maGeometry.nBottomDecoration;
+
+ rPosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ), Size( w, h ) );
+ }
+ else
+ rPosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
+ Size( maGeometry.nWidth, maGeometry.nHeight ) );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::SetSize( const Size &rSize )
+{
+ if( rSize.Width() > 0 && rSize.Height() > 0 )
+ {
+ if( ! ( nStyle_ & SAL_FRAME_STYLE_SIZEABLE )
+ && ! IsChildWindow()
+ && ( nStyle_ & (SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) != SAL_FRAME_STYLE_FLOAT )
+ {
+ XSizeHints* pHints = XAllocSizeHints();
+ long nSupplied = 0;
+ XGetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints,
+ &nSupplied
+ );
+ pHints->min_width = rSize.Width();
+ pHints->min_height = rSize.Height();
+ pHints->max_width = rSize.Width();
+ pHints->max_height = rSize.Height();
+ pHints->flags |= PMinSize | PMaxSize;
+ XSetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints );
+ XFree( pHints );
+ }
+ XResizeWindow( GetXDisplay(), IsSysChildWindow() ? GetWindow() : GetShellWindow(), rSize.Width(), rSize.Height() );
+ if( GetWindow() != GetShellWindow() )
+ {
+ if( (nStyle_ & SAL_FRAME_STYLE_PLUG ) )
+ XMoveResizeWindow( GetXDisplay(), GetWindow(), 0, 0, rSize.Width(), rSize.Height() );
+ else
+ XResizeWindow( GetXDisplay(), GetWindow(), rSize.Width(), rSize.Height() );
+ }
+
+ maGeometry.nWidth = rSize.Width();
+ maGeometry.nHeight = rSize.Height();
+
+ // allow the external status window to reposition
+ if (mbInputFocus && mpInputContext != NULL)
+ mpInputContext->SetICFocus ( this );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetPosSize( const Rectangle &rPosSize )
+{
+ XWindowChanges values;
+ values.x = rPosSize.Left();
+ values.y = rPosSize.Top();
+ values.width = rPosSize.GetWidth();
+ values.height = rPosSize.GetHeight();
+
+ if( !values.width || !values.height )
+ return;
+
+ if( mpParent && ! IsSysChildWindow() )
+ {
+ // --- RTL --- (mirror window pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ values.x = mpParent->maGeometry.nWidth-values.width-1-values.x;
+
+ XLIB_Window aChild;
+ // coordinates are relative to parent, so translate to root coordinates
+ XTranslateCoordinates( GetDisplay()->GetDisplay(),
+ mpParent->GetWindow(),
+ GetDisplay()->GetRootWindow( m_nScreen ),
+ values.x, values.y,
+ &values.x, &values.y,
+ & aChild );
+ }
+
+ bool bMoved = false;
+ bool bSized = false;
+ if( values.x != maGeometry.nX || values.y != maGeometry.nY )
+ bMoved = true;
+ if( values.width != (int)maGeometry.nWidth || values.height != (int)maGeometry.nHeight )
+ bSized = true;
+
+ if( ! ( nStyle_ & ( SAL_FRAME_STYLE_PLUG | SAL_FRAME_STYLE_FLOAT ) )
+ && !(pDisplay_->GetProperties() & PROPERTY_SUPPORT_WM_ClientPos) )
+ {
+ values.x -= maGeometry.nLeftDecoration;
+ values.y -= maGeometry.nTopDecoration;
+ }
+
+ // do net set WMNormalHints for ..
+ if(
+ // child windows
+ ! IsChildWindow()
+ // popups (menu, help window, etc.)
+ && (nStyle_ & (SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) != SAL_FRAME_STYLE_FLOAT
+ // shown, sizeable windows
+ && ( nShowState_ == SHOWSTATE_UNKNOWN ||
+ nShowState_ == SHOWSTATE_HIDDEN ||
+ ! ( nStyle_ & SAL_FRAME_STYLE_SIZEABLE )
+ )
+ )
+ {
+ XSizeHints* pHints = XAllocSizeHints();
+ long nSupplied = 0;
+ XGetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints,
+ &nSupplied
+ );
+ if( ! ( nStyle_ & SAL_FRAME_STYLE_SIZEABLE ) )
+ {
+ pHints->min_width = rPosSize.GetWidth();
+ pHints->min_height = rPosSize.GetHeight();
+ pHints->max_width = rPosSize.GetWidth();
+ pHints->max_height = rPosSize.GetHeight();
+ pHints->flags |= PMinSize | PMaxSize;
+ }
+ if( nShowState_ == SHOWSTATE_UNKNOWN || nShowState_ == SHOWSTATE_HIDDEN )
+ {
+ pHints->flags |= PPosition | PWinGravity;
+ pHints->x = values.x;
+ pHints->y = values.y;
+ pHints->win_gravity = pDisplay_->getWMAdaptor()->getPositionWinGravity();
+ }
+ if( mbFullScreen )
+ {
+ pHints->max_width = 10000;
+ pHints->max_height = 10000;
+ pHints->flags |= PMaxSize;
+ }
+ XSetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints );
+ XFree( pHints );
+ }
+
+ XMoveResizeWindow( GetXDisplay(), IsSysChildWindow() ? GetWindow() : GetShellWindow(), values.x, values.y, values.width, values.height );
+ if( GetShellWindow() != GetWindow() )
+ {
+ if( (nStyle_ & SAL_FRAME_STYLE_PLUG ) )
+ XMoveResizeWindow( GetXDisplay(), GetWindow(), 0, 0, values.width, values.height );
+ else
+ XMoveResizeWindow( GetXDisplay(), GetWindow(), values.x, values.y, values.width, values.height );
+ }
+
+ maGeometry.nX = values.x;
+ maGeometry.nY = values.y;
+ maGeometry.nWidth = values.width;
+ maGeometry.nHeight = values.height;
+ if( IsSysChildWindow() && mpParent )
+ {
+ // translate back to root coordinates
+ maGeometry.nX += mpParent->maGeometry.nX;
+ maGeometry.nY += mpParent->maGeometry.nY;
+ }
+
+ updateScreenNumber();
+ if( bSized && ! bMoved )
+ CallCallback( SALEVENT_RESIZE, NULL );
+ else if( bMoved && ! bSized )
+ CallCallback( SALEVENT_MOVE, NULL );
+ else
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+
+ // allow the external status window to reposition
+ if (mbInputFocus && mpInputContext != NULL)
+ mpInputContext->SetICFocus ( this );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::Minimize()
+{
+ if( IsSysChildWindow() )
+ return;
+
+ if( SHOWSTATE_UNKNOWN == nShowState_ || SHOWSTATE_HIDDEN == nShowState_ )
+ {
+ stderr0( "X11SalFrame::Minimize on withdrawn window\n" );
+ return;
+ }
+
+ if( XIconifyWindow( GetXDisplay(),
+ GetShellWindow(),
+ pDisplay_->GetDefaultScreenNumber() ) )
+ nShowState_ = SHOWSTATE_MINIMIZED;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::Maximize()
+{
+ if( IsSysChildWindow() )
+ return;
+
+ if( SHOWSTATE_MINIMIZED == nShowState_ )
+ {
+ GetDisplay()->getWMAdaptor()->frameIsMapping( this );
+ XMapWindow( GetXDisplay(), GetShellWindow() );
+ nShowState_ = SHOWSTATE_NORMAL;
+ }
+
+ pDisplay_->getWMAdaptor()->maximizeFrame( this, true, true );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::Restore()
+{
+ if( IsSysChildWindow() )
+ return;
+
+ if( SHOWSTATE_UNKNOWN == nShowState_ || SHOWSTATE_HIDDEN == nShowState_ )
+ {
+ stderr0( "X11SalFrame::Restore on withdrawn window\n" );
+ return;
+ }
+
+ if( SHOWSTATE_MINIMIZED == nShowState_ )
+ {
+ GetDisplay()->getWMAdaptor()->frameIsMapping( this );
+ XMapWindow( GetXDisplay(), GetShellWindow() );
+ nShowState_ = SHOWSTATE_NORMAL;
+ }
+
+ pDisplay_->getWMAdaptor()->maximizeFrame( this, false, false );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetScreenNumber( unsigned int nNewScreen )
+{
+ if( nNewScreen == maGeometry.nScreenNumber )
+ return;
+
+ if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
+ {
+ if( nNewScreen >= GetDisplay()->GetXineramaScreens().size() )
+ return;
+
+ Rectangle aOldScreenRect( GetDisplay()->GetXineramaScreens()[maGeometry.nScreenNumber] );
+ Rectangle aNewScreenRect( GetDisplay()->GetXineramaScreens()[nNewScreen] );
+ bool bVisible = bMapped_;
+ if( bVisible )
+ Show( sal_False );
+ maGeometry.nX = aNewScreenRect.Left() + (maGeometry.nX - aOldScreenRect.Left());
+ maGeometry.nY = aNewScreenRect.Top() + (maGeometry.nY - aOldScreenRect.Top());
+ createNewWindow( None, m_nScreen );
+ if( bVisible )
+ Show( sal_True );
+ maGeometry.nScreenNumber = nNewScreen;
+ }
+ else if( sal_Int32(nNewScreen) < GetDisplay()->GetScreenCount() )
+ {
+ bool bVisible = bMapped_;
+ if( bVisible )
+ Show( sal_False );
+ createNewWindow( None, nNewScreen );
+ if( bVisible )
+ Show( sal_True );
+ maGeometry.nScreenNumber = nNewScreen;
+ }
+}
+
+void X11SalFrame::SetApplicationID( const rtl::OUString &rWMClass )
+{
+ if( rWMClass != m_sWMClass && ! IsChildWindow() )
+ {
+ m_sWMClass = rWMClass;
+ updateWMClass();
+ std::list< X11SalFrame* >::const_iterator it;
+ for( it = maChildren.begin(); it != maChildren.end(); ++it )
+ (*it)->SetApplicationID(rWMClass);
+ }
+}
+
+void X11SalFrame::updateWMClass()
+{
+ XClassHint* pClass = XAllocClassHint();
+ rtl::OString aResName = X11SalData::getFrameResName( mnExtStyle );
+ pClass->res_name = const_cast<char*>(aResName.getStr());
+
+ rtl::OString aResClass = rtl::OUStringToOString(m_sWMClass, RTL_TEXTENCODING_ASCII_US);
+ const char *pResClass = aResClass.getLength() ? aResClass.getStr() : X11SalData::getFrameClassName();
+
+ pClass->res_class = const_cast<char*>(pResClass);
+ XSetClassHint( GetXDisplay(), GetShellWindow(), pClass );
+ XFree( pClass );
+}
+
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::ShowFullScreen( sal_Bool bFullScreen, sal_Int32 nScreen )
+{
+ if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
+ {
+ if( mbFullScreen == (bool)bFullScreen )
+ return;
+ if( bFullScreen )
+ {
+ maRestorePosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
+ Size( maGeometry.nWidth, maGeometry.nHeight ) );
+ Rectangle aRect;
+ if( nScreen < 0 || nScreen >= static_cast<int>(GetDisplay()->GetXineramaScreens().size()) )
+ aRect = Rectangle( Point(0,0), GetDisplay()->GetScreenSize( m_nScreen ) );
+ else
+ aRect = GetDisplay()->GetXineramaScreens()[nScreen];
+ nStyle_ |= SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
+ bool bVisible = bMapped_;
+ if( bVisible )
+ Show( sal_False );
+ maGeometry.nX = aRect.Left();
+ maGeometry.nY = aRect.Top();
+ maGeometry.nWidth = aRect.GetWidth();
+ maGeometry.nHeight = aRect.GetHeight();
+ mbMaximizedHorz = mbMaximizedVert = false;
+ mbFullScreen = true;
+ createNewWindow( None, m_nScreen );
+ if( GetDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ GetDisplay()->getWMAdaptor()->enableAlwaysOnTop( this, true );
+ else
+ GetDisplay()->getWMAdaptor()->showFullScreen( this, true );
+ if( bVisible )
+ Show(sal_True);
+
+ }
+ else
+ {
+ mbFullScreen = false;
+ nStyle_ &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
+ bool bVisible = bMapped_;
+ Rectangle aRect = maRestorePosSize;
+ maRestorePosSize = Rectangle();
+ if( bVisible )
+ Show( sal_False );
+ createNewWindow( None, m_nScreen );
+ if( !aRect.IsEmpty() )
+ SetPosSize( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(),
+ SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y |
+ SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+ if( bVisible )
+ Show( sal_True );
+ }
+ }
+ else
+ {
+ if( nScreen < 0 || nScreen >= GetDisplay()->GetScreenCount() )
+ nScreen = m_nScreen;
+ if( nScreen != m_nScreen )
+ {
+ bool bVisible = bMapped_;
+ if( mbFullScreen )
+ pDisplay_->getWMAdaptor()->showFullScreen( this, false );
+ if( bVisible )
+ Show( sal_False );
+ createNewWindow( None, nScreen );
+ if( mbFullScreen )
+ pDisplay_->getWMAdaptor()->showFullScreen( this, true );
+ if( bVisible )
+ Show( sal_True );
+ }
+ if( mbFullScreen == (bool)bFullScreen )
+ return;
+
+ pDisplay_->getWMAdaptor()->showFullScreen( this, bFullScreen );
+ if( IsOverrideRedirect()
+ && WMSupportsFWS( GetXDisplay(), GetDisplay()->GetRootWindow( m_nScreen ) ) )
+ {
+ AddFwsProtocols( GetXDisplay(), GetShellWindow() );
+ RegisterFwsWindow( GetXDisplay(), GetShellWindow() );
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------
+ the xautolock pseudo screen saver needs special treatment since it
+ doesn't cooperate with XxxxScreenSaver settings
+ ------------------------------------------------------------------- */
+
+static Bool
+IsRunningXAutoLock( Display *p_display, XLIB_Window a_window )
+{
+ const char *p_atomname = "XAUTOLOCK_SEMAPHORE_PID";
+ Atom a_pidatom;
+
+ // xautolock interns this atom
+ a_pidatom = XInternAtom( p_display, p_atomname, True );
+ if ( a_pidatom == None )
+ return False;
+
+ Atom a_type;
+ int n_format;
+ unsigned long n_items;
+ unsigned long n_bytes_after;
+ pid_t *p_pid;
+ pid_t n_pid;
+ // get pid of running xautolock
+ XGetWindowProperty (p_display, a_window, a_pidatom, 0L, 2L, False,
+ AnyPropertyType, &a_type, &n_format, &n_items, &n_bytes_after,
+ (unsigned char**) &p_pid );
+ n_pid = *p_pid;
+ XFree( p_pid );
+
+ if ( a_type == XA_INTEGER )
+ {
+ // check if xautolock pid points to a running process
+ if ( kill(n_pid, 0) == -1 )
+ return False;
+ else
+ return True;
+ }
+
+ return False;
+}
+
+/* definitions from xautolock.c (pl15) */
+#define XAUTOLOCK_DISABLE 1
+#define XAUTOLOCK_ENABLE 2
+
+static Bool
+MessageToXAutoLock( Display *p_display, int n_message )
+{
+ const char *p_atomname = "XAUTOLOCK_MESSAGE" ;
+ Atom a_messageatom;
+ XLIB_Window a_rootwindow;
+
+ a_rootwindow = RootWindowOfScreen( ScreenOfDisplay(p_display, 0) );
+ if ( ! IsRunningXAutoLock(p_display, a_rootwindow) )
+ {
+ // remove any pending messages
+ a_messageatom = XInternAtom( p_display, p_atomname, True );
+ if ( a_messageatom != None )
+ XDeleteProperty( p_display, a_rootwindow, a_messageatom );
+ return False;
+ }
+
+ a_messageatom = XInternAtom( p_display, p_atomname, False );
+ XChangeProperty (p_display, a_rootwindow, a_messageatom, XA_INTEGER,
+ 8, PropModeReplace, (unsigned char*)&n_message, sizeof(n_message) );
+
+ return True;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::StartPresentation( sal_Bool bStart )
+{
+ I18NStatus::get().show( !bStart, I18NStatus::presentation );
+ if ( bStart )
+ MessageToXAutoLock( GetXDisplay(), XAUTOLOCK_DISABLE );
+ else
+ MessageToXAutoLock( GetXDisplay(), XAUTOLOCK_ENABLE );
+
+ if( ! bStart && hPresentationWindow != None )
+ doReparentPresentationDialogues( GetDisplay() );
+ hPresentationWindow = (bStart && IsOverrideRedirect() ) ? GetWindow() : None;
+
+
+ // needs static here to save DPMS settings
+ int dummy;
+ static bool DPMSExtensionAvailable =
+#if !defined(SOLARIS) && !defined(AIX)
+ (DPMSQueryExtension(GetXDisplay(), &dummy, &dummy) != 0);
+ static sal_Bool DPMSEnabled = false;
+#else
+ false;
+ bool DPMSEnabled = false;
+ (void)dummy;
+#define CARD16 unsigned short
+#endif
+ static CARD16 dpms_standby_timeout=0;
+ static CARD16 dpms_suspend_timeout=0;
+ static CARD16 dpms_off_timeout=0;
+
+
+ if( bStart || nScreenSaversTimeout_ || DPMSEnabled)
+ {
+ if( hPresentationWindow )
+ {
+ /* #i10559# workaround for WindowMaker: try to restore
+ * current focus after presentation window is gone
+ */
+ int revert_to = 0;
+ XGetInputFocus( GetXDisplay(), &hPresFocusWindow, &revert_to );
+ }
+ int timeout, interval, prefer_blanking, allow_exposures;
+ XGetScreenSaver( GetXDisplay(),
+ &timeout,
+ &interval,
+ &prefer_blanking,
+ &allow_exposures );
+
+
+ // get the DPMS state right before the start
+ if (DPMSExtensionAvailable)
+ {
+#if !defined(SOLARIS) && !defined(AIX)
+ CARD16 state; // card16 is defined in Xdm.h
+ DPMSInfo( GetXDisplay(),
+ &state,
+ &DPMSEnabled);
+#endif
+ }
+ if( bStart ) // start show
+ {
+ if ( timeout )
+ {
+ nScreenSaversTimeout_ = timeout;
+ XResetScreenSaver( GetXDisplay() );
+ XSetScreenSaver( GetXDisplay(),
+ 0,
+ interval,
+ prefer_blanking,
+ allow_exposures );
+ }
+#if !defined(SOLARIS) && !defined(AIX)
+ if( DPMSEnabled )
+ {
+ if ( DPMSExtensionAvailable )
+ {
+ DPMSGetTimeouts( GetXDisplay(),
+ &dpms_standby_timeout,
+ &dpms_suspend_timeout,
+ &dpms_off_timeout);
+ DPMSSetTimeouts(GetXDisplay(), 0,0,0);
+ }
+ }
+#endif
+ }
+ else
+ {
+ if( nScreenSaversTimeout_ )
+ {
+ XSetScreenSaver( GetXDisplay(),
+ nScreenSaversTimeout_,
+ interval,
+ prefer_blanking,
+ allow_exposures );
+ nScreenSaversTimeout_ = 0;
+ }
+#if !defined(SOLARIS) && !defined(AIX)
+ if ( DPMSEnabled )
+ {
+ if ( DPMSExtensionAvailable )
+ {
+ // restore timeouts
+ DPMSSetTimeouts(GetXDisplay(), dpms_standby_timeout,
+ dpms_suspend_timeout, dpms_off_timeout);
+ }
+ }
+#endif
+ }
+ }
+}
+
+// Pointer
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::SetPointer( PointerStyle ePointerStyle )
+{
+ hCursor_ = pDisplay_->GetPointer( ePointerStyle );
+ XDefineCursor( GetXDisplay(), GetWindow(), hCursor_ );
+
+ if( IsCaptured() || nVisibleFloats > 0 )
+ XChangeActivePointerGrab( GetXDisplay(),
+ PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
+ hCursor_,
+ CurrentTime );
+}
+
+void X11SalFrame::SetPointerPos(long nX, long nY)
+{
+ /* when the application tries to center the mouse in the dialog the
+ * window isn't mapped already. So use coordinates relative to the root window.
+ */
+ unsigned int nWindowLeft = maGeometry.nX + nX;
+ unsigned int nWindowTop = maGeometry.nY + nY;
+
+ XWarpPointer( GetXDisplay(), None, pDisplay_->GetRootWindow( pDisplay_->GetDefaultScreenNumber() ),
+ 0, 0, 0, 0, nWindowLeft, nWindowTop);
+}
+
+// delay handling of extended text input
+#if !defined(__synchronous_extinput__)
+void
+X11SalFrame::PostExtTextEvent (sal_uInt16 nExtTextEventType, void *pExtTextEvent)
+{
+ XLIB_Window nFocusWindow = GetWindow();
+ Atom nEventAtom = GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::SAL_EXTTEXTEVENT );
+
+ XEvent aEvent;
+ aEvent.xclient.type = ClientMessage;
+ aEvent.xclient.serial = 0;
+ aEvent.xclient.send_event = True;
+ aEvent.xclient.display = GetXDisplay();
+ aEvent.xclient.window = nFocusWindow;
+ aEvent.xclient.message_type = nEventAtom;
+ aEvent.xclient.format = 32;
+
+#if SAL_TYPES_SIZEOFLONG > 4
+ aEvent.xclient.data.l[0] = (sal_uInt32)((long)pExtTextEvent & 0xffffffff);
+ aEvent.xclient.data.l[1] = (sal_uInt32)((long)pExtTextEvent >> 32);
+#else
+ aEvent.xclient.data.l[0] = (sal_uInt32)((long)pExtTextEvent);
+ aEvent.xclient.data.l[1] = 0;
+#endif
+ aEvent.xclient.data.l[2] = (sal_uInt32)nExtTextEventType;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+
+ XPutBackEvent( GetXDisplay(), &aEvent );
+}
+
+void
+X11SalFrame::HandleExtTextEvent (XClientMessageEvent *pEvent)
+{
+ #if SAL_TYPES_SIZEOFLONG > 4
+ void* pExtTextEvent = (void*)( (pEvent->data.l[0] & 0xffffffff)
+ | (pEvent->data.l[1] << 32) );
+ #else
+ void* pExtTextEvent = (void*)(pEvent->data.l[0]);
+ #endif
+ sal_uInt16 nExtTextEventType = sal_uInt16(pEvent->data.l[2]);
+
+ CallCallback(nExtTextEventType, pExtTextEvent);
+
+ switch (nExtTextEventType)
+ {
+ case SALEVENT_ENDEXTTEXTINPUT:
+ break;
+
+ case SALEVENT_EXTTEXTINPUT:
+ break;
+
+ default:
+
+ fprintf(stderr, "X11SalFrame::HandleExtTextEvent: invalid extended input\n");
+ }
+}
+#endif /* defined(__synchronous_extinput__) */
+
+// PostEvent
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+sal_Bool X11SalFrame::PostEvent( void *pData )
+{
+ GetDisplay()->SendInternalEvent( this, pData );
+ return sal_True;
+}
+
+// Title
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::SetTitle( const XubString& rTitle )
+{
+ if( ! ( IsChildWindow() || (nStyle_ & SAL_FRAME_STYLE_FLOAT ) ) )
+ {
+ m_aTitle = rTitle;
+ GetDisplay()->getWMAdaptor()->setWMName( this, rTitle );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalFrame::Flush()
+{
+ XFlush( GetDisplay()->GetDisplay() );
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalFrame::Sync()
+{
+ XSync( GetDisplay()->GetDisplay(), False );
+}
+
+// Keyboard
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// -----------------------------------------------------------------------
+
+void X11SalFrame::SetInputContext( SalInputContext* pContext )
+{
+ if (pContext == NULL)
+ return;
+
+ // 1. We should create an input context for this frame
+ // only when SAL_INPUTCONTEXT_TEXT is set.
+
+ if (!(pContext->mnOptions & SAL_INPUTCONTEXT_TEXT))
+ {
+ if( mpInputContext )
+ mpInputContext->Unmap( this );
+ return;
+ }
+
+ // 2. We should use on-the-spot inputstyle
+ // only when SAL_INPUTCONTEXT_EXTTEXTINPUT is set.
+
+ if (mpInputContext == NULL)
+ {
+ I18NStatus& rStatus( I18NStatus::get() );
+ rStatus.setParent( this );
+ mpInputContext = new SalI18N_InputContext( this );
+ if (mpInputContext->UseContext())
+ {
+ mpInputContext->ExtendEventMask( GetShellWindow() );
+ if (pContext->mnOptions & SAL_INPUTCONTEXT_CHANGELANGUAGE)
+ mpInputContext->SetLanguage(pContext->meLanguage);
+ if (mbInputFocus)
+ mpInputContext->SetICFocus( this );
+ }
+ }
+ else
+ mpInputContext->Map( this );
+ return;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalFrame::EndExtTextInput( sal_uInt16 nFlags )
+{
+ if (mpInputContext != NULL)
+ mpInputContext->EndExtTextInput( nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+XubString X11SalFrame::GetKeyName( sal_uInt16 nKeyCode )
+{
+ return GetDisplay()->GetKeyName( nKeyCode );
+}
+
+XubString X11SalFrame::GetSymbolKeyName( const XubString&, sal_uInt16 nKeyCode )
+{
+ return GetKeyName( nKeyCode );
+}
+
+sal_Bool X11SalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& )
+{
+ // not supported yet
+ return sal_False;
+}
+
+LanguageType X11SalFrame::GetInputLanguage()
+{
+ // could be improved by checking unicode ranges of the last input
+ return LANGUAGE_DONTKNOW;
+}
+
+// Settings
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+inline Color getColorFromLong( long nColor )
+{
+ return Color( (nColor & 0xff), (nColor & 0xff00)>>8, (nColor & 0xff0000)>>16);
+}
+
+void X11SalFrame::UpdateSettings( AllSettings& rSettings )
+{
+
+ DtIntegrator* pIntegrator = GetDisplay()->getDtIntegrator();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "DtIntegrator: %d\n", pIntegrator ? pIntegrator->GetDtType() : -1 );
+#endif
+ if( pIntegrator )
+ pIntegrator->GetSystemLook( rSettings );
+}
+
+void X11SalFrame::CaptureMouse( sal_Bool bCapture )
+{
+ nCaptured_ = pDisplay_->CaptureMouse( bCapture ? this : NULL );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetParent( SalFrame* pNewParent )
+{
+ if( mpParent != pNewParent )
+ {
+ if( mpParent )
+ mpParent->maChildren.remove( this );
+
+ mpParent = static_cast<X11SalFrame*>(pNewParent);
+ mpParent->maChildren.push_back( this );
+ if( mpParent->m_nScreen != m_nScreen )
+ createNewWindow( None, mpParent->m_nScreen );
+ GetDisplay()->getWMAdaptor()->changeReferenceFrame( this, mpParent );
+ }
+}
+
+SalFrame* X11SalFrame::GetParent() const
+{
+ return mpParent;
+}
+
+void X11SalFrame::createNewWindow( XLIB_Window aNewParent, int nScreen )
+{
+ bool bWasVisible = bMapped_;
+ if( bWasVisible )
+ Show( sal_False );
+
+ if( nScreen < 0 || nScreen >= GetDisplay()->GetScreenCount() )
+ nScreen = m_nScreen;
+
+ SystemParentData aParentData;
+ aParentData.aWindow = aNewParent;
+ aParentData.bXEmbedSupport = (aNewParent != None && m_bXEmbed); // caution: this is guesswork
+ if( aNewParent == None )
+ {
+ aNewParent = GetDisplay()->GetRootWindow(nScreen);
+ aParentData.aWindow = None;
+ m_bXEmbed = false;
+ }
+ else
+ {
+ // is new parent a root window ?
+ Display* pDisp = GetDisplay()->GetDisplay();
+ int nScreens = GetDisplay()->GetScreenCount();
+ for( int i = 0; i < nScreens; i++ )
+ {
+ if( aNewParent == RootWindow( pDisp, i ) )
+ {
+ nScreen = i;
+ aParentData.aWindow = None;
+ m_bXEmbed = false;
+ break;
+ }
+ }
+ }
+
+ // first deinit frame
+ updateGraphics(true);
+ if( mpInputContext )
+ {
+ mpInputContext->UnsetICFocus( this );
+ mpInputContext->Unmap( this );
+ }
+ if( GetWindow() == hPresentationWindow )
+ {
+ hPresentationWindow = None;
+ doReparentPresentationDialogues( GetDisplay() );
+ }
+ XDestroyWindow( GetXDisplay(), mhWindow );
+ mhWindow = None;
+
+ passOnSaveYourSelf();
+
+ // now init with new parent again
+ if ( aParentData.aWindow != None )
+ Init( nStyle_ | SAL_FRAME_STYLE_PLUG, nScreen, &aParentData );
+ else
+ Init( nStyle_ & ~SAL_FRAME_STYLE_PLUG, nScreen, NULL, true );
+
+ // update graphics if necessary
+ updateGraphics(false);
+
+ if( m_aTitle.Len() )
+ SetTitle( m_aTitle );
+
+ if( mpParent )
+ {
+ if( mpParent->m_nScreen != m_nScreen )
+ SetParent( NULL );
+ else
+ pDisplay_->getWMAdaptor()->changeReferenceFrame( this, mpParent );
+ }
+
+ if( bWasVisible )
+ Show( sal_True );
+
+ std::list< X11SalFrame* > aChildren = maChildren;
+ for( std::list< X11SalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
+ (*it)->createNewWindow( None, m_nScreen );
+
+ // FIXME: SalObjects
+}
+
+bool X11SalFrame::SetPluginParent( SystemParentData* pNewParent )
+{
+ if( pNewParent->nSize >= sizeof(SystemParentData) )
+ m_bXEmbed = pNewParent->aWindow != None && pNewParent->bXEmbedSupport;
+ createNewWindow( pNewParent ? pNewParent->aWindow : None );
+
+ return true;
+}
+
+// Sound
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::Beep( SoundType eSoundType ) // not fully suported
+{
+ switch( eSoundType )
+ {
+ case SOUND_DEFAULT:
+ case SOUND_ERROR:
+ GetDisplay()->Beep();
+ break;
+ default:
+ // Excessive beeping averted
+ break;
+ }
+}
+
+// Event Handling
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static sal_uInt16 sal_GetCode( int state )
+{
+ sal_uInt16 nCode = 0;
+
+ if( state & Button1Mask )
+ nCode |= MOUSE_LEFT;
+ if( state & Button2Mask )
+ nCode |= MOUSE_MIDDLE;
+ if( state & Button3Mask )
+ nCode |= MOUSE_RIGHT;
+
+ if( state & ShiftMask )
+ nCode |= KEY_SHIFT;
+ if( state & ControlMask )
+ nCode |= KEY_MOD1;
+ if( state & Mod1Mask )
+ nCode |= KEY_MOD2;
+
+ // Map Meta/Super modifier to MOD3 on all Unix systems
+ // except Mac OS X
+ if( (state & Mod3Mask) )
+ nCode |= KEY_MOD3;
+
+ return nCode;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+SalFrame::SalPointerState X11SalFrame::GetPointerState()
+{
+ SalPointerState aState;
+ XLIB_Window aRoot, aChild;
+ int rx, ry, wx, wy;
+ unsigned int nMask = 0;
+ XQueryPointer( GetXDisplay(),
+ GetShellWindow(),
+ &aRoot,
+ &aChild,
+ &rx, &ry,
+ &wx, &wy,
+ &nMask
+ );
+
+ aState.maPos = Point(wx, wy);
+ aState.mnState = sal_GetCode( nMask );
+ return aState;
+}
+
+SalFrame::SalIndicatorState X11SalFrame::GetIndicatorState()
+{
+ SalIndicatorState aState;
+ aState.mnState = GetX11SalData()->GetDisplay()->GetIndicatorState();
+ return aState;
+}
+
+void X11SalFrame::SimulateKeyPress( sal_uInt16 nKeyCode )
+{
+ GetX11SalData()->GetDisplay()->SimulateKeyPress(nKeyCode);
+}
+
+long X11SalFrame::HandleMouseEvent( XEvent *pEvent )
+{
+ SalMouseEvent aMouseEvt;
+ sal_uInt16 nEvent = 0;
+ bool bClosePopups = false;
+
+ if( nVisibleFloats && pEvent->type == EnterNotify )
+ return 0;
+
+ // Solaris X86: clicking the right button on a two-button mouse
+ // generates a button2 event not a button3 event
+ if (pDisplay_->GetProperties() & PROPERTY_SUPPORT_3ButtonMouse )
+ {
+ switch (pEvent->type)
+ {
+ case EnterNotify:
+ case LeaveNotify:
+ if ( pEvent->xcrossing.state & Button2Mask )
+ {
+ pEvent->xcrossing.state &= ~Button2Mask;
+ pEvent->xcrossing.state |= Button3Mask;
+ }
+ break;
+
+ case MotionNotify:
+ if ( pEvent->xmotion.state & Button2Mask )
+ {
+ pEvent->xmotion.state &= ~Button2Mask;
+ pEvent->xmotion.state |= Button3Mask;
+ }
+ break;
+
+ default:
+ if ( Button2 == pEvent->xbutton.button )
+ {
+ pEvent->xbutton.state &= ~Button2Mask;
+ pEvent->xbutton.state |= Button3Mask;
+ pEvent->xbutton.button = Button3;
+ }
+ break;
+ }
+ }
+
+
+ if( LeaveNotify == pEvent->type || EnterNotify == pEvent->type )
+ {
+ /*
+ * some WMs (and/or) applications have a passive grab on
+ * mouse buttons (XGrabButton). This leads to enter/leave notifies
+ * with mouse buttons pressed in the state mask before the actual
+ * ButtonPress event gets dispatched. But EnterNotify
+ * is reported in vcl as MouseMove event. Some office code
+ * decides that a pressed button in a MouseMove belongs to
+ * a drag operation which leads to doing things differently.
+ *
+ * ignore Enter/LeaveNotify resulting from grabs so that
+ * help windows do not disappear just after appearing
+ *
+ * hopefully this workaround will not break anything.
+ */
+ if( pEvent->xcrossing.mode == NotifyGrab || pEvent->xcrossing.mode == NotifyUngrab )
+ return 0;
+
+ aMouseEvt.mnX = pEvent->xcrossing.x;
+ aMouseEvt.mnY = pEvent->xcrossing.y;
+ aMouseEvt.mnTime = pEvent->xcrossing.time;
+ aMouseEvt.mnCode = sal_GetCode( pEvent->xcrossing.state );
+ aMouseEvt.mnButton = 0;
+
+ nEvent = LeaveNotify == pEvent->type
+ ? SALEVENT_MOUSELEAVE
+ : SALEVENT_MOUSEMOVE;
+ }
+ else if( pEvent->type == MotionNotify )
+ {
+ aMouseEvt.mnX = pEvent->xmotion.x;
+ aMouseEvt.mnY = pEvent->xmotion.y;
+ aMouseEvt.mnTime = pEvent->xmotion.time;
+ aMouseEvt.mnCode = sal_GetCode( pEvent->xmotion.state );
+
+ aMouseEvt.mnButton = 0;
+
+ nEvent = SALEVENT_MOUSEMOVE;
+ if( nVisibleFloats > 0 && mpParent )
+ {
+ XLIB_Cursor aCursor = mpParent->GetCursor();
+ if( pEvent->xmotion.x >= 0 && pEvent->xmotion.x < (int)maGeometry.nWidth &&
+ pEvent->xmotion.y >= 0 && pEvent->xmotion.y < (int)maGeometry.nHeight )
+ aCursor = None;
+
+ XChangeActivePointerGrab( GetXDisplay(),
+ PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
+ aCursor,
+ CurrentTime );
+ }
+ }
+ else
+ {
+ // let mouse events reach the correct window
+ if( nVisibleFloats < 1 )
+ {
+ if( ! (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ XUngrabPointer( GetXDisplay(), CurrentTime );
+ }
+ else if( pEvent->type == ButtonPress )
+ {
+ // see if the user clicks outside all of the floats
+ // if yes release the grab
+ bool bInside = false;
+ const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it);
+ if( pFrame->IsFloatGrabWindow() &&
+ pFrame->bMapped_ &&
+ pEvent->xbutton.x_root >= pFrame->maGeometry.nX &&
+ pEvent->xbutton.x_root < pFrame->maGeometry.nX + (int)pFrame->maGeometry.nWidth &&
+ pEvent->xbutton.y_root >= pFrame->maGeometry.nY &&
+ pEvent->xbutton.y_root < pFrame->maGeometry.nY + (int)pFrame->maGeometry.nHeight )
+ {
+ bInside = true;
+ break;
+ }
+ }
+ if( ! bInside )
+ {
+ // need not take care of the XUngrabPointer in Show( sal_False )
+ // because XUngrabPointer does not produce errors if pointer
+ // is not grabbed
+ XUngrabPointer( GetXDisplay(), CurrentTime );
+ bClosePopups = true;
+
+ /* #i15246# only close popups if pointer is outside all our frames
+ * cannot use our own geometry data here because stacking
+ * is unknown (the above case implicitly assumes
+ * that floats are on top which should be true)
+ */
+ XLIB_Window aRoot, aChild;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask_return;
+ if( XQueryPointer( GetXDisplay(),
+ GetDisplay()->GetRootWindow( m_nScreen ),
+ &aRoot, &aChild,
+ &root_x, &root_y,
+ &win_x, &win_y,
+ &mask_return )
+ && aChild // pointer may not be in any child
+ )
+ {
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it);
+ if( ! pFrame->IsFloatGrabWindow()
+ && ( pFrame->GetWindow() == aChild ||
+ pFrame->GetShellWindow() == aChild ||
+ pFrame->GetStackingWindow() == aChild )
+ )
+ {
+ // #i63638# check that pointer is inside window, not
+ // only inside stacking window
+ if( root_x >= pFrame->maGeometry.nX && root_x < sal::static_int_cast< int >(pFrame->maGeometry.nX+pFrame->maGeometry.nWidth) &&
+ root_y >= pFrame->maGeometry.nY && root_y < sal::static_int_cast< int >(pFrame->maGeometry.nX+pFrame->maGeometry.nHeight) )
+ {
+ bClosePopups = false;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if( m_bXEmbed && pEvent->xbutton.button == Button1 )
+ askForXEmbedFocus( pEvent->xbutton.time );
+
+ if( pEvent->xbutton.button == Button1 ||
+ pEvent->xbutton.button == Button2 ||
+ pEvent->xbutton.button == Button3 )
+ {
+ aMouseEvt.mnX = pEvent->xbutton.x;
+ aMouseEvt.mnY = pEvent->xbutton.y;
+ aMouseEvt.mnTime = pEvent->xbutton.time;
+ aMouseEvt.mnCode = sal_GetCode( pEvent->xbutton.state );
+
+ if( Button1 == pEvent->xbutton.button )
+ aMouseEvt.mnButton = MOUSE_LEFT;
+ else if( Button2 == pEvent->xbutton.button )
+ aMouseEvt.mnButton = MOUSE_MIDDLE;
+ else if( Button3 == pEvent->xbutton.button )
+ aMouseEvt.mnButton = MOUSE_RIGHT;
+
+ nEvent = ButtonPress == pEvent->type
+ ? SALEVENT_MOUSEBUTTONDOWN
+ : SALEVENT_MOUSEBUTTONUP;
+ }
+ else if( pEvent->xbutton.button == Button4 ||
+ pEvent->xbutton.button == Button5 ||
+ pEvent->xbutton.button == Button6 ||
+ pEvent->xbutton.button == Button7 )
+ {
+ const bool bIncrement(
+ pEvent->xbutton.button == Button4 ||
+ pEvent->xbutton.button == Button6 );
+ const bool bHoriz(
+ pEvent->xbutton.button == Button6 ||
+ pEvent->xbutton.button == Button7 );
+
+ if( pEvent->type == ButtonRelease )
+ return 0;
+
+ static sal_uLong nLines = 0;
+ if( ! nLines )
+ {
+ char* pEnv = getenv( "SAL_WHEELLINES" );
+ nLines = pEnv ? atoi( pEnv ) : 3;
+ if( nLines > 10 )
+ nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
+ }
+
+ SalWheelMouseEvent aWheelEvt;
+ aWheelEvt.mnTime = pEvent->xbutton.time;
+ aWheelEvt.mnX = pEvent->xbutton.x;
+ aWheelEvt.mnY = pEvent->xbutton.y;
+ aWheelEvt.mnDelta = bIncrement ? 120 : -120;
+ aWheelEvt.mnNotchDelta = bIncrement ? 1 : -1;
+ aWheelEvt.mnScrollLines = nLines;
+ aWheelEvt.mnCode = sal_GetCode( pEvent->xbutton.state );
+ aWheelEvt.mbHorz = bHoriz;
+
+ nEvent = SALEVENT_WHEELMOUSE;
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aWheelEvt.mnX = nWidth_-1-aWheelEvt.mnX;
+ return CallCallback( nEvent, &aWheelEvt );
+ }
+ }
+
+ int nRet = 0;
+ if( nEvent == SALEVENT_MOUSELEAVE
+ || ( aMouseEvt.mnX < nWidth_ && aMouseEvt.mnX > -1 &&
+ aMouseEvt.mnY < nHeight_ && aMouseEvt.mnY > -1 )
+ || pDisplay_->MouseCaptured( this )
+ )
+ {
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aMouseEvt.mnX = nWidth_-1-aMouseEvt.mnX;
+ nRet = CallCallback( nEvent, &aMouseEvt );
+ }
+
+ if( bClosePopups )
+ {
+ /* #108213# close popups after dispatching the event outside the popup;
+ * applications do weird things.
+ */
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maWinData.mpFirstFloat )
+ {
+ static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
+ if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) && !(pEnv && *pEnv) )
+ pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ }
+ }
+
+ return nRet;
+}
+
+// F10 means either KEY_F10 or KEY_MENU, which has to be decided
+// in the independent part.
+struct KeyAlternate
+{
+ sal_uInt16 nKeyCode;
+ sal_Unicode nCharCode;
+ KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
+ KeyAlternate( sal_uInt16 nKey, sal_Unicode nChar = 0 ) : nKeyCode( nKey ), nCharCode( nChar ) {}
+};
+
+inline KeyAlternate
+GetAlternateKeyCode( const sal_uInt16 nKeyCode )
+{
+ KeyAlternate aAlternate;
+
+ switch( nKeyCode )
+ {
+ case KEY_F10: aAlternate = KeyAlternate( KEY_MENU );break;
+ case KEY_F24: aAlternate = KeyAlternate( KEY_SUBTRACT, '-' );break;
+ }
+
+ return aAlternate;
+}
+
+void X11SalFrame::beginUnicodeSequence()
+{
+ rtl::OUString& rSeq( GetX11SalData()->GetUnicodeAccumulator() );
+ DeletionListener aDeleteWatch( this );
+
+ if( rSeq.getLength() )
+ endUnicodeSequence();
+
+ rSeq = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "u" ) );
+
+ if( ! aDeleteWatch.isDeleted() )
+ {
+ sal_uInt16 nTextAttr = SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
+ SalExtTextInputEvent aEv;
+ aEv.mnTime = 0;
+ aEv.maText = rSeq;
+ aEv.mpTextAttr = &nTextAttr;
+ aEv.mnCursorPos = 0;
+ aEv.mnDeltaStart = 0;
+ aEv.mnCursorFlags = 0;
+ aEv.mbOnlyCursor = sal_False;
+
+ CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&aEv);
+ }
+}
+
+bool X11SalFrame::appendUnicodeSequence( sal_Unicode c )
+{
+ bool bRet = false;
+ rtl::OUString& rSeq( GetX11SalData()->GetUnicodeAccumulator() );
+ if( rSeq.getLength() > 0 )
+ {
+ // range check
+ if( (c >= sal_Unicode('0') && c <= sal_Unicode('9')) ||
+ (c >= sal_Unicode('a') && c <= sal_Unicode('f')) ||
+ (c >= sal_Unicode('A') && c <= sal_Unicode('F')) )
+ {
+ rtl::OUStringBuffer aBuf( rSeq.getLength() + 1 );
+ aBuf.append( rSeq );
+ aBuf.append( c );
+ rSeq = aBuf.makeStringAndClear();
+ std::vector<sal_uInt16> attribs( rSeq.getLength(), SAL_EXTTEXTINPUT_ATTR_UNDERLINE );
+
+ SalExtTextInputEvent aEv;
+ aEv.mnTime = 0;
+ aEv.maText = rSeq;
+ aEv.mpTextAttr = &attribs[0];
+ aEv.mnCursorPos = 0;
+ aEv.mnDeltaStart = 0;
+ aEv.mnCursorFlags = 0;
+ aEv.mbOnlyCursor = sal_False;
+
+ CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&aEv);
+ bRet = true;
+ }
+ else
+ bRet = endUnicodeSequence();
+ }
+ else
+ endUnicodeSequence();
+ return bRet;
+}
+
+bool X11SalFrame::endUnicodeSequence()
+{
+ rtl::OUString& rSeq( GetX11SalData()->GetUnicodeAccumulator() );
+
+ DeletionListener aDeleteWatch( this );
+ if( rSeq.getLength() > 1 && rSeq.getLength() < 6 )
+ {
+ // cut the "u"
+ rtl::OUString aNumbers( rSeq.copy( 1 ) );
+ sal_Int32 nValue = aNumbers.toInt32( 16 );
+ if( nValue >= 32 )
+ {
+ sal_uInt16 nTextAttr = SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
+ SalExtTextInputEvent aEv;
+ aEv.mnTime = 0;
+ aEv.maText = rtl::OUString( sal_Unicode(nValue) );
+ aEv.mpTextAttr = &nTextAttr;
+ aEv.mnCursorPos = 0;
+ aEv.mnDeltaStart = 0;
+ aEv.mnCursorFlags = 0;
+ aEv.mbOnlyCursor = sal_False;
+ CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&aEv);
+ }
+ }
+ bool bWasInput = rSeq.getLength() > 0;
+ rSeq = rtl::OUString();
+ if( bWasInput && ! aDeleteWatch.isDeleted() )
+ CallCallback(SALEVENT_ENDEXTTEXTINPUT, NULL);
+ return bWasInput;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleKeyEvent( XKeyEvent *pEvent )
+{
+ KeySym nKeySym;
+ KeySym nUnmodifiedKeySym;
+ int nLen = 2048;
+ unsigned char *pPrintable = (unsigned char*)alloca( nLen );
+
+ // singlebyte code composed by input method, the new default
+ if (mpInputContext != NULL && mpInputContext->UseContext())
+ {
+ // returns a keysym as well as the pPrintable (in system encoding)
+ // printable may be empty.
+ Status nStatus;
+ nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen,
+ &nUnmodifiedKeySym,
+ &nStatus, mpInputContext->GetContext() );
+ if ( nStatus == XBufferOverflow )
+ {
+ nLen *= 2;
+ pPrintable = (unsigned char*)alloca( nLen );
+ nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen,
+ &nUnmodifiedKeySym,
+ &nStatus, mpInputContext->GetContext() );
+ }
+ }
+ else
+ {
+ // fallback, this should never ever be called
+ Status nStatus = 0;
+ nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen, &nUnmodifiedKeySym, &nStatus );
+ }
+
+ SalKeyEvent aKeyEvt;
+ sal_uInt16 nKeyCode;
+ sal_uInt16 nModCode = 0;
+ char aDummy;
+
+ if( pEvent->state & ShiftMask )
+ nModCode |= KEY_SHIFT;
+ if( pEvent->state & ControlMask )
+ nModCode |= KEY_MOD1;
+ if( pEvent->state & Mod1Mask )
+ nModCode |= KEY_MOD2;
+
+ if( nModCode != (KEY_SHIFT|KEY_MOD1) )
+ endUnicodeSequence();
+
+ if( nKeySym == XK_Shift_L || nKeySym == XK_Shift_R
+ || nKeySym == XK_Control_L || nKeySym == XK_Control_R
+ || nKeySym == XK_Alt_L || nKeySym == XK_Alt_R
+ || nKeySym == XK_Meta_L || nKeySym == XK_Meta_R
+ || nKeySym == XK_Super_L || nKeySym == XK_Super_R )
+ {
+ SalKeyModEvent aModEvt;
+ aModEvt.mnModKeyCode = 0;
+ if( pEvent->type == XLIB_KeyPress && mnExtKeyMod == 0 )
+ mbSendExtKeyModChange = true;
+ else if( pEvent->type == KeyRelease && mbSendExtKeyModChange )
+ {
+ aModEvt.mnModKeyCode = mnExtKeyMod;
+ mnExtKeyMod = 0;
+ }
+
+ // pressing just the ctrl key leads to a keysym of XK_Control but
+ // the event state does not contain ControlMask. In the release
+ // event its the other way round: it does contain the Control mask.
+ // The modifier mode therefore has to be adapted manually.
+ sal_uInt16 nExtModMask = 0;
+ sal_uInt16 nModMask = 0;
+ switch( nKeySym )
+ {
+ case XK_Control_L:
+ nExtModMask = MODKEY_LMOD1;
+ nModMask = KEY_MOD1;
+ break;
+ case XK_Control_R:
+ nExtModMask = MODKEY_RMOD1;
+ nModMask = KEY_MOD1;
+ break;
+ case XK_Alt_L:
+ nExtModMask = MODKEY_LMOD2;
+ nModMask = KEY_MOD2;
+ break;
+ case XK_Alt_R:
+ nExtModMask = MODKEY_RMOD2;
+ nModMask = KEY_MOD2;
+ break;
+ case XK_Shift_L:
+ nExtModMask = MODKEY_LSHIFT;
+ nModMask = KEY_SHIFT;
+ break;
+ case XK_Shift_R:
+ nExtModMask = MODKEY_RSHIFT;
+ nModMask = KEY_SHIFT;
+ break;
+ // Map Meta/Super keys to MOD3 modifier on all Unix systems
+ // except Mac OS X
+ case XK_Meta_L:
+ case XK_Super_L:
+ nExtModMask = MODKEY_LMOD3;
+ nModMask = KEY_MOD3;
+ break;
+ case XK_Meta_R:
+ case XK_Super_R:
+ nExtModMask = MODKEY_RMOD3;
+ nModMask = KEY_MOD3;
+ break;
+ }
+ if( pEvent->type == KeyRelease )
+ {
+ nModCode &= ~nModMask;
+ mnExtKeyMod &= ~nExtModMask;
+ }
+ else
+ {
+ nModCode |= nModMask;
+ mnExtKeyMod |= nExtModMask;
+ }
+
+ aModEvt.mnCode = nModCode;
+ aModEvt.mnTime = pEvent->time;
+
+ int nRet = CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
+
+ return nRet;
+ }
+
+ mbSendExtKeyModChange = false;
+
+ // try to figure out the vcl code for the keysym
+ // #i52338# use the unmodified KeySym if there is none for the real KeySym
+ // because the independent part has only keycodes for unshifted keys
+ nKeyCode = pDisplay_->GetKeyCode( nKeySym, &aDummy );
+ if( nKeyCode == 0 )
+ nKeyCode = pDisplay_->GetKeyCode( nUnmodifiedKeySym, &aDummy );
+
+ // try to figure out a printable if XmbLookupString returns only a keysym
+ // and NOT a printable. Do not store it in pPrintable[0] since it is expected to
+ // be in system encoding, not unicode.
+ // #i8988##, if KeySym and printable look equally promising then prefer KeySym
+ // the printable is bound to the encoding so the KeySym might contain more
+ // information (in et_EE locale: "Compose + Z + <" delivers "," in printable and
+ // (the desired) Zcaron in KeySym
+ sal_Unicode nKeyString = 0x0;
+ if ( (nLen == 0)
+ || ((nLen == 1) && (nKeySym > 0)) )
+ nKeyString = KeysymToUnicode (nKeySym);
+ // if we have nothing we give up
+ if( !nKeyCode && !nLen && !nKeyString)
+ return 0;
+
+ DeletionListener aDeleteWatch( this );
+
+ if( nModCode == (KEY_SHIFT | KEY_MOD1) && pEvent->type == XLIB_KeyPress )
+ {
+ sal_uInt16 nSeqKeyCode = pDisplay_->GetKeyCode( nUnmodifiedKeySym, &aDummy );
+ if( nSeqKeyCode == KEY_U )
+ {
+ beginUnicodeSequence();
+ return 1;
+ }
+ else if( nSeqKeyCode >= KEY_0 && nSeqKeyCode <= KEY_9 )
+ {
+ if( appendUnicodeSequence( sal_Unicode( '0' ) + sal_Unicode(nSeqKeyCode - KEY_0) ) )
+ return 1;
+ }
+ else if( nSeqKeyCode >= KEY_A && nSeqKeyCode <= KEY_F )
+ {
+ if( appendUnicodeSequence( sal_Unicode( 'a' ) + sal_Unicode(nSeqKeyCode - KEY_A) ) )
+ return 1;
+ }
+ else
+ endUnicodeSequence();
+ }
+
+ if( aDeleteWatch.isDeleted() )
+ return 0;
+
+ rtl_TextEncoding nEncoding;
+
+ if (mpInputContext != NULL && mpInputContext->IsMultiLingual() )
+ nEncoding = RTL_TEXTENCODING_UTF8;
+ else
+ nEncoding = osl_getThreadTextEncoding();
+
+ sal_Unicode *pBuffer;
+ sal_Unicode *pString;
+ sal_Size nBufferSize = nLen * 2;
+ sal_Size nSize;
+ pBuffer = (sal_Unicode*) malloc( nBufferSize + 2 );
+ pBuffer[ 0 ] = 0;
+
+ if (nKeyString != 0)
+ {
+ pString = &nKeyString;
+ nSize = 1;
+ }
+ else
+ if (nLen > 0 && nEncoding != RTL_TEXTENCODING_UNICODE)
+ {
+ // create text converter
+ rtl_TextToUnicodeConverter aConverter =
+ rtl_createTextToUnicodeConverter( nEncoding );
+ rtl_TextToUnicodeContext aContext =
+ rtl_createTextToUnicodeContext( aConverter );
+
+ sal_uInt32 nConversionInfo;
+ sal_Size nConvertedChars;
+
+ // convert to single byte text stream
+ nSize = rtl_convertTextToUnicode(
+ aConverter, aContext,
+ (char*)pPrintable, nLen,
+ pBuffer, nBufferSize,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE,
+ &nConversionInfo, &nConvertedChars );
+
+ // destroy converter
+ rtl_destroyTextToUnicodeContext( aConverter, aContext );
+ rtl_destroyTextToUnicodeConverter( aConverter );
+
+ pString = pBuffer;
+ }
+ else
+ if (nLen > 0 /* nEncoding == RTL_TEXTENCODING_UNICODE */)
+ {
+ pString = (sal_Unicode*)pPrintable;
+ nSize = nLen;
+ }
+ else
+ {
+ pString = pBuffer;
+ nSize = 0;
+ }
+
+ if ( mpInputContext != NULL
+ && mpInputContext->UseContext()
+ && KeyRelease != pEvent->type
+ && ( (nSize > 1)
+ || (nSize > 0 && mpInputContext->IsPreeditMode())) )
+ {
+ mpInputContext->CommitKeyEvent(pString, nSize);
+ }
+ else
+ // normal single character keyinput
+ {
+ aKeyEvt.mnCode = nKeyCode | nModCode;
+ aKeyEvt.mnRepeat = 0;
+ aKeyEvt.mnTime = pEvent->time;
+ aKeyEvt.mnCharCode = pString[ 0 ];
+
+ if( KeyRelease == pEvent->type )
+ {
+ CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ }
+ else
+ {
+ if ( ! CallCallback(SALEVENT_KEYINPUT, &aKeyEvt) )
+ {
+ // independent layer doesnt want to handle key-event, so check
+ // whether the keycode may have an alternate meaning
+ KeyAlternate aAlternate = GetAlternateKeyCode( nKeyCode );
+ if ( aAlternate.nKeyCode != 0 )
+ {
+ aKeyEvt.mnCode = aAlternate.nKeyCode | nModCode;
+ if( aAlternate.nCharCode )
+ aKeyEvt.mnCharCode = aAlternate.nCharCode;
+ CallCallback(SALEVENT_KEYINPUT, &aKeyEvt);
+ }
+ }
+ }
+ }
+
+ //
+ // update the spot location for PreeditPosition IME style
+ //
+ if (! aDeleteWatch.isDeleted())
+ {
+ if (mpInputContext != NULL && mpInputContext->UseContext())
+ mpInputContext->UpdateSpotLocation();
+ }
+
+ free (pBuffer);
+ return True;
+}
+
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleFocusEvent( XFocusChangeEvent *pEvent )
+{
+ // ReflectionX in Windows mode changes focus while mouse is grabbed
+ if( nVisibleFloats > 0 && GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii( "ReflectionX Windows" ) )
+ return 1;
+
+ /* ignore focusout resulting from keyboard grabs
+ * we do not grab it and are not interested when
+ * someone else does CDE e.g. does a XGrabKey on arrow keys
+ * handle focus events with mode NotifyWhileGrabbed
+ * because with CDE alt-tab focus changing we do not get
+ * normal focus events
+ * cast focus event to the input context, otherwise the
+ * status window does not follow the application frame
+ */
+
+ if ( mpInputContext != NULL )
+ {
+ if( FocusIn == pEvent->type )
+ mpInputContext->SetICFocus( this );
+ else
+ {
+ /*
+ * do not unset the IC focuse here because would kill
+ * a lookup choice windows that might have the focus now
+ * mpInputContext->UnsetICFocus( this );
+ */
+ I18NStatus::get().show( false, I18NStatus::focus );
+ }
+ }
+
+
+ if ( pEvent->mode == NotifyNormal || pEvent->mode == NotifyWhileGrabbed ||
+ ( ( nStyle_ & SAL_FRAME_STYLE_PLUG ) && pEvent->window == GetShellWindow() )
+ )
+ {
+ if( hPresentationWindow != None && hPresentationWindow != GetShellWindow() )
+ return 0;
+
+ if( FocusIn == pEvent->type )
+ {
+ GetSalData()->m_pInstance->updatePrinterUpdate();
+ mbInputFocus = True;
+ ImplSVData* pSVData = ImplGetSVData();
+
+
+
+ long nRet = CallCallback( SALEVENT_GETFOCUS, 0 );
+ if ((mpParent != NULL && nStyle_ == 0)
+ && pSVData->maWinData.mpFirstFloat )
+ {
+ sal_uLong nMode = pSVData->maWinData.mpFirstFloat->GetPopupModeFlags();
+ pSVData->maWinData.mpFirstFloat->SetPopupModeFlags(
+ nMode & ~(FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE));
+ }
+ return nRet;
+ }
+ else
+ {
+ mbInputFocus = False;
+ mbSendExtKeyModChange = false;
+ mnExtKeyMod = 0;
+ return CallCallback( SALEVENT_LOSEFOCUS, 0 );
+ }
+ }
+
+ return 0;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+long X11SalFrame::HandleExposeEvent( XEvent *pEvent )
+{
+ XRectangle aRect = { 0, 0, 0, 0 };
+ sal_uInt16 nCount = 0;
+
+ if( pEvent->type == Expose )
+ {
+ aRect.x = pEvent->xexpose.x;
+ aRect.y = pEvent->xexpose.y;
+ aRect.width = pEvent->xexpose.width;
+ aRect.height = pEvent->xexpose.height;
+ nCount = pEvent->xexpose.count;
+ }
+ else if( pEvent->type == GraphicsExpose )
+ {
+ aRect.x = pEvent->xgraphicsexpose.x;
+ aRect.y = pEvent->xgraphicsexpose.y;
+ aRect.width = pEvent->xgraphicsexpose.width;
+ aRect.height = pEvent->xgraphicsexpose.height;
+ nCount = pEvent->xgraphicsexpose.count;
+ }
+
+ if( IsOverrideRedirect() && mbFullScreen &&
+ aPresentationReparentList.begin() == aPresentationReparentList.end() )
+ // we are in fullscreen mode -> override redirect
+ // focus is possibly lost, so reget it
+ XSetInputFocus( GetXDisplay(), GetShellWindow(), RevertToNone, CurrentTime );
+
+ // width and height are extents, so they are of by one for rectangle
+ maPaintRegion.Union( Rectangle( Point(aRect.x, aRect.y), Size(aRect.width+1, aRect.height+1) ) );
+
+ if( nCount )
+ // wait for last expose rectangle, do not wait for resize timer
+ // if a completed graphics expose sequence is available
+ return 1;
+
+ SalPaintEvent aPEvt( maPaintRegion.Left(), maPaintRegion.Top(), maPaintRegion.GetWidth(), maPaintRegion.GetHeight() );
+
+ CallCallback( SALEVENT_PAINT, &aPEvt );
+ maPaintRegion = Rectangle();
+
+ return 1;
+}
+
+void X11SalFrame::RestackChildren( XLIB_Window* pTopLevelWindows, int nTopLevelWindows )
+{
+ if( maChildren.begin() != maChildren.end() )
+ {
+ int nWindow = nTopLevelWindows;
+ while( nWindow-- )
+ if( pTopLevelWindows[nWindow] == GetStackingWindow() )
+ break;
+ if( nWindow < 0 )
+ return;
+
+ std::list< X11SalFrame* >::const_iterator it;
+ for( it = maChildren.begin(); it != maChildren.end(); ++it )
+ {
+ X11SalFrame* pData = *it;
+ if( pData->bMapped_ )
+ {
+ int nChild = nWindow;
+ while( nChild-- )
+ {
+ if( pTopLevelWindows[nChild] == pData->GetStackingWindow() )
+ {
+ // if a child is behind its parent, place it above the
+ // parent (for insane WMs like Dtwm and olwm)
+ XWindowChanges aCfg;
+ aCfg.sibling = GetStackingWindow();
+ aCfg.stack_mode = Above;
+ XConfigureWindow( GetXDisplay(), pData->GetStackingWindow(), CWSibling|CWStackMode, &aCfg );
+ break;
+ }
+ }
+ }
+ }
+ for( it = maChildren.begin(); it != maChildren.end(); ++it )
+ {
+ X11SalFrame* pData = *it;
+ pData->RestackChildren( pTopLevelWindows, nTopLevelWindows );
+ }
+ }
+}
+
+void X11SalFrame::RestackChildren()
+{
+ if( ! GetDisplay()->getWMAdaptor()->isTransientBehaviourAsExpected()
+ && maChildren.begin() != maChildren.end() )
+ {
+ XLIB_Window aRoot, aParent, *pChildren = NULL;
+ unsigned int nChildren;
+ if( XQueryTree( GetXDisplay(),
+ GetDisplay()->GetRootWindow( m_nScreen ),
+ &aRoot,
+ &aParent,
+ &pChildren,
+ &nChildren ) )
+ {
+ RestackChildren( pChildren, nChildren );
+ XFree( pChildren );
+ }
+ }
+}
+
+static Bool size_event_predicate( Display*, XEvent* event, XPointer arg )
+{
+ if( event->type != ConfigureNotify )
+ return False;
+ X11SalFrame* frame = reinterpret_cast< X11SalFrame* >( arg );
+ XConfigureEvent* pEvent = &event->xconfigure;
+ if( pEvent->window != frame->GetShellWindow()
+ && pEvent->window != frame->GetWindow()
+ && pEvent->window != frame->GetForeignParent()
+ && pEvent->window != frame->GetStackingWindow())
+ { // ignored at top of HandleSizeEvent()
+ return False;
+ }
+ if( pEvent->window == frame->GetStackingWindow())
+ return False; // filtered later in HandleSizeEvent()
+ // at this point we know that there is another similar event in the queue
+ frame->setPendingSizeEvent();
+ return False; // but do not process the new event out of order
+}
+
+void X11SalFrame::setPendingSizeEvent()
+{
+ mPendingSizeEvent = true;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleSizeEvent( XConfigureEvent *pEvent )
+{
+ // NOTE: if you add more tests in this function, make sure to update size_event_predicate()
+ // so that it finds exactly the same events
+
+ if ( pEvent->window != GetShellWindow()
+ && pEvent->window != GetWindow()
+ && pEvent->window != GetForeignParent()
+ && pEvent->window != GetStackingWindow()
+ )
+ {
+ // could be as well a sys-child window (aka SalObject)
+ return 1;
+ }
+
+
+ if( ( nStyle_ & SAL_FRAME_STYLE_PLUG ) && pEvent->window == GetShellWindow() )
+ {
+ // just update the children's positions
+ RestackChildren();
+ return 1;
+ }
+
+ if( pEvent->window == GetForeignParent() )
+ XResizeWindow( GetXDisplay(),
+ GetWindow(),
+ pEvent->width,
+ pEvent->height );
+
+ XLIB_Window hDummy;
+ XTranslateCoordinates( GetXDisplay(),
+ GetWindow(),
+ pDisplay_->GetRootWindow( pDisplay_->GetDefaultScreenNumber() ),
+ 0, 0,
+ &pEvent->x, &pEvent->y,
+ &hDummy );
+
+ if( pEvent->window == GetStackingWindow() )
+ {
+ if( maGeometry.nX != pEvent->x || maGeometry.nY != pEvent->y )
+ {
+ maGeometry.nX = pEvent->x;
+ maGeometry.nY = pEvent->y;
+ CallCallback( SALEVENT_MOVE, NULL );
+ }
+ return 1;
+ }
+
+ // check size hints in first time SalFrame::Show
+ if( SHOWSTATE_UNKNOWN == nShowState_ && bMapped_ )
+ nShowState_ = SHOWSTATE_NORMAL;
+
+ // Avoid a race condition where resizing this window to one size and shortly after that
+ // to another size generates first size event with the old size and only after that
+ // with the new size, temporarily making us think the old size is valid (bnc#674806).
+ // So if there is another size event for this window pending, ignore this one.
+ mPendingSizeEvent = false;
+ XEvent dummy;
+ XCheckIfEvent( GetXDisplay(), &dummy, size_event_predicate, reinterpret_cast< XPointer >( this ));
+ if( mPendingSizeEvent )
+ return 1;
+
+ nWidth_ = pEvent->width;
+ nHeight_ = pEvent->height;
+
+ bool bMoved = ( pEvent->x != maGeometry.nX || pEvent->y != maGeometry.nY );
+ bool bSized = ( pEvent->width != (int)maGeometry.nWidth || pEvent->height != (int)maGeometry.nHeight );
+
+ maGeometry.nX = pEvent->x;
+ maGeometry.nY = pEvent->y;
+ maGeometry.nWidth = pEvent->width;
+ maGeometry.nHeight = pEvent->height;
+ updateScreenNumber();
+
+ // update children's position
+ RestackChildren();
+
+ if( bSized && ! bMoved )
+ CallCallback( SALEVENT_RESIZE, NULL );
+ else if( bMoved && ! bSized )
+ CallCallback( SALEVENT_MOVE, NULL );
+ else if( bMoved && bSized )
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+
+ return 1;
+}
+
+IMPL_LINK( X11SalFrame, HandleAlwaysOnTopRaise, void*, EMPTYARG )
+{
+ if( bMapped_ )
+ ToTop( 0 );
+ return 0;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleReparentEvent( XReparentEvent *pEvent )
+{
+ Display *pDisplay = pEvent->display;
+ XLIB_Window hWM_Parent;
+ XLIB_Window hRoot, *Children, hDummy;
+ unsigned int nChildren;
+ sal_Bool bNone = pDisplay_->GetProperties()
+ & PROPERTY_SUPPORT_WM_Parent_Pixmap_None;
+ sal_Bool bAccessParentWindow = ! (pDisplay_->GetProperties()
+ & PROPERTY_FEATURE_TrustedSolaris);
+
+ static const char* pDisableStackingCheck = getenv( "SAL_DISABLE_STACKING_CHECK" );
+
+ GetDisplay()->GetXLib()->PushXErrorLevel( true );
+
+ /*
+ * don't rely on the new parent from the event.
+ * the event may be "out of date", that is the window manager
+ * window may not exist anymore. This can happen if someone
+ * shows a frame and hides it again quickly (not that that would
+ * be very sensible)
+ */
+ hWM_Parent = GetShellWindow();
+ do
+ {
+ Children = NULL;
+ XQueryTree( pDisplay,
+ hWM_Parent,
+ &hRoot,
+ &hDummy,
+ &Children,
+ &nChildren );
+ if( GetDisplay()->GetXLib()->HasXErrorOccurred() )
+ {
+ hWM_Parent = GetShellWindow();
+ break;
+ }
+ /* this sometimes happens if a Show(sal_True) is
+ * immediately followed by Show(sal_False) (which is braindead anyway)
+ */
+ if( hDummy == hWM_Parent )
+ hDummy = hRoot;
+ if( hDummy != hRoot )
+ {
+ hWM_Parent = hDummy;
+ if( bAccessParentWindow && bNone )
+ XSetWindowBackgroundPixmap( pDisplay, hWM_Parent, None );
+ }
+ if( Children )
+ XFree( Children );
+ } while( hDummy != hRoot );
+
+ if( GetStackingWindow() == None
+ && hWM_Parent != hPresentationWindow
+ && hWM_Parent != GetShellWindow()
+ && ( ! pDisableStackingCheck || ! *pDisableStackingCheck )
+ )
+ {
+ mhStackingWindow = hWM_Parent;
+ if (bAccessParentWindow)
+ XSelectInput( pDisplay, GetStackingWindow(), StructureNotifyMask );
+ }
+
+ if( hWM_Parent == pDisplay_->GetRootWindow( pDisplay_->GetDefaultScreenNumber() )
+ || hWM_Parent == GetForeignParent()
+ || pEvent->parent == pDisplay_->GetRootWindow( pDisplay_->GetDefaultScreenNumber() )
+ || ( nStyle_ & SAL_FRAME_STYLE_FLOAT ) )
+ {
+ // Reparenting before Destroy
+ aPresentationReparentList.remove( GetStackingWindow() );
+ mhStackingWindow = None;
+ GetDisplay()->GetXLib()->PopXErrorLevel();
+ return 0;
+ }
+
+ /*
+ * evil hack to show decorated windows on top
+ * of override redirect presentation windows:
+ * reparent the window manager window to the presentation window
+ * does not work with non-reparenting WMs
+ * in future this should not be necessary anymore with
+ * _NET_WM_STATE_FULLSCREEN available
+ */
+ if( hPresentationWindow != None
+ && hPresentationWindow != GetWindow()
+ && GetStackingWindow() != None
+ && GetStackingWindow() != GetDisplay()->GetRootWindow( m_nScreen )
+ )
+ {
+ int x = 0, y = 0;
+ XLIB_Window aChild;
+ XTranslateCoordinates( GetXDisplay(),
+ GetStackingWindow(),
+ GetDisplay()->GetRootWindow( m_nScreen ),
+ 0, 0,
+ &x, &y,
+ &aChild
+ );
+ XReparentWindow( GetXDisplay(),
+ GetStackingWindow(),
+ hPresentationWindow,
+ x, y
+ );
+ aPresentationReparentList.push_back( GetStackingWindow() );
+ }
+
+ int nLeft = 0, nTop = 0;
+ XTranslateCoordinates( GetXDisplay(),
+ GetShellWindow(),
+ hWM_Parent,
+ 0, 0,
+ &nLeft,
+ &nTop,
+ &hDummy );
+ maGeometry.nLeftDecoration = nLeft > 0 ? nLeft-1 : 0;
+ maGeometry.nTopDecoration = nTop > 0 ? nTop-1 : 0;
+
+ /*
+ * decorations are not symmetric,
+ * so need real geometries here
+ * (this will fail with virtual roots ?)
+ */
+ GetDisplay()->GetXLib()->ResetXErrorOccurred();
+ int xp, yp, x, y;
+ unsigned int wp, w, hp, h, bw, d;
+ XGetGeometry( GetXDisplay(),
+ GetShellWindow(),
+ &hRoot,
+ &x, &y, &w, &h, &bw, &d );
+ XGetGeometry( GetXDisplay(),
+ hWM_Parent,
+ &hRoot,
+ &xp, &yp, &wp, &hp, &bw, &d );
+ bool bResized = false;
+ if( ! GetDisplay()->GetXLib()->HasXErrorOccurred() )
+ {
+ maGeometry.nRightDecoration = wp - w - maGeometry.nLeftDecoration;
+ maGeometry.nBottomDecoration = hp - h - maGeometry.nTopDecoration;
+ /*
+ * note: this works because hWM_Parent is direct child of root,
+ * not necessarily parent of GetShellWindow()
+ */
+ maGeometry.nX = xp + nLeft;
+ maGeometry.nY = yp + nTop;
+ bResized = w != maGeometry.nWidth || h != maGeometry.nHeight;
+ maGeometry.nWidth = w;
+ maGeometry.nHeight = h;
+ }
+
+
+ // limit width and height if we are too large: #47757
+ // olwm and fvwm need this, it doesnt harm the rest
+
+ // #i81311# do this only for sizable frames
+ if( (nStyle_ & SAL_FRAME_STYLE_SIZEABLE) != 0 )
+ {
+ Size aScreenSize = GetDisplay()->GetScreenSize( m_nScreen );
+ int nScreenWidth = aScreenSize.Width();
+ int nScreenHeight = aScreenSize.Height();
+ int nFrameWidth = maGeometry.nWidth + maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
+ int nFrameHeight = maGeometry.nHeight + maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
+
+ if ((nFrameWidth > nScreenWidth) || (nFrameHeight > nScreenHeight))
+ {
+ Size aSize(maGeometry.nWidth, maGeometry.nHeight);
+
+ if (nFrameWidth > nScreenWidth)
+ aSize.Width() = nScreenWidth - maGeometry.nRightDecoration - maGeometry.nLeftDecoration;
+ if (nFrameHeight > nScreenHeight)
+ aSize.Height() = nScreenHeight - maGeometry.nBottomDecoration - maGeometry.nTopDecoration;
+
+ SetSize( aSize );
+ bResized = false;
+ }
+ }
+ if( bResized )
+ CallCallback( SALEVENT_RESIZE, NULL );
+
+ GetDisplay()->GetXLib()->PopXErrorLevel();
+
+ return 1;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleColormapEvent( XColormapEvent* )
+{
+ return 0;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleStateEvent( XPropertyEvent *pEvent )
+{
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytes_after;
+ unsigned char *prop = NULL;
+
+ if( 0 != XGetWindowProperty( GetXDisplay(),
+ GetShellWindow(),
+ pEvent->atom, // property
+ 0, // long_offset (32bit)
+ 2, // long_length (32bit)
+ False, // delete
+ pEvent->atom, // req_type
+ &actual_type,
+ &actual_format,
+ &nitems,
+ &bytes_after,
+ &prop )
+ || ! prop
+ )
+ return 0;
+
+ DBG_ASSERT( actual_type = pEvent->atom
+ && 32 == actual_format
+ && 2 == nitems
+ && 0 == bytes_after, "HandleStateEvent" );
+
+ if( *(unsigned long*)prop == NormalState )
+ nShowState_ = SHOWSTATE_NORMAL;
+ else if( *(unsigned long*)prop == IconicState )
+ nShowState_ = SHOWSTATE_MINIMIZED;
+
+ XFree( prop );
+ return 1;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleClientMessage( XClientMessageEvent *pEvent )
+{
+ const WMAdaptor& rWMAdaptor( *pDisplay_->getWMAdaptor() );
+
+#if !defined(__synchronous_extinput__)
+ if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::SAL_EXTTEXTEVENT ) )
+ {
+ HandleExtTextEvent (pEvent);
+ return 1;
+ }
+#endif
+ else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::SAL_QUITEVENT ) )
+ {
+ stderr0( "X11SalFrame::Dispatch Quit\n" );
+ Close(); // ???
+ return 1;
+ }
+ else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::WM_PROTOCOLS ) )
+ {
+ if( (Atom)pEvent->data.l[0] == rWMAdaptor.getAtom( WMAdaptor::NET_WM_PING ) )
+ rWMAdaptor.answerPing( this, pEvent );
+ else if( ! ( nStyle_ & SAL_FRAME_STYLE_PLUG )
+ && ! (( nStyle_ & SAL_FRAME_STYLE_FLOAT ) && (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION))
+ )
+ {
+ if( (Atom)pEvent->data.l[0] == rWMAdaptor.getAtom( WMAdaptor::WM_DELETE_WINDOW ) )
+ {
+ Close();
+ return 1;
+ }
+ else if( (Atom)pEvent->data.l[0] == rWMAdaptor.getAtom( WMAdaptor::WM_TAKE_FOCUS ) )
+ {
+ // do nothing, we set the input focus in ToTop() if necessary
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "got WM_TAKE_FOCUS on %s window\n",
+ (nStyle_&SAL_FRAME_STYLE_OWNERDRAWDECORATION) ?
+ "ownerdraw" : "NON OWNERDRAW" );
+ #endif
+ }
+ else if( (Atom)pEvent->data.l[0] == rWMAdaptor.getAtom( WMAdaptor::WM_SAVE_YOURSELF ) )
+ {
+ bool bSession = rWMAdaptor.getWindowManagerName().EqualsAscii( "Dtwm" );
+
+ if( ! bSession )
+ {
+ if( this == s_pSaveYourselfFrame )
+ {
+ rtl::OString aExec(rtl::OUStringToOString(SessionManagerClient::getExecName(), osl_getThreadTextEncoding()));
+ const char* argv[2];
+ argv[0] = "/bin/sh";
+ argv[1] = const_cast<char*>(aExec.getStr());
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SaveYourself request, setting command: %s %s\n", argv[0], argv[1] );
+ #endif
+ XSetCommand( GetXDisplay(), GetShellWindow(), (char**)argv, 2 );
+ }
+ else
+ // can only happen in race between WM and window closing
+ XChangeProperty( GetXDisplay(), GetShellWindow(), rWMAdaptor.getAtom( WMAdaptor::WM_COMMAND ), XA_STRING, 8, PropModeReplace, (unsigned char*)"", 0 );
+ }
+ else
+ {
+ // save open documents; would be good for non Dtwm, too,
+ // but there is no real Shutdown message in the ancient
+ // SM protocol; on Dtwm SaveYourself really means Shutdown, too.
+ IceSalSession::handleOldX11SaveYourself( this );
+ }
+ }
+ }
+ }
+ else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::XEMBED ) &&
+ pEvent->window == GetWindow() )
+ {
+ if( pEvent->data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
+ pEvent->data.l[1] == 2 ) // XEMBED_WINDOW_DEACTIVATE
+ {
+ XFocusChangeEvent aEvent;
+ aEvent.type = (pEvent->data.l[1] == 1 ? FocusIn : FocusOut);
+ aEvent.serial = pEvent->serial;
+ aEvent.send_event = True;
+ aEvent.display = pEvent->display;
+ aEvent.window = pEvent->window;
+ aEvent.mode = NotifyNormal;
+ aEvent.detail = NotifyDetailNone;
+ HandleFocusEvent( &aEvent );
+ }
+ }
+ return 0;
+}
+
+void X11SalFrame::SaveYourselfDone( SalFrame* pSaveFrame )
+{
+ // session save was done, inform dtwm
+ if( s_pSaveYourselfFrame && pSaveFrame )
+ {
+ rtl::OString aExec(rtl::OUStringToOString(SessionManagerClient::getExecName(), osl_getThreadTextEncoding()));
+ const char* argv[2];
+ argv[0] = "/bin/sh";
+ argv[1] = const_cast<char*>(aExec.getStr());
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SaveYourself request, setting command: %s %s\n", argv[0], argv[1] );
+#endif
+ XSetCommand( s_pSaveYourselfFrame->GetXDisplay(),
+ s_pSaveYourselfFrame->GetShellWindow(),
+ (char**)argv, 2 );
+ if( pSaveFrame != s_pSaveYourselfFrame )
+ {
+ // check if it still exists
+ const X11SalFrame* pFrame = NULL;
+ const std::list< SalFrame* >& rFrames = static_cast<X11SalFrame*>(pSaveFrame)->GetDisplay()->getFrames();
+ std::list< SalFrame* >::const_iterator it = rFrames.begin();
+ while( it != rFrames.end() )
+ {
+ pFrame = static_cast< const X11SalFrame* >(*it);
+ if( pFrame == pSaveFrame )
+ break;
+ ++it;
+ }
+ if( pFrame == pSaveFrame )
+ {
+ const WMAdaptor& rWMAdaptor( *pFrame->pDisplay_->getWMAdaptor() );
+ XChangeProperty( pFrame->GetXDisplay(),
+ pFrame->GetShellWindow(),
+ rWMAdaptor.getAtom( WMAdaptor::WM_COMMAND ), XA_STRING, 8, PropModeReplace, (unsigned char*)"", 0 );
+ }
+ }
+ s_pSaveYourselfFrame->ShutDown();
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+extern "C"
+{
+Bool call_checkKeyReleaseForRepeat( Display* pDisplay, XEvent* pCheck, XPointer pX11SalFrame )
+{
+ return X11SalFrame::checkKeyReleaseForRepeat( pDisplay, pCheck, pX11SalFrame );
+}
+}
+
+Bool X11SalFrame::checkKeyReleaseForRepeat( Display*, XEvent* pCheck, XPointer pX11SalFrame )
+{
+ X11SalFrame* pThis = (X11SalFrame*)pX11SalFrame;
+ return
+ pCheck->type == XLIB_KeyPress &&
+ pCheck->xkey.state == pThis->nKeyState_ &&
+ pCheck->xkey.keycode == pThis->nKeyCode_ &&
+ pCheck->xkey.time == pThis->nReleaseTime_ ? True : False;
+}
+
+long X11SalFrame::Dispatch( XEvent *pEvent )
+{
+ long nRet = 0;
+
+ if( -1 == nCaptured_ )
+ {
+ CaptureMouse( sal_True );
+#ifdef DBG_UTIL
+ if( -1 != nCaptured_ )
+ pDisplay_->PrintEvent( "Captured", pEvent );
+#endif
+ }
+
+ if( pEvent->xany.window == GetShellWindow() || pEvent->xany.window == GetWindow() )
+ {
+ switch( pEvent->type )
+ {
+ case XLIB_KeyPress:
+ nKeyCode_ = pEvent->xkey.keycode;
+ nKeyState_ = pEvent->xkey.state;
+ nRet = HandleKeyEvent( &pEvent->xkey );
+ break;
+
+ case KeyRelease:
+ if( -1 == nCompose_ )
+ {
+ nReleaseTime_ = pEvent->xkey.time;
+ XEvent aEvent;
+ if( XCheckIfEvent( pEvent->xkey.display, &aEvent, call_checkKeyReleaseForRepeat, (XPointer)this ) )
+ XPutBackEvent( pEvent->xkey.display, &aEvent );
+ else
+ nRet = HandleKeyEvent( &pEvent->xkey );
+ }
+ break;
+
+ case ButtonPress:
+ // if we loose the focus in presentation mode
+ // there are good chances that we never get it back
+ // since the WM ignores us
+ if( IsOverrideRedirect() )
+ {
+ XSetInputFocus( GetXDisplay(), GetShellWindow(),
+ RevertToNone, CurrentTime );
+ }
+
+ case ButtonRelease:
+ case MotionNotify:
+ case EnterNotify:
+ case LeaveNotify:
+ nRet = HandleMouseEvent( pEvent );
+ break;
+
+ case FocusIn:
+ case FocusOut:
+ nRet = HandleFocusEvent( &pEvent->xfocus );
+ break;
+
+ case Expose:
+ case GraphicsExpose:
+ nRet = HandleExposeEvent( pEvent );
+ break;
+
+ case MapNotify:
+ if( pEvent->xmap.window == GetShellWindow() )
+ {
+ if( nShowState_ == SHOWSTATE_HIDDEN )
+ {
+ /*
+ * workaround for (at least) KWin 2.2.2
+ * which will map windows that were once transient
+ * even if they are withdrawn when the respective
+ * document is mapped.
+ */
+ if( ! (nStyle_ & SAL_FRAME_STYLE_PLUG) )
+ XUnmapWindow( GetXDisplay(), GetShellWindow() );
+ break;
+ }
+ bMapped_ = sal_True;
+ bViewable_ = sal_True;
+ nRet = sal_True;
+ if ( mpInputContext != NULL )
+ mpInputContext->Map( this );
+ CallCallback( SALEVENT_RESIZE, NULL );
+ if( pDisplay_->GetServerVendor() == vendor_hummingbird )
+ {
+ /*
+ * With Exceed sometimes there does not seem to be
+ * an Expose after the MapNotify.
+ * so start a delayed paint here
+ */
+ maPaintRegion.Union( Rectangle( Point( 0, 0 ), Size( maGeometry.nWidth, maGeometry.nHeight ) ) );
+ XEvent aEvent;
+ aEvent.xexpose.type = Expose;
+ aEvent.xexpose.display = pDisplay_->GetDisplay();
+ aEvent.xexpose.x = 0;
+ aEvent.xexpose.y = 0;
+ aEvent.xexpose.width = maGeometry.nWidth;
+ aEvent.xexpose.height = maGeometry.nHeight;
+ aEvent.xexpose.count = 0;
+ XSendEvent( pDisplay_->GetDisplay(),
+ GetWindow(),
+ True,
+ ExposureMask,
+ &aEvent );
+ }
+
+ bool bSetFocus = m_bSetFocusOnMap;
+ /* another workaround for sawfish: if a transient window for the same parent is shown
+ * sawfish does not set the focus to it. Applies only for click to focus mode.
+ */
+ if( ! (nStyle_ & SAL_FRAME_STYLE_FLOAT ) && mbInShow && GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii( "Sawfish" ) )
+ {
+ // don't set the focus into the IME status window
+ // since this will lead to a parent loose-focus, close status,
+ // reget focus, open status, .... flicker loop
+ if ( (I18NStatus::get().getStatusFrame() != this) )
+ bSetFocus = true;
+ }
+
+ /*
+ * sometimes a message box/dialogue is brought up when a frame is not mapped
+ * the corresponding TRANSIENT_FOR hint is then set to the root window
+ * so that the dialogue shows in all cases. Correct it here if the
+ * frame is shown afterwards.
+ */
+ if( ! IsChildWindow()
+ && ! IsOverrideRedirect()
+ && ! IsFloatGrabWindow()
+ )
+ {
+ for( std::list< X11SalFrame* >::const_iterator it = maChildren.begin();
+ it != maChildren.end(); ++it )
+ {
+ if( (*it)->mbTransientForRoot )
+ pDisplay_->getWMAdaptor()->changeReferenceFrame( *it, this );
+ }
+ }
+
+ if( hPresentationWindow != None && GetShellWindow() == hPresentationWindow )
+ XSetInputFocus( GetXDisplay(), GetShellWindow(), RevertToParent, CurrentTime );
+ /* For unknown reasons Dtwm does respect the input_hint
+ * set to False, but not when mapping the window. So
+ * emulate the correct behaviour and set the focus back
+ * to where it most probably should have been.
+ */
+ if( (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
+ mpParent &&
+ GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii( "Dtwm" )
+ )
+ {
+ XSetInputFocus( GetXDisplay(),
+ mpParent->GetShellWindow(),
+ RevertToParent,
+ CurrentTime );
+ bSetFocus = false;
+ }
+
+ if( bSetFocus )
+ {
+ XSetInputFocus( GetXDisplay(),
+ GetShellWindow(),
+ RevertToParent,
+ CurrentTime );
+ }
+
+
+ RestackChildren();
+ mbInShow = sal_False;
+ m_bSetFocusOnMap = false;
+ }
+ break;
+
+ case UnmapNotify:
+ if( pEvent->xunmap.window == GetShellWindow() )
+ {
+ bMapped_ = sal_False;
+ bViewable_ = sal_False;
+ nRet = sal_True;
+ if ( mpInputContext != NULL )
+ mpInputContext->Unmap( this );
+ CallCallback( SALEVENT_RESIZE, NULL );
+ }
+ break;
+
+ case ConfigureNotify:
+ if( pEvent->xconfigure.window == GetShellWindow()
+ || pEvent->xconfigure.window == GetWindow() )
+ nRet = HandleSizeEvent( &pEvent->xconfigure );
+ break;
+
+ case VisibilityNotify:
+ nVisibility_ = pEvent->xvisibility.state;
+ nRet = sal_True;
+ if( bAlwaysOnTop_
+ && bMapped_
+ && ! GetDisplay()->getWMAdaptor()->isAlwaysOnTopOK()
+ && nVisibility_ != VisibilityUnobscured )
+ maAlwaysOnTopRaiseTimer.Start();
+ break;
+
+ case ReparentNotify:
+ nRet = HandleReparentEvent( &pEvent->xreparent );
+ break;
+
+ case MappingNotify:
+ if( MappingPointer != pEvent->xmapping.request )
+ nRet = CallCallback( SALEVENT_KEYBOARDCHANGED, 0 );
+ break;
+
+ case ColormapNotify:
+ nRet = HandleColormapEvent( &pEvent->xcolormap );
+ break;
+
+ case PropertyNotify:
+ {
+ if( pEvent->xproperty.atom == pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_STATE ) )
+ nRet = HandleStateEvent( &pEvent->xproperty );
+ else
+ nRet = pDisplay_->getWMAdaptor()->handlePropertyNotify( this, &pEvent->xproperty );
+ break;
+ }
+
+ case ClientMessage:
+ nRet = HandleClientMessage( &pEvent->xclient );
+ break;
+ }
+ }
+ else
+ {
+ switch( pEvent->type )
+ {
+ case FocusIn:
+ case FocusOut:
+ if( ( nStyle_ & SAL_FRAME_STYLE_PLUG )
+ && ( pEvent->xfocus.window == GetShellWindow()
+ || pEvent->xfocus.window == GetForeignParent() )
+ )
+ {
+ nRet = HandleFocusEvent( &pEvent->xfocus );
+ }
+ break;
+
+ case ConfigureNotify:
+ if( pEvent->xconfigure.window == GetForeignParent() ||
+ pEvent->xconfigure.window == GetShellWindow() )
+ nRet = HandleSizeEvent( &pEvent->xconfigure );
+
+ if( pEvent->xconfigure.window == GetStackingWindow() )
+ nRet = HandleSizeEvent( &pEvent->xconfigure );
+
+ RestackChildren();
+ break;
+ }
+ }
+
+ return nRet;
+}
+
+void X11SalFrame::ResetClipRegion()
+{
+ delete [] m_pClipRectangles;
+ m_pClipRectangles = NULL;
+ m_nCurClipRect = m_nMaxClipRect = 0;
+
+ const int dest_kind = ShapeBounding;
+ const int op = ShapeSet;
+ const int ordering = YSorted;
+
+ XWindowAttributes win_attrib;
+ XRectangle win_size;
+
+ XLIB_Window aShapeWindow = mhShellWindow;
+
+ XGetWindowAttributes ( GetDisplay()->GetDisplay(),
+ aShapeWindow,
+ &win_attrib );
+
+ win_size.x = 0;
+ win_size.y = 0;
+ win_size.width = win_attrib.width;
+ win_size.height = win_attrib.height;
+
+ XShapeCombineRectangles ( GetDisplay()->GetDisplay(),
+ aShapeWindow,
+ dest_kind,
+ 0, 0, // x_off, y_off
+ &win_size, // list of rectangles
+ 1, // number of rectangles
+ op, ordering );
+}
+
+void X11SalFrame::BeginSetClipRegion( sal_uLong nRects )
+{
+ if( m_pClipRectangles )
+ delete [] m_pClipRectangles;
+ if( nRects )
+ m_pClipRectangles = new XRectangle[nRects];
+ else
+ m_pClipRectangles = NULL;
+ m_nMaxClipRect = static_cast<int>(nRects);
+ m_nCurClipRect = 0;
+}
+
+void X11SalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( m_pClipRectangles && m_nCurClipRect < m_nMaxClipRect )
+ {
+ m_pClipRectangles[m_nCurClipRect].x = nX;
+ m_pClipRectangles[m_nCurClipRect].y = nY;
+ m_pClipRectangles[m_nCurClipRect].width = nWidth;
+ m_pClipRectangles[m_nCurClipRect].height = nHeight;
+ m_nCurClipRect++;
+ }
+}
+
+void X11SalFrame::EndSetClipRegion()
+{
+ const int dest_kind = ShapeBounding;
+ const int ordering = YSorted;
+ const int op = ShapeSet;
+
+ XLIB_Window aShapeWindow = mhShellWindow;
+ XShapeCombineRectangles ( GetDisplay()->GetDisplay(),
+ aShapeWindow,
+ dest_kind,
+ 0, 0, // x_off, y_off
+ m_pClipRectangles,
+ m_nCurClipRect,
+ op, ordering );
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/window/salobj.cxx b/vcl/unx/generic/window/salobj.cxx
new file mode 100644
index 000000000000..124c0f6cadbb
--- /dev/null
+++ b/vcl/unx/generic/window/salobj.cxx
@@ -0,0 +1,569 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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 <tools/debug.hxx>
+
+#include <vcl/keycodes.hxx>
+
+#include <tools/prex.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/shape.h>
+#include <tools/postx.h>
+
+#include <unx/salunx.h>
+#include <unx/salstd.hxx>
+#include <unx/saldata.hxx>
+#include <unx/salinst.h>
+#include <unx/saldisp.hxx>
+#include <unx/salframe.h>
+#include <unx/salobj.h>
+
+#include <salwtype.hxx>
+
+
+// =======================================================================
+// SalInstance member to create and destroy a SalObject
+
+SalObject* X11SalInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, sal_Bool bShow )
+{
+ return X11SalObject::CreateObject( pParent, pWindowData, bShow );
+}
+
+X11SalObject* X11SalObject::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, sal_Bool bShow )
+{
+ int error_base, event_base;
+ X11SalObject* pObject = new X11SalObject();
+ SystemChildData* pObjData = const_cast<SystemChildData*>(pObject->GetSystemData());
+
+ if ( ! XShapeQueryExtension( (Display*)pObjData->pDisplay,
+ &event_base, &error_base ) )
+ {
+ delete pObject;
+ return NULL;
+ }
+
+ pObject->mpParent = pParent;
+
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ const SystemEnvData* pEnv = pParent->GetSystemData();
+ Display* pDisp = pSalDisp->GetDisplay();
+ XLIB_Window aObjectParent = (XLIB_Window)pEnv->aWindow;
+
+ // find out on which screen that window is
+ XWindowAttributes aParentAttr;
+ XGetWindowAttributes( pDisp, aObjectParent, &aParentAttr );
+ int nScreen = XScreenNumberOfScreen( aParentAttr.screen );
+ Visual* pVisual = (pWindowData && pWindowData->pVisual) ?
+ (Visual*)pWindowData->pVisual :
+ pSalDisp->GetVisual( nScreen ).GetVisual();
+ // get visual info
+ VisualID aVisID = XVisualIDFromVisual( pVisual );
+ XVisualInfo aTemplate;
+ aTemplate.visualid = aVisID;
+ int nVisuals = 0;
+ XVisualInfo* pInfos = XGetVisualInfo( pDisp, VisualIDMask, &aTemplate, &nVisuals );
+ // only one VisualInfo structure can match the visual id
+ DBG_ASSERT( nVisuals == 1, "match count for visual id is not 1" );
+ unsigned int nDepth = pInfos->depth;
+ XFree( pInfos );
+ XSetWindowAttributes aAttribs;
+ aAttribs.event_mask = StructureNotifyMask
+ | ButtonPressMask
+ | ButtonReleaseMask
+ | PointerMotionMask
+ | EnterWindowMask
+ | LeaveWindowMask
+ | FocusChangeMask
+ | ExposureMask
+ ;
+
+ pObject->maPrimary =
+ XCreateSimpleWindow( pDisp,
+ aObjectParent,
+ 0, 0,
+ 1, 1, 0,
+ pSalDisp->GetColormap( nScreen ).GetBlackPixel(),
+ pSalDisp->GetColormap( nScreen ).GetWhitePixel()
+ );
+ if( aVisID == pSalDisp->GetVisual( nScreen ).GetVisualId() )
+ {
+ pObject->maSecondary =
+ XCreateSimpleWindow( pDisp,
+ pObject->maPrimary,
+ 0, 0,
+ 1, 1, 0,
+ pSalDisp->GetColormap( nScreen ).GetBlackPixel(),
+ pSalDisp->GetColormap( nScreen ).GetWhitePixel()
+ );
+ }
+ else
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "visual id of vcl %x, of visual %x\n",
+ static_cast<unsigned int> (pSalDisp->GetVisual( nScreen ).GetVisualId()),
+ static_cast<unsigned int> (aVisID) );
+ #endif
+ pSalDisp->GetXLib()->PushXErrorLevel( true );
+
+ // create colormap for visual - there might not be one
+ pObject->maColormap = aAttribs.colormap = XCreateColormap(
+ pDisp,
+ pSalDisp->GetRootWindow( nScreen ),
+ pVisual,
+ AllocNone );
+
+ pObject->maSecondary =
+ XCreateWindow( pDisp,
+ pSalDisp->GetRootWindow( nScreen ),
+ 0, 0,
+ 1, 1, 0,
+ nDepth, InputOutput,
+ pVisual,
+ CWEventMask|CWColormap, &aAttribs );
+ XSync( pDisp, False );
+ sal_Bool bWasXError = pSalDisp->GetXLib()->HasXErrorOccurred();
+ pSalDisp->GetXLib()->PopXErrorLevel();
+ if( bWasXError )
+ {
+ pObject->maSecondary = None;
+ delete pObject;
+ return NULL;
+ }
+ XReparentWindow( pDisp, pObject->maSecondary, pObject->maPrimary, 0, 0 );
+ }
+
+ pSalDisp->GetXLib()->PushXErrorLevel( true );
+ if( bShow ) {
+ XMapWindow( pDisp, pObject->maSecondary );
+ XMapWindow( pDisp, pObject->maPrimary );
+ }
+
+ pObjData->pDisplay = pDisp;
+ pObjData->aWindow = pObject->maSecondary;
+ pObjData->pWidget = NULL;
+ pObjData->pVisual = pVisual;
+ pObjData->nDepth = nDepth;
+ pObjData->aColormap = aVisID == pSalDisp->GetVisual( nScreen ).GetVisualId() ?
+ pSalDisp->GetColormap( nScreen ).GetXColormap() : None;
+ pObjData->pAppContext = NULL;
+
+ XSync(pDisp, False);
+ sal_Bool bWasXError = pSalDisp->GetXLib()->HasXErrorOccurred();
+ pSalDisp->GetXLib()->PopXErrorLevel();
+ if( bWasXError )
+ {
+ delete pObject;
+ return NULL;
+ }
+
+ return pObject;
+}
+
+
+void X11SalInstance::DestroyObject( SalObject* pObject )
+{
+ delete pObject;
+}
+
+
+// ======================================================================
+// SalClipRegion is a member of SalObject
+// definition of SalClipRegion my be found in unx/inc/salobj.h
+
+
+SalClipRegion::SalClipRegion()
+{
+ ClipRectangleList = NULL;
+ numClipRectangles = 0;
+ maxClipRectangles = 0;
+ nClipRegionType = SAL_OBJECT_CLIP_INCLUDERECTS;
+}
+
+
+SalClipRegion::~SalClipRegion()
+{
+ if ( ClipRectangleList )
+ delete [] ClipRectangleList;
+}
+
+
+void
+SalClipRegion::BeginSetClipRegion( sal_uLong nRects )
+{
+ if (ClipRectangleList)
+ delete [] ClipRectangleList;
+
+ ClipRectangleList = new XRectangle[nRects];
+ numClipRectangles = 0;
+ maxClipRectangles = nRects;
+}
+
+
+void
+SalClipRegion::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if ( nWidth && nHeight && (numClipRectangles < maxClipRectangles) )
+ {
+ XRectangle *aRect = ClipRectangleList + numClipRectangles;
+
+ aRect->x = (short) nX;
+ aRect->y = (short) nY;
+ aRect->width = (unsigned short) nWidth;
+ aRect->height= (unsigned short) nHeight;
+
+ numClipRectangles++;
+ }
+}
+
+
+// =======================================================================
+// SalObject Implementation
+
+
+X11SalObject::X11SalObject()
+{
+ maSystemChildData.nSize = sizeof( SystemChildData );
+ maSystemChildData.pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
+ maSystemChildData.aWindow = None;
+ maSystemChildData.pSalFrame = 0;
+ maSystemChildData.pWidget = 0;
+ maSystemChildData.pVisual = 0;
+ maSystemChildData.nDepth = 0;
+ maSystemChildData.aColormap = 0;
+ maSystemChildData.pAppContext = NULL;
+ maSystemChildData.aShellWindow = 0;
+ maSystemChildData.pShellWidget = NULL;
+ maPrimary = 0;
+ maSecondary = 0;
+ maColormap = 0;
+
+ std::list< SalObject* >& rObjects = GetX11SalData()->GetDisplay()->getSalObjects();
+ rObjects.push_back( this );
+}
+
+
+X11SalObject::~X11SalObject()
+{
+ std::list< SalObject* >& rObjects = GetX11SalData()->GetDisplay()->getSalObjects();
+ rObjects.remove( this );
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ pSalDisp->GetXLib()->PushXErrorLevel( true );
+ if ( maSecondary )
+ XDestroyWindow( (Display*)maSystemChildData.pDisplay, maSecondary );
+ if ( maPrimary )
+ XDestroyWindow( (Display*)maSystemChildData.pDisplay, maPrimary );
+ if ( maColormap )
+ XFreeColormap((Display*)maSystemChildData.pDisplay, maColormap);
+ XSync( (Display*)maSystemChildData.pDisplay, False );
+ pSalDisp->GetXLib()->PopXErrorLevel();
+}
+
+
+void
+X11SalObject::ResetClipRegion()
+{
+ maClipRegion.ResetClipRegion();
+
+ const int dest_kind = ShapeBounding;
+ const int op = ShapeSet;
+ const int ordering = YSorted;
+
+ XWindowAttributes win_attrib;
+ XRectangle win_size;
+
+ XLIB_Window aShapeWindow = maPrimary;
+
+ XGetWindowAttributes ( (Display*)maSystemChildData.pDisplay,
+ aShapeWindow,
+ &win_attrib );
+
+ win_size.x = 0;
+ win_size.y = 0;
+ win_size.width = win_attrib.width;
+ win_size.height = win_attrib.height;
+
+ XShapeCombineRectangles ( (Display*)maSystemChildData.pDisplay,
+ aShapeWindow,
+ dest_kind,
+ 0, 0, // x_off, y_off
+ &win_size, // list of rectangles
+ 1, // number of rectangles
+ op, ordering );
+}
+
+
+void
+X11SalObject::BeginSetClipRegion( sal_uLong nRectCount )
+{
+ maClipRegion.BeginSetClipRegion ( nRectCount );
+}
+
+
+void
+X11SalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ maClipRegion.UnionClipRegion ( nX, nY, nWidth, nHeight );
+}
+
+
+void
+X11SalObject::EndSetClipRegion()
+{
+ XRectangle *pRectangles = maClipRegion.EndSetClipRegion ();
+ const int nType = maClipRegion.GetClipRegionType();
+ const int nRectangles = maClipRegion.GetRectangleCount();
+
+ const int dest_kind = ShapeBounding;
+ const int ordering = YSorted;
+ int op;
+
+ switch ( nType )
+ {
+ case SAL_OBJECT_CLIP_INCLUDERECTS :
+ op = ShapeSet;
+ break;
+ case SAL_OBJECT_CLIP_EXCLUDERECTS :
+ op = ShapeSubtract;
+ break;
+ case SAL_OBJECT_CLIP_ABSOLUTE :
+ op = ShapeSet;
+ break;
+ default :
+ op = ShapeUnion;
+ }
+
+ XLIB_Window aShapeWindow = maPrimary;
+
+ XShapeCombineRectangles ( (Display*)maSystemChildData.pDisplay,
+ aShapeWindow,
+ dest_kind,
+ 0, 0, // x_off, y_off
+ pRectangles,
+ nRectangles,
+ op, ordering );
+}
+
+
+sal_uInt16
+X11SalObject::GetClipRegionType()
+{
+ return maClipRegion.GetClipRegionType();
+}
+
+// -----------------------------------------------------------------------
+
+void
+X11SalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight )
+{
+ if ( maPrimary && maSecondary && nWidth && nHeight )
+ {
+ XMoveResizeWindow( (Display*)maSystemChildData.pDisplay,
+ maPrimary,
+ nX, nY, nWidth, nHeight );
+ XMoveResizeWindow( (Display*)maSystemChildData.pDisplay,
+ maSecondary,
+ 0, 0, nWidth, nHeight );
+ }
+}
+
+
+void
+X11SalObject::Show( sal_Bool bVisible )
+{
+ if ( ! maSystemChildData.aWindow )
+ return;
+
+ if ( bVisible ) {
+ XMapWindow( (Display*)maSystemChildData.pDisplay,
+ maSecondary );
+ XMapWindow( (Display*)maSystemChildData.pDisplay,
+ maPrimary );
+ } else {
+ XUnmapWindow( (Display*)maSystemChildData.pDisplay,
+ maPrimary );
+ XUnmapWindow( (Display*)maSystemChildData.pDisplay,
+ maSecondary );
+ }
+ mbVisible = bVisible;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalObject::Enable( sal_Bool )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalObject::GrabFocus()
+{
+ if( mbVisible )
+ XSetInputFocus( (Display*)maSystemChildData.pDisplay,
+ maSystemChildData.aWindow,
+ RevertToNone,
+ CurrentTime );
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalObject::SetBackground()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalObject::SetBackground( SalColor )
+{
+}
+
+// -----------------------------------------------------------------------
+
+const SystemChildData* X11SalObject::GetSystemData() const
+{
+ return &maSystemChildData;
+}
+
+static sal_uInt16 sal_GetCode( int state )
+{
+ sal_uInt16 nCode = 0;
+
+ if( state & Button1Mask )
+ nCode |= MOUSE_LEFT;
+ if( state & Button2Mask )
+ nCode |= MOUSE_MIDDLE;
+ if( state & Button3Mask )
+ nCode |= MOUSE_RIGHT;
+
+ if( state & ShiftMask )
+ nCode |= KEY_SHIFT;
+ if( state & ControlMask )
+ nCode |= KEY_MOD1;
+ if( state & Mod1Mask )
+ nCode |= KEY_MOD2;
+ if( state & Mod3Mask )
+ nCode |= KEY_MOD3;
+
+ return nCode;
+}
+
+long X11SalObject::Dispatch( XEvent* pEvent )
+{
+ std::list< SalObject* >& rObjects = GetX11SalData()->GetDisplay()->getSalObjects();
+
+ for( std::list< SalObject* >::iterator it = rObjects.begin(); it != rObjects.end(); ++it )
+ {
+ X11SalObject* pObject = static_cast<X11SalObject*>(*it);
+ if( pEvent->xany.window == pObject->maPrimary ||
+ pEvent->xany.window == pObject->maSecondary )
+ {
+ if( pObject->IsMouseTransparent() && (
+ pEvent->type == ButtonPress ||
+ pEvent->type == ButtonRelease ||
+ pEvent->type == EnterNotify ||
+ pEvent->type == LeaveNotify ||
+ pEvent->type == MotionNotify
+ )
+ )
+ {
+ SalMouseEvent aEvt;
+ const SystemEnvData* pParentData = pObject->mpParent->GetSystemData();
+ int dest_x, dest_y;
+ XLIB_Window aChild = None;
+ XTranslateCoordinates( pEvent->xbutton.display,
+ pEvent->xbutton.root,
+ pParentData->aWindow,
+ pEvent->xbutton.x_root,
+ pEvent->xbutton.y_root,
+ &dest_x, &dest_y,
+ &aChild );
+ aEvt.mnX = dest_x;
+ aEvt.mnY = dest_y;
+ aEvt.mnTime = pEvent->xbutton.time;
+ aEvt.mnCode = sal_GetCode( pEvent->xbutton.state );
+ aEvt.mnButton = 0;
+ sal_uInt16 nEvent = 0;
+ if( pEvent->type == ButtonPress ||
+ pEvent->type == ButtonRelease )
+ {
+ switch( pEvent->xbutton.button )
+ {
+ case Button1: aEvt.mnButton = MOUSE_LEFT;break;
+ case Button2: aEvt.mnButton = MOUSE_MIDDLE;break;
+ case Button3: aEvt.mnButton = MOUSE_RIGHT;break;
+ }
+ nEvent = (pEvent->type == ButtonPress) ?
+ SALEVENT_MOUSEBUTTONDOWN :
+ SALEVENT_MOUSEBUTTONUP;
+ }
+ else if( pEvent->type == EnterNotify )
+ nEvent = SALEVENT_MOUSELEAVE;
+ else
+ nEvent = SALEVENT_MOUSEMOVE;
+ pObject->mpParent->CallCallback( nEvent, &aEvt );
+ }
+ else
+ {
+ switch( pEvent->type )
+ {
+ case UnmapNotify:
+ pObject->mbVisible = sal_False;
+ return 1;
+ case MapNotify:
+ pObject->mbVisible = sal_True;
+ return 1;
+ case ButtonPress:
+ pObject->CallCallback( SALOBJ_EVENT_TOTOP, NULL );
+ return 1;
+ case FocusIn:
+ pObject->CallCallback( SALOBJ_EVENT_GETFOCUS, NULL );
+ return 1;
+ case FocusOut:
+ pObject->CallCallback( SALOBJ_EVENT_LOSEFOCUS, NULL );
+ return 1;
+ default: break;
+ }
+ }
+ return 0;
+ }
+ }
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalObject::InterceptChildWindowKeyDown( sal_Bool /*bIntercept*/ )
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ \ No newline at end of file