diff options
author | Mathias Bauer <mba@openoffice.org> | 2009-09-25 21:47:16 +0200 |
---|---|---|
committer | Mathias Bauer <mba@openoffice.org> | 2009-09-25 21:47:16 +0200 |
commit | 4de41d18fd2b96079b9a0aa9f1ef123e431fe938 (patch) | |
tree | cd19df126f82819bb8f82c7e1cdbcd07b449a29d /vcl | |
parent | 6152b5efa3490cc8f09f269dc7542ffe3833358c (diff) | |
parent | 728c8eb458b5613eb5b8bbe8201dfc33a8a9cd78 (diff) |
merge commit
Diffstat (limited to 'vcl')
127 files changed, 13517 insertions, 849 deletions
diff --git a/vcl/aqua/inc/saldata.hxx b/vcl/aqua/inc/saldata.hxx index dc629b9a3b8c..a84be1fc2c25 100644 --- a/vcl/aqua/inc/saldata.hxx +++ b/vcl/aqua/inc/saldata.hxx @@ -35,6 +35,8 @@ #include <Cocoa/Cocoa.h> #include "postmac.h" +#include "com/sun/star/uno/Reference.hxx" + #include "vcl/sv.h" #include "vcl/svdata.hxx" #include "vcl/salwtype.hxx" @@ -112,6 +114,9 @@ struct SalData long mnDPIX; // #i100617# read DPI only once per office life long mnDPIY; // #i100617# read DPI only once per office life + com::sun::star::uno::Reference< com::sun::star::uno::XInterface > + mxClipboard; + SalData(); ~SalData(); diff --git a/vcl/aqua/inc/salframe.h b/vcl/aqua/inc/salframe.h index aeabdefc72a5..1d1eb3cb6bd3 100644 --- a/vcl/aqua/inc/salframe.h +++ b/vcl/aqua/inc/salframe.h @@ -44,6 +44,8 @@ #include <utility> #include <stdexcept> +#include <boost/shared_ptr.hpp> + class AquaSalGraphics; class AquaSalFrame; class AquaSalTimer; @@ -60,47 +62,49 @@ typedef struct SalFrame::SalPointerState SalPointerState; class AquaSalFrame : public SalFrame { public: - NSWindow* mpWindow; // Cocoa window - NSView* mpView; // Cocoa view (actually a custom view, see below - NSMenuItem* mpDockMenuEntry; // entry in the dynamic dock menu - NSRect maScreenRect; // for mirroring purposes - AquaSalGraphics* mpGraphics; // current frame graphics - AquaSalFrame* mpParent; // pointer to parent frame - SystemEnvData maSysData; // system data - int mnMinWidth; // min. client width in pixels - int mnMinHeight; // min. client height in pixels - int mnMaxWidth; // max. client width in pixels - int mnMaxHeight; // max. client height in pixels - NSRect maFullScreenRect; // old window size when in FullScreen - bool mbGraphics:1; // is Graphics used? - bool mbFullScreen:1; // is Window in FullScreen? - bool mbShown:1; - bool mbInitShow:1; - bool mbPositioned:1; - bool mbSized:1; - bool mbPresentation:1; - - ULONG mnStyle; - unsigned int mnStyleMask; // our style mask from NSWindow creation - - ULONG mnLastEventTime; - unsigned int mnLastModifierFlags; - AquaSalMenu* mpMenu; - - SalExtStyle mnExtStyle; // currently document frames are marked this way - - PointerStyle mePointerStyle; // currently active pointer style - - NSTrackingRectTag mnTrackingRectTag; // used to get enter/leave messages - - CGMutablePathRef mrClippingPath; // used for "shaping" - std::vector< CGRect > maClippingRects; - - std::list<AquaBlinker*> maBlinkers; - - Rectangle maInvalidRect; - - ULONG mnICOptions; + NSWindow* mpWindow; // Cocoa window + NSView* mpView; // Cocoa view (actually a custom view, see below + NSMenuItem* mpDockMenuEntry; // entry in the dynamic dock menu + NSRect maScreenRect; // for mirroring purposes + AquaSalGraphics* mpGraphics; // current frame graphics + AquaSalFrame* mpParent; // pointer to parent frame + SystemEnvData maSysData; // system data + int mnMinWidth; // min. client width in pixels + int mnMinHeight; // min. client height in pixels + int mnMaxWidth; // max. client width in pixels + int mnMaxHeight; // max. client height in pixels + NSRect maFullScreenRect; // old window size when in FullScreen + bool mbGraphics:1; // is Graphics used? + bool mbFullScreen:1; // is Window in FullScreen? + bool mbShown:1; + bool mbInitShow:1; + bool mbPositioned:1; + bool mbSized:1; + bool mbPresentation:1; + + ULONG mnStyle; + unsigned int mnStyleMask; // our style mask from NSWindow creation + + ULONG mnLastEventTime; + unsigned int mnLastModifierFlags; + AquaSalMenu* mpMenu; + + SalExtStyle mnExtStyle; // currently document frames are marked this way + + PointerStyle mePointerStyle; // currently active pointer style + + NSTrackingRectTag mnTrackingRectTag; // used to get enter/leave messages + + CGMutablePathRef mrClippingPath; // used for "shaping" + std::vector< CGRect > maClippingRects; + + std::list<AquaBlinker*> maBlinkers; + + Rectangle maInvalidRect; + + ULONG mnICOptions; + + boost::shared_ptr< Timer > mpActivityTimer; // Timer to prevent system sleep during presentation public: /** Constructor diff --git a/vcl/aqua/inc/salinst.h b/vcl/aqua/inc/salinst.h index b2cbc83d9f79..82ac5b6f4ffd 100644 --- a/vcl/aqua/inc/salinst.h +++ b/vcl/aqua/inc/salinst.h @@ -146,6 +146,12 @@ public: virtual void SetEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) ); virtual void SetErrorEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) ); + // dtrans implementation + virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > + CreateClipboard( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& i_rArguments ); + virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDragSource(); + virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDropTarget(); + static void handleAppDefinedEvent( NSEvent* pEvent ); // check whether a particular string is passed on the command line diff --git a/vcl/aqua/inc/vclnsapp.h b/vcl/aqua/inc/vclnsapp.h index fc637ff75a31..622f1bfd6bcd 100755 --- a/vcl/aqua/inc/vclnsapp.h +++ b/vcl/aqua/inc/vclnsapp.h @@ -35,6 +35,8 @@ #include "Cocoa/Cocoa.h" #include "postmac.h" +class AquaSalFrame; + @interface CocoaThreadEnabler : NSObject { } @@ -64,6 +66,8 @@ -(void)applicationWillResignActive: (NSNotification *)pNotification; -(MacOSBOOL)applicationShouldHandleReopen: (NSApplication*)pApp hasVisibleWindows: (MacOSBOOL)bWinVisible; -(void)setDockIconClickHandler: (NSObject*)pHandler; +-(void)cycleFrameForward: (AquaSalFrame*)pCurFrame; +-(void)cycleFrameBackward: (AquaSalFrame*)pCurFrame; @end #endif diff --git a/vcl/aqua/source/a11y/aqua11yfactory.mm b/vcl/aqua/source/a11y/aqua11yfactory.mm index b660472d9bbe..a49bce957b3b 100644 --- a/vcl/aqua/source/a11y/aqua11yfactory.mm +++ b/vcl/aqua/source/a11y/aqua11yfactory.mm @@ -151,7 +151,18 @@ static bool enabled = false; } [ nativeRole release ]; [ aWrapper setActsAsRadioGroup: asRadioGroup ]; - if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::TRANSIENT ) ) { + #if 0 + /* #i102033# NSAccessibility does not seemt to know an equivalent for transient children. + That means we need to cache this, else e.g. tree list boxes are not accessible (moreover + it crashes by notifying dead objects - which would seemt o be another bug) + + FIXME: + Unfortunately this can increase memory consumption drastically until the non transient parent + is destroyed an finally all the transients are released. + */ + if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::TRANSIENT ) ) + #endif + { [ dAllWrapper setObject: aWrapper forKey: nKey ]; } } diff --git a/vcl/aqua/source/a11y/aqua11ywrapper.mm b/vcl/aqua/source/a11y/aqua11ywrapper.mm index 99bcbd20f698..64e0e9ef0308 100644 --- a/vcl/aqua/source/a11y/aqua11ywrapper.mm +++ b/vcl/aqua/source/a11y/aqua11ywrapper.mm @@ -109,7 +109,18 @@ static MacOSBOOL isPopupMenuOpen = NO; // XAccessibleMultiLineText mpReferenceWrapper -> rAccessibleMultiLineText = Reference < XAccessibleMultiLineText > ( rxAccessibleContext, UNO_QUERY ); // XAccessibleEventBroadcaster - if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::TRANSIENT ) ) { + #if 0 + /* #i102033# NSAccessibility does not seemt to know an equivalent for transient children. + That means we need to cache this, else e.g. tree list boxes are not accessible (moreover + it crashes by notifying dead objects - which would seemt o be another bug) + + FIXME: + Unfortunately this can increase memory consumption drastically until the non transient parent + is destroyed an finally all the transients are released. + */ + if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::TRANSIENT ) ) + #endif + { Reference< XAccessibleEventBroadcaster > xBroadcaster(rxAccessibleContext, UNO_QUERY); if( xBroadcaster.is() ) { /* diff --git a/vcl/aqua/source/app/makefile.mk b/vcl/aqua/source/app/makefile.mk index 2bf3641898f1..a90c95c74a6e 100644 --- a/vcl/aqua/source/app/makefile.mk +++ b/vcl/aqua/source/app/makefile.mk @@ -50,8 +50,6 @@ dummy: .ELSE # "$(GUIBASE)"!="aqua" -#CFLAGS+=-x objective-c++ - SLOFILES= $(SLO)$/salinst.obj \ $(SLO)$/saldata.obj \ $(SLO)$/vclnsapp.obj \ diff --git a/vcl/aqua/source/app/salinst.cxx b/vcl/aqua/source/app/salinst.cxx index 71bfb7953187..56bf1a612b40 100644 --- a/vcl/aqua/source/app/salinst.cxx +++ b/vcl/aqua/source/app/salinst.cxx @@ -815,6 +815,18 @@ bool AquaSalInstance::AnyInput( USHORT nType ) return false; } + if( nType & INPUT_TIMER ) + { + if( AquaSalTimer::pRunningTimer ) + { + NSDate* pDt = [AquaSalTimer::pRunningTimer fireDate]; + if( pDt && [pDt timeIntervalSinceNow] < 0 ) + { + return true; + } + } + } + unsigned/*NSUInteger*/ nEventMask = 0; if( nType & INPUT_MOUSE) nEventMask |= @@ -828,7 +840,7 @@ bool AquaSalInstance::AnyInput( USHORT nType ) nEventMask |= NSKeyDownMask | NSKeyUpMask | NSFlagsChangedMask; if( nType & INPUT_OTHER) nEventMask |= NSTabletPoint; - // TODO: INPUT_PAINT / INPUT_TIMER / more INPUT_OTHER + // TODO: INPUT_PAINT / more INPUT_OTHER if( !nType) return false; diff --git a/vcl/aqua/source/app/vclnsapp.mm b/vcl/aqua/source/app/vclnsapp.mm index 43d44c709c12..5a295b5e1171 100755 --- a/vcl/aqua/source/app/vclnsapp.mm +++ b/vcl/aqua/source/app/vclnsapp.mm @@ -104,6 +104,24 @@ return; } } + + // #i90083# handle frame switching + // FIXME: lousy workaround + if( (nModMask & (NSControlKeyMask|NSAlternateKeyMask)) == 0 ) + { + if( [[pEvent characters] isEqualToString: @"<"] || + [[pEvent characters] isEqualToString: @"~"] ) + { + [self cycleFrameForward: pFrame]; + return; + } + else if( [[pEvent characters] isEqualToString: @">"] || + [[pEvent characters] isEqualToString: @"`"] ) + { + [self cycleFrameBackward: pFrame]; + return; + } + } // get information whether the event was handled; keyDown returns nothing GetSalData()->maKeyEventAnswer[ pEvent ] = false; @@ -186,6 +204,84 @@ { [super sendEvent: pEvent]; } + +-(void)cycleFrameForward: (AquaSalFrame*)pCurFrame +{ + // find current frame in list + std::list< AquaSalFrame* >& rFrames( GetSalData()->maFrames ); + std::list< AquaSalFrame* >::iterator it = rFrames.begin(); + for( ; it != rFrames.end() && *it != pCurFrame; ++it ) + ; + if( it != rFrames.end() ) + { + // now find the next frame (or end) + do + { + ++it; + if( it != rFrames.end() ) + { + if( (*it)->mpDockMenuEntry != NULL && + (*it)->mbShown ) + { + [(*it)->getWindow() makeKeyAndOrderFront: NSApp]; + return; + } + } + } while( it != rFrames.end() ); + // cycle around, find the next up to pCurFrame + it = rFrames.begin(); + while( *it != pCurFrame ) + { + if( (*it)->mpDockMenuEntry != NULL && + (*it)->mbShown ) + { + [(*it)->getWindow() makeKeyAndOrderFront: NSApp]; + return; + } + ++it; + } + } +} + +-(void)cycleFrameBackward: (AquaSalFrame*)pCurFrame +{ + // do the same as cycleFrameForward only with a reverse iterator + + // find current frame in list + std::list< AquaSalFrame* >& rFrames( GetSalData()->maFrames ); + std::list< AquaSalFrame* >::reverse_iterator it = rFrames.rbegin(); + for( ; it != rFrames.rend() && *it != pCurFrame; ++it ) + ; + if( it != rFrames.rend() ) + { + // now find the next frame (or end) + do + { + ++it; + if( it != rFrames.rend() ) + { + if( (*it)->mpDockMenuEntry != NULL && + (*it)->mbShown ) + { + [(*it)->getWindow() makeKeyAndOrderFront: NSApp]; + return; + } + } + } while( it != rFrames.rend() ); + // cycle around, find the next up to pCurFrame + it = rFrames.rbegin(); + while( *it != pCurFrame ) + { + if( (*it)->mpDockMenuEntry != NULL && + (*it)->mbShown ) + { + [(*it)->getWindow() makeKeyAndOrderFront: NSApp]; + return; + } + ++it; + } + } +} -(NSMenu*)applicationDockMenu:(NSApplication *)sender { diff --git a/vcl/aqua/source/dtrans/DataFlavorMapping.cxx b/vcl/aqua/source/dtrans/DataFlavorMapping.cxx new file mode 100644 index 000000000000..af05f084a97e --- /dev/null +++ b/vcl/aqua/source/dtrans/DataFlavorMapping.cxx @@ -0,0 +1,711 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DataFlavorMapping.cxx,v $ + * $Revision: 1.6 $ + * + * 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. + * + ************************************************************************/ + +#include "vcl/unohelp.hxx" +#include <DataFlavorMapping.hxx> +#include "HtmlFmtFlt.hxx" +#include "PictToBmpFlt.hxx" +#include "com/sun/star/datatransfer/UnsupportedFlavorException.hpp" +#include "com/sun/star/datatransfer/XMimeContentType.hpp" +#include "com/sun/star/lang/XMultiServiceFactory.hpp" +#include "com/sun/star/uno/Sequence.hxx" + +#include <rtl/ustring.hxx> +#include <rtl/memory.h> +#include <osl/endian.h> + +#include <vector> +#include <stdio.h> + +#include <premac.h> +#include <QuickTime/QuickTime.h> +#include <postmac.h> + +using namespace ::com::sun::star::datatransfer; +using namespace rtl; +using namespace ::com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace cppu; +using namespace std; + +namespace // private +{ + const Type CPPUTYPE_SEQINT8 = getCppuType((Sequence<sal_Int8>*)0); + const Type CPPUTYPE_OUSTRING = getCppuType( (OUString*)0 ); + + /* Determine whether or not a DataFlavor is valid. + */ + bool isValidFlavor(const DataFlavor& aFlavor) + { + size_t len = aFlavor.MimeType.getLength(); + Type dtype = aFlavor.DataType; + return ((len > 0) && ((dtype == CPPUTYPE_SEQINT8) || (dtype == CPPUTYPE_OUSTRING))); + } + + typedef vector<sal_Unicode> UnicodeBuffer; + + OUString NSStringToOUString(NSString* cfString) + { + BOOST_ASSERT(cfString && "Invalid parameter"); + + const char* utf8Str = [cfString UTF8String]; + unsigned int len = rtl_str_getLength(utf8Str); + + return OUString(utf8Str, len, RTL_TEXTENCODING_UTF8); + } + + NSString* OUStringToNSString(const OUString& ustring) + { + OString utf8Str = OUStringToOString(ustring, RTL_TEXTENCODING_UTF8); + return [NSString stringWithCString: utf8Str.getStr() encoding: NSUTF8StringEncoding]; + } + + + const NSString* PBTYPE_UT16 = @"CorePasteboardFlavorType 0x75743136"; + const NSString* PBTYPE_PICT = @"CorePasteboardFlavorType 0x50494354"; + const NSString* PBTYPE_HTML = @"CorePasteboardFlavorType 0x48544D4C"; + const NSString* PBTYPE_SODX = @"application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\""; + const NSString* PBTYPE_SESX = @"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""; + const NSString* PBTYPE_SLSDX = @"application/x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link Source Descriptor (XML)\""; + const NSString* PBTYPE_ESX = @"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""; + const NSString* PBTYPE_LSX = @"application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\""; + const NSString* PBTYPE_EOX = @"application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\""; + const NSString* PBTYPE_SVXB = @"application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\""; + const NSString* PBTYPE_GDIMF = @"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\""; + const NSString* PBTYPE_WMF = @"application/x-openoffice-wmf;windows_formatname=\"Image WMF\""; + const NSString* PBTYPE_EMF = @"application/x-openoffice-emf;windows_formatname=\"Image EMF\""; + + const NSString* PBTYPE_DUMMY_INTERNAL = @"application/x-openoffice-internal"; + + const char* FLAVOR_SODX = "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\""; + const char* FLAVOR_SESX = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""; + const char* FLAVOR_SLSDX = "application/x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link Source Descriptor (XML)\""; + const char* FLAVOR_ESX = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""; + const char* FLAVOR_LSX = "application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\""; + const char* FLAVOR_EOX = "application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\""; + const char* FLAVOR_SVXB = "application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\""; + const char* FLAVOR_GDIMF = "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\""; + const char* FLAVOR_WMF = "application/x-openoffice-wmf;windows_formatname=\"Image WMF\""; + const char* FLAVOR_EMF = "application/x-openoffice-emf;windows_formatname=\"Image EMF\""; + + const char* FLAVOR_DUMMY_INTERNAL = "application/x-openoffice-internal"; + + + struct FlavorMap + { + NSString* SystemFlavor; + const char* OOoFlavor; + const char* HumanPresentableName; + Type DataType; + }; + + /* At the moment it appears as if only MS Office pastes "public.html" to the clipboard. + */ + FlavorMap flavorMap[] = + { + { NSStringPboardType, "text/plain;charset=utf-16", "Unicode Text (UTF-16)", CPPUTYPE_OUSTRING }, + { NSRTFPboardType, "text/richtext", "Rich Text Format", CPPUTYPE_SEQINT8 }, + { NSPICTPboardType, "image/bmp", "Windows Bitmap", CPPUTYPE_SEQINT8 }, + { NSHTMLPboardType, "text/html", "Plain Html", CPPUTYPE_SEQINT8 }, + { NSFilenamesPboardType, "application/x-openoffice-filelist;windows_formatname=\"FileList\"", "FileList", CPPUTYPE_SEQINT8 }, + { PBTYPE_SESX, FLAVOR_SESX, "Star Embed Source (XML)", CPPUTYPE_SEQINT8 }, + { PBTYPE_SLSDX, FLAVOR_SLSDX, "Star Link Source Descriptor (XML)", CPPUTYPE_SEQINT8 }, + { PBTYPE_ESX, FLAVOR_ESX, "Star Embed Source (XML)", CPPUTYPE_SEQINT8 }, + { PBTYPE_LSX, FLAVOR_LSX, "Star Link Source (XML)", CPPUTYPE_SEQINT8 }, + { PBTYPE_EOX, FLAVOR_EOX, "Star Embedded Object (XML)", CPPUTYPE_SEQINT8 }, + { PBTYPE_SVXB, FLAVOR_SVXB, "SVXB (StarView Bitmap/Animation", CPPUTYPE_SEQINT8 }, + { PBTYPE_GDIMF, FLAVOR_GDIMF, "GDIMetaFile", CPPUTYPE_SEQINT8 }, + { PBTYPE_WMF, FLAVOR_WMF, "Windows MetaFile", CPPUTYPE_SEQINT8 }, + { PBTYPE_EMF, FLAVOR_EMF, "Windows Enhanced MetaFile", CPPUTYPE_SEQINT8 }, + { PBTYPE_SODX, FLAVOR_SODX, "Star Object Descriptor (XML)", CPPUTYPE_SEQINT8 }, + { PBTYPE_DUMMY_INTERNAL, FLAVOR_DUMMY_INTERNAL, "internal data",CPPUTYPE_SEQINT8 } + // { PBTYPE_UT16, "text/plain;charset=utf-16", "Unicode Text (UTF-16)", CPPUTYPE_OUSTRING } + // { kUTTypePICT, @"PICT", "image/x-macpict;windows_formatname=\"Mac Pict\"", "Mac Pict", CPPUTYPE_SEQINT8 } + // { kUTTypeHTML, @"HTML", "text/html", "Plain Html", CPPUTYPE_SEQINT8 } + }; + + + #define SIZE_FLAVOR_MAP (sizeof(flavorMap)/sizeof(FlavorMap)) + + + inline bool isByteSequenceType(const Type& theType) + { + return (theType == CPPUTYPE_SEQINT8); + } + + inline bool isOUStringType(const Type& theType) + { + return (theType == CPPUTYPE_OUSTRING); + } + +} // namespace private + + +//########################### + +/* A base class for other data provider. + */ +class DataProviderBaseImpl : public DataProvider +{ +public: + DataProviderBaseImpl(const Any& data); + DataProviderBaseImpl(id data); + virtual ~DataProviderBaseImpl(); + +protected: + Any mData; + //NSData* mSystemData; + id mSystemData; +}; + +DataProviderBaseImpl::DataProviderBaseImpl(const Any& data) : + mData(data), + mSystemData(nil) +{ +} + +DataProviderBaseImpl::DataProviderBaseImpl(id data) : + mSystemData(data) +{ + [mSystemData retain]; +} + + +DataProviderBaseImpl::~DataProviderBaseImpl() +{ + if (mSystemData) + { + [mSystemData release]; + } +} + +//################################# + +class UniDataProvider : public DataProviderBaseImpl +{ +public: + UniDataProvider(const Any& data); + + UniDataProvider(NSData* data); + + virtual NSData* getSystemData(); + + virtual Any getOOoData(); +}; + +UniDataProvider::UniDataProvider(const Any& data) : + DataProviderBaseImpl(data) +{ +} + +UniDataProvider::UniDataProvider(NSData* data) : + DataProviderBaseImpl(data) +{ +} + +NSData* UniDataProvider::getSystemData() +{ + OUString ustr; + mData >>= ustr; + + OString strUtf8; + ustr.convertToString(&strUtf8, RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS); + + return [NSData dataWithBytes: strUtf8.getStr() length: strUtf8.getLength()]; +} + +Any UniDataProvider::getOOoData() +{ + Any oOOData; + + if (mSystemData) + { + oOOData = makeAny(OUString(reinterpret_cast<const sal_Char*>([mSystemData bytes]), + [mSystemData length], + RTL_TEXTENCODING_UTF8)); + } + else + { + oOOData = mData; + } + + return oOOData; +} + +//########################### + +class ByteSequenceDataProvider : public DataProviderBaseImpl +{ +public: + ByteSequenceDataProvider(const Any& data); + + ByteSequenceDataProvider(NSData* data); + + virtual NSData* getSystemData(); + + virtual Any getOOoData(); +}; + +ByteSequenceDataProvider::ByteSequenceDataProvider(const Any& data) : + DataProviderBaseImpl(data) +{ +} + +ByteSequenceDataProvider::ByteSequenceDataProvider(NSData* data) : + DataProviderBaseImpl(data) +{ +} + + +NSData* ByteSequenceDataProvider::getSystemData() +{ + Sequence<sal_Int8> rawData; + mData >>= rawData; + + return [NSData dataWithBytes: rawData.getArray() length: rawData.getLength()]; +} + +Any ByteSequenceDataProvider::getOOoData() +{ + Any oOOData; + + if (mSystemData) + { + unsigned int flavorDataLength = [mSystemData length]; + Sequence<sal_Int8> byteSequence; + byteSequence.realloc(flavorDataLength); + memcpy(byteSequence.getArray(), [mSystemData bytes], flavorDataLength); + oOOData = makeAny(byteSequence); + } + else + { + oOOData = mData; + } + + return oOOData; +} + + +//########################### + +class HTMLFormatDataProvider : public DataProviderBaseImpl +{ +public: + HTMLFormatDataProvider(const Any& data); + + HTMLFormatDataProvider(NSData* data); + + virtual NSData* getSystemData(); + + virtual Any getOOoData(); +}; + +HTMLFormatDataProvider::HTMLFormatDataProvider(const Any& data) : + DataProviderBaseImpl(data) +{ +} + +HTMLFormatDataProvider::HTMLFormatDataProvider(NSData* data) : + DataProviderBaseImpl(data) +{ +} + +NSData* HTMLFormatDataProvider::getSystemData() +{ + Sequence<sal_Int8> textHtmlData; + mData >>= textHtmlData; + + Sequence<sal_Int8> htmlFormatData = TextHtmlToHTMLFormat(textHtmlData); + + return [NSData dataWithBytes: htmlFormatData.getArray() length: htmlFormatData.getLength()]; +} + +Any HTMLFormatDataProvider::getOOoData() +{ + Any oOOData; + + if (mSystemData) + { + unsigned int flavorDataLength = [mSystemData length]; + Sequence<sal_Int8> unkHtmlData; + + unkHtmlData.realloc(flavorDataLength); + memcpy(unkHtmlData.getArray(), [mSystemData bytes], flavorDataLength); + + Sequence<sal_Int8>* pPlainHtml = &unkHtmlData; + Sequence<sal_Int8> plainHtml; + + if (isHTMLFormat(unkHtmlData)) + { + plainHtml = HTMLFormatToTextHtml(unkHtmlData); + pPlainHtml = &plainHtml; + } + + oOOData = makeAny(*pPlainHtml); + } + else + { + oOOData = mData; + } + + return oOOData; +} + +//########################### + +class BMPDataProvider : public DataProviderBaseImpl +{ +public: + BMPDataProvider(const Any& data); + + BMPDataProvider(NSData* data); + + virtual NSData* getSystemData(); + + virtual Any getOOoData(); +}; + +BMPDataProvider::BMPDataProvider(const Any& data) : + DataProviderBaseImpl(data) +{ +} + +BMPDataProvider::BMPDataProvider(NSData* data) : + DataProviderBaseImpl(data) +{ +} + +NSData* BMPDataProvider::getSystemData() +{ + Sequence<sal_Int8> bmpData; + mData >>= bmpData; + + Sequence<sal_Int8> pictData; + NSData* sysData = NULL; + + if (BMPtoPICT(bmpData, pictData)) + { + sysData = [NSData dataWithBytes: pictData.getArray() length: pictData.getLength()]; + } + + return sysData; +} + +/* At the moment the OOo 'PCT' filter is not good enough to be used + and there is no flavor defined for exchanging 'PCT' with OOo so + we will at the moment convert 'PCT' to a Windows BMP and provide + this to OOo +*/ +Any BMPDataProvider::getOOoData() +{ + Any oOOData; + + if (mSystemData) + { + unsigned int flavorDataLength = [mSystemData length]; + Sequence<sal_Int8> pictData(flavorDataLength); + + memcpy(pictData.getArray(), [mSystemData bytes], flavorDataLength); + + Sequence<sal_Int8> bmpData; + + if (PICTtoBMP(pictData, bmpData)) + { + oOOData = makeAny(bmpData); + } + } + else + { + oOOData = mData; + } + + return oOOData; +} + +//###################### + +class FileListDataProvider : public DataProviderBaseImpl +{ +public: + FileListDataProvider(const Any& data); + FileListDataProvider(NSArray* data); + + virtual NSData* getSystemData(); + virtual Any getOOoData(); +}; + +FileListDataProvider::FileListDataProvider(const Any& data) : + DataProviderBaseImpl(data) +{ +} + +FileListDataProvider::FileListDataProvider(NSArray* data) : + DataProviderBaseImpl(data) +{ +} + +NSData* FileListDataProvider::getSystemData() +{ + return [NSData data]; +} + +Any FileListDataProvider::getOOoData() +{ + Any oOOData; + + if (mSystemData) + { + size_t length = [mSystemData count]; + size_t lenSeqRequired = 0; + + for (size_t i = 0; i < length; i++) + { + NSString* fname = [mSystemData objectAtIndex: i]; + lenSeqRequired += [fname maximumLengthOfBytesUsingEncoding: NSUnicodeStringEncoding] + sizeof(unichar); + } + + Sequence<sal_Int8> oOOFileList(lenSeqRequired); + unichar* pBuffer = reinterpret_cast<unichar*>(oOOFileList.getArray()); + rtl_zeroMemory(pBuffer, lenSeqRequired); + + for (size_t i = 0; i < length; i++) + { + NSString* fname = [mSystemData objectAtIndex: i]; + [fname getCharacters: pBuffer]; + size_t l = [fname length]; + pBuffer += l + 1; + } + + oOOData = makeAny(oOOFileList); + } + else + { + oOOData = mData; + } + + return oOOData; +} + +//########################### + +DataFlavorMapper::DataFlavorMapper() +{ + Reference<XMultiServiceFactory> mrServiceManager = vcl::unohelper::GetMultiServiceFactory(); + mrXMimeCntFactory = Reference<XMimeContentTypeFactory>(mrServiceManager->createInstance( + OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.MimeContentTypeFactory"))), UNO_QUERY); + + if (!mrXMimeCntFactory.is()) + throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create com.sun.star.datatransfer.MimeContentTypeFactory")), NULL); +} + +DataFlavor DataFlavorMapper::systemToOpenOfficeFlavor(NSString* systemDataFlavor) const +{ + DataFlavor oOOFlavor; + + for (size_t i = 0; i < SIZE_FLAVOR_MAP; i++) + { + if ([systemDataFlavor caseInsensitiveCompare: flavorMap[i].SystemFlavor] == NSOrderedSame) + { + oOOFlavor.MimeType = OUString::createFromAscii(flavorMap[i].OOoFlavor); + oOOFlavor.HumanPresentableName = OUString(RTL_CONSTASCII_USTRINGPARAM(flavorMap[i].HumanPresentableName)); + oOOFlavor.DataType = flavorMap[i].DataType; + return oOOFlavor; + } + } // for + + return oOOFlavor; +} + +NSString* DataFlavorMapper::openOfficeToSystemFlavor(const DataFlavor& oOOFlavor) const +{ + NSString* sysFlavor = NULL; + + for (size_t i = 0; i < SIZE_FLAVOR_MAP; i++) + { + if (oOOFlavor.MimeType.compareToAscii(flavorMap[i].OOoFlavor, strlen(flavorMap[i].OOoFlavor)) == 0) + { + sysFlavor = flavorMap[i].SystemFlavor; + } + } + + return sysFlavor; +} + +DataProviderPtr_t DataFlavorMapper::getDataProvider(NSString* systemFlavor, Reference<XTransferable> rTransferable) const +{ + DataProviderPtr_t dp; + + try + { + DataFlavor oOOFlavor = systemToOpenOfficeFlavor(systemFlavor); + + Any data = rTransferable->getTransferData(oOOFlavor); + + if (isByteSequenceType(data.getValueType())) + { + if ([systemFlavor caseInsensitiveCompare: NSHTMLPboardType] == NSOrderedSame) + { + dp = DataProviderPtr_t(new HTMLFormatDataProvider(data)); + } + else if ([systemFlavor caseInsensitiveCompare: NSPICTPboardType] == NSOrderedSame) + { + dp = DataProviderPtr_t(new BMPDataProvider(data)); + } + else if ([systemFlavor caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame) + { + dp = DataProviderPtr_t(new FileListDataProvider(data)); + } + else + { + dp = DataProviderPtr_t(new ByteSequenceDataProvider(data)); + } + } + else // Must be OUString type + { + BOOST_ASSERT(isOUStringType(data.getValueType())); + dp = DataProviderPtr_t(new UniDataProvider(data)); + } + } + catch(UnsupportedFlavorException&) + { + // Somebody violates the contract of the clipboard + // interface @see XTransferable + } + + return dp; +} + +DataProviderPtr_t DataFlavorMapper::getDataProvider(const NSString* systemFlavor, NSArray* systemData) const +{ + return DataProviderPtr_t(new FileListDataProvider(systemData)); +} + +DataProviderPtr_t DataFlavorMapper::getDataProvider(const NSString* systemFlavor, NSData* systemData) const +{ + DataProviderPtr_t dp; + + if ([systemFlavor caseInsensitiveCompare: NSStringPboardType] == NSOrderedSame) + { + dp = DataProviderPtr_t(new UniDataProvider(systemData)); + } + else if ([systemFlavor caseInsensitiveCompare: NSHTMLPboardType] == NSOrderedSame) + { + dp = DataProviderPtr_t(new HTMLFormatDataProvider(systemData)); + } + else if ([systemFlavor caseInsensitiveCompare: NSPICTPboardType] == NSOrderedSame) + { + dp = DataProviderPtr_t(new BMPDataProvider(systemData)); + } + else if ([systemFlavor caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame) + { + //dp = DataProviderPtr_t(new FileListDataProvider(systemData)); + } + else + { + dp = DataProviderPtr_t(new ByteSequenceDataProvider(systemData)); + } + + return dp; +} + +bool DataFlavorMapper::isValidMimeContentType(const rtl::OUString& contentType) const +{ + bool result = true; + + try + { + Reference<XMimeContentType> xCntType(mrXMimeCntFactory->createMimeContentType(contentType)); + } + catch( IllegalArgumentException& ) + { + result = false; + } + + return result; +} + +NSArray* DataFlavorMapper::flavorSequenceToTypesArray(const com::sun::star::uno::Sequence<com::sun::star::datatransfer::DataFlavor>& flavors) const +{ + sal_uInt32 nFlavors = flavors.getLength(); + NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity: 1]; + + for (sal_uInt32 i = 0; i < nFlavors; i++) + { + NSString* str = openOfficeToSystemFlavor(flavors[i]); + + if (str != NULL) + { + [array addObject: str]; + } + } + + // #i89462# #i90747# + // in case no system flavor was found to report + // report at least one so D&D between OOo targets works + if( [array count] == 0 ) + { + [array addObject: PBTYPE_DUMMY_INTERNAL]; + } + + return [array autorelease]; +} + +com::sun::star::uno::Sequence<com::sun::star::datatransfer::DataFlavor> DataFlavorMapper::typesArrayToFlavorSequence(NSArray* types) const +{ + int nFormats = [types count]; + Sequence<DataFlavor> flavors; + + for (int i = 0; i < nFormats; i++) + { + NSString* sysFormat = [types objectAtIndex: i]; + DataFlavor oOOFlavor = systemToOpenOfficeFlavor(sysFormat); + + if (isValidFlavor(oOOFlavor)) + { + flavors.realloc(flavors.getLength() + 1); + flavors[flavors.getLength() - 1] = oOOFlavor; + } + } + + return flavors; +} + + +NSArray* DataFlavorMapper::getAllSupportedPboardTypes() const +{ + NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity: SIZE_FLAVOR_MAP]; + + for (sal_uInt32 i = 0; i < SIZE_FLAVOR_MAP; i++) + { + [array addObject: flavorMap[i].SystemFlavor]; + } + + return [array autorelease]; +} diff --git a/vcl/aqua/source/dtrans/DataFlavorMapping.hxx b/vcl/aqua/source/dtrans/DataFlavorMapping.hxx new file mode 100644 index 000000000000..03cb77e319f7 --- /dev/null +++ b/vcl/aqua/source/dtrans/DataFlavorMapping.hxx @@ -0,0 +1,141 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DataFlavorMapping.hxx,v $ + * $Revision: 1.4 $ + * + * 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 INCLUDED_DATAFLAVORMAPPING_HXX_ +#define INCLUDED_DATAFLAVORMAPPING_HXX_ + +#include <com/sun/star/datatransfer/DataFlavor.hpp> +#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> + +#include <premac.h> +#import <Cocoa/Cocoa.h> +#include <postmac.h> + +#include <memory> +#include <boost/shared_ptr.hpp> + + +/* An interface to get the clipboard data in either + system or OOo format. + */ +class DataProvider +{ +public: + virtual ~DataProvider() {}; + + /* Get the clipboard data in the system format. + The caller has to retain/release the returned + CFDataRef on demand. + */ + virtual NSData* getSystemData() = 0; + + /* Get the clipboard data in OOo format. + */ + virtual com::sun::star::uno::Any getOOoData() = 0; +}; + +typedef std::auto_ptr<DataProvider> DataProviderPtr_t; + + +//################################ + + +class DataFlavorMapper +{ +public: + /* Initialialize a DataFavorMapper instance. Throws a RuntimeException in case the XMimeContentTypeFactory service + cannot be created. + */ + DataFlavorMapper(); + + + /* Map a system data flavor to an OpenOffice data flavor. + Return an empty string if there is not suiteable + mapping from a system data flavor to a OpenOffice data + flavor. + */ + com::sun::star::datatransfer::DataFlavor systemToOpenOfficeFlavor(NSString* systemDataFlavor) const; + + + /* Map an OpenOffice data flavor to a system data flavor. + If there is no suiteable mapping available NULL will + be returned. + */ + NSString* openOfficeToSystemFlavor(const com::sun::star::datatransfer::DataFlavor& oooDataFlavor) const; + + + /* Get a data provider which is able to provide the data 'rTransferable' offers in a format that can + be put on to the system clipboard. + */ + DataProviderPtr_t getDataProvider(NSString* systemFlavor, + const com::sun::star::uno::Reference< com::sun::star::datatransfer::XTransferable > rTransferable) const; + + + + /* Get a data provider which is able to provide 'systemData' in the OOo expected format. + */ + DataProviderPtr_t getDataProvider(const NSString* systemFlavor, NSArray* systemData) const; + + + /* Get a data provider which is able to provide 'systemData' in the OOo expected format. + */ + DataProviderPtr_t getDataProvider(const NSString* systemFlavor, NSData* systemData) const; + + + /* Translate a sequence of DataFlavors into a NSArray of system types. + Only those DataFlavors for which a suitable mapping to a system + type exist will be contained in the returned types array. + */ + NSArray* flavorSequenceToTypesArray(const com::sun::star::uno::Sequence<com::sun::star::datatransfer::DataFlavor>& flavors) const; + + /* Translate a NSArray of system types into a sequence of DataFlavors. + Only those types for which a suitable mapping to a DataFlavor + exist will be contained in the new DataFlavor Sequence. + */ + com::sun::star::uno::Sequence<com::sun::star::datatransfer::DataFlavor> typesArrayToFlavorSequence(NSArray* types) const; + + /* Returns an NSArray containing all pasteboard types supported by OOo + */ + NSArray* DataFlavorMapper::getAllSupportedPboardTypes() const; + +private: + /* Determines if the provided Mime content type is valid. + */ + bool isValidMimeContentType(const rtl::OUString& contentType) const; + +private: + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XMimeContentTypeFactory> mrXMimeCntFactory; +}; + +typedef boost::shared_ptr<DataFlavorMapper> DataFlavorMapperPtr_t; + +#endif diff --git a/vcl/aqua/source/dtrans/DragActionConversion.cxx b/vcl/aqua/source/dtrans/DragActionConversion.cxx new file mode 100644 index 000000000000..793dcca503a0 --- /dev/null +++ b/vcl/aqua/source/dtrans/DragActionConversion.cxx @@ -0,0 +1,95 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DragActionConversion.cxx,v $ + * $Revision: 1.3 $ + * + * 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. + * + ************************************************************************/ + +#include "DragActionConversion.hxx" +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> + + +using namespace com::sun::star::datatransfer::dnd; + + +/* Convert office drag actions as defined in + <type>com::sun::star::datatransfer::dnd::DNDConstants</type> + into system conform drag actions. + */ +unsigned int OfficeToSystemDragActions(sal_Int8 dragActions) +{ + unsigned int actions = NSDragOperationNone; + + if (dragActions & DNDConstants::ACTION_COPY) + { + actions |= NSDragOperationCopy; + } + + if (dragActions & DNDConstants::ACTION_MOVE) + { + actions |= NSDragOperationMove; + } + + if (dragActions & DNDConstants::ACTION_LINK) + { + actions |= NSDragOperationLink; + } + + return actions; +} + +/* Convert system conform drag actions into office conform + drag actions as defined in + <type>com::sun::star::datatransfer::dnd::DNDConstants</type>. + */ +sal_Int8 SystemToOfficeDragActions(unsigned int dragActions) +{ + sal_Int8 actions = DNDConstants::ACTION_NONE; + + if (dragActions & NSDragOperationCopy) + { + actions |= DNDConstants::ACTION_COPY; + } + + if (dragActions & NSDragOperationMove) + { + actions |= DNDConstants::ACTION_MOVE; + } + + if (dragActions & NSDragOperationLink) + { + actions |= DNDConstants::ACTION_LINK; + } + + // We map NSDragOperationGeneric to ACTION_DEFAULT to + // signal that we have to decide for a drag action + if (dragActions & NSDragOperationGeneric) + { + actions |= DNDConstants::ACTION_DEFAULT; + } + + return actions; +} diff --git a/vcl/aqua/source/dtrans/DragActionConversion.hxx b/vcl/aqua/source/dtrans/DragActionConversion.hxx new file mode 100644 index 000000000000..137e2af30be1 --- /dev/null +++ b/vcl/aqua/source/dtrans/DragActionConversion.hxx @@ -0,0 +1,49 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DragActionConversion.hxx,v $ + * $Revision: 1.3 $ + * + * 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. + * + ************************************************************************/ + + +#include <sal/types.h> + +#include <premac.h> +#import <Cocoa/Cocoa.h> +#include <postmac.h> + + +/* Convert office drag actions as defined in + <type>com::sun::star::datatransfer::dnd::DNDConstants</type> + into system conform drag actions. + */ +unsigned int OfficeToSystemDragActions(sal_Int8 dragActions); + +/* Convert system conform drag actions into office conform + drag actions as defined in + <type>com::sun::star::datatransfer::dnd::DNDConstants</type>. + */ +sal_Int8 SystemToOfficeDragActions(unsigned int dragActions); diff --git a/vcl/aqua/source/dtrans/DragSource.cxx b/vcl/aqua/source/dtrans/DragSource.cxx new file mode 100644 index 000000000000..074ce5c6c318 --- /dev/null +++ b/vcl/aqua/source/dtrans/DragSource.cxx @@ -0,0 +1,366 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DragSource.cxx,v $ + * $Revision: 1.4 $ + * + * 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 <com/sun/star/datatransfer/dnd/DNDConstants.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/awt/MouseButton.hpp> +#include <rtl/unload.h> + +#include "comphelper/makesequence.hxx" + +#include "DragSource.hxx" +#include "DragSourceContext.hxx" +#include "aqua_clipboard.hxx" +#include "DragActionConversion.hxx" + +#include <rtl/ustring.h> +#include <memory> + + +using namespace rtl; +using namespace cppu; +using namespace osl; +using namespace com::sun::star::datatransfer; +using namespace com::sun::star::datatransfer::clipboard; +using namespace com::sun::star::datatransfer::dnd; +using namespace com::sun::star::datatransfer::dnd::DNDConstants; +using namespace com::sun::star::uno; +using namespace com::sun::star::awt::MouseButton; +using namespace com::sun::star::awt; +using namespace com::sun::star::lang; +using namespace comphelper; +using namespace std; + + +// For OOo internal D&D we provide the Transferable without NSDragPboard +// interference as a shortcut +Reference<XTransferable> DragSource::g_XTransferable = Reference<XTransferable>(); +NSView* DragSource::g_DragSourceView = nil; +bool DragSource::g_DropSuccessSet = false; +bool DragSource::g_DropSuccess = false; + + +OUString dragSource_getImplementationName() +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.datatransfer.dnd.OleDragSource_V1")); +} + +Sequence<OUString> dragSource_getSupportedServiceNames() +{ + return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDragSource"))); +} + + +@implementation DragSourceHelper; + +-(DragSourceHelper*)initWithDragSource: (DragSource*) pds +{ + self = [super init]; + + if (self) + { + mDragSource = pds; + } + + return self; +} + + +-(void)mouseDown: (NSEvent*)theEvent +{ + mDragSource->saveMouseEvent(theEvent); +} + + +-(void)mouseDragged: (NSEvent*)theEvent +{ + mDragSource->saveMouseEvent(theEvent); +} + + +-(unsigned int)draggingSourceOperationMaskForLocal: (MacOSBOOL)isLocal +{ + return mDragSource->getSupportedDragOperations(isLocal); +} + + +-(void)draggedImage:(NSImage*)anImage beganAt:(NSPoint)aPoint +{ + DragSourceDragEvent dsde(static_cast<OWeakObject*>(mDragSource), + new DragSourceContext(mDragSource), + mDragSource, + DNDConstants::ACTION_COPY, + DNDConstants::ACTION_COPY); + + mDragSource->mXDragSrcListener->dragEnter(dsde); +} + + +-(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation +{ + // an internal drop can accept the drop but fail with dropComplete( false ) + // this is different than the Cocoa API + bool bDropSuccess = operation != NSDragOperationNone; + if( DragSource::g_DropSuccessSet ) + bDropSuccess = DragSource::g_DropSuccess; + + DragSourceDropEvent dsde(static_cast<OWeakObject*>(mDragSource), + new DragSourceContext(mDragSource), + static_cast< XDragSource* >(mDragSource), + SystemToOfficeDragActions(operation), + bDropSuccess ); + + mDragSource->mXDragSrcListener->dragDropEnd(dsde); + mDragSource->mXDragSrcListener = Reference<XDragSourceListener>(); +} + + +-(void)draggedImage:(NSImage *)draggedImage movedTo:(NSPoint)screenPoint +{ + DragSourceDragEvent dsde(static_cast<OWeakObject*>(mDragSource), + new DragSourceContext(mDragSource), + mDragSource, + DNDConstants::ACTION_COPY, + DNDConstants::ACTION_COPY); + + mDragSource->mXDragSrcListener->dragOver(dsde); +} + +@end + + +DragSource::DragSource(): + WeakComponentImplHelper3<XDragSource, XInitialization, XServiceInfo>(m_aMutex), + mView(NULL), + mLastMouseEventBeforeStartDrag(nil), + m_MouseButton(0) +{ +} + + +DragSource::~DragSource() +{ + [(id <MouseEventListener>)mView unregisterMouseEventListener: mDragSourceHelper]; + [mDragSourceHelper release]; +} + + +void SAL_CALL DragSource::initialize(const Sequence< Any >& aArguments) + throw(Exception) +{ + if (aArguments.getLength() < 2) + { + throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Not enough parameter.")), + static_cast<OWeakObject*>(this)); + } + + Any pNSView = aArguments[1]; + sal_uInt64 tmp = 0; + pNSView >>= tmp; + mView = (NSView*)tmp; + + /* All SalFrameView the base class for all VCL system views inherits from + NSView in order to get mouse and other events. This is the only way to + get these events. In order to start a drag operation we need to provide + the mouse event which was the trigger. SalFrameView therefor implements + a hook mechanism so that we can get mouse events for our purpose. + */ + if (![mView respondsToSelector: @selector(registerMouseEventListener:)] || + ![mView respondsToSelector: @selector(unregisterMouseEventListener:)]) + { + throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Provided view doesn't support mouse listener")), + static_cast<OWeakObject*>(this)); + } + + mDragSourceHelper = [[DragSourceHelper alloc] initWithDragSource: this]; + + if (mDragSourceHelper == nil) + { + throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Cannot initialize DragSource")), + static_cast<OWeakObject*>(this)); + } + + [(id <MouseEventListener>)mView registerMouseEventListener: mDragSourceHelper]; +} + + +//---------------------------------------------------- +// XDragSource +//---------------------------------------------------- + +sal_Bool SAL_CALL DragSource::isDragImageSupported( ) + throw(RuntimeException) +{ + return true; +} + + +sal_Int32 SAL_CALL DragSource::getDefaultCursor( sal_Int8 /*dragAction*/ ) + throw( IllegalArgumentException, RuntimeException) +{ + return 0; +} + + +void SAL_CALL DragSource::startDrag(const DragGestureEvent& trigger, + sal_Int8 sourceActions, + sal_Int32 cursor, + sal_Int32 image, + const Reference<XTransferable >& transferable, + const Reference<XDragSourceListener >& listener ) + throw( RuntimeException) +{ + MutexGuard guard(m_aMutex); + + OSL_ASSERT(listener.is() && "DragSource::startDrag: No XDragSourceListener provided\n"); + OSL_ASSERT(transferable.is() && "DragSource::startDrag: No transferable provided\n"); + + trigger.Event >>= mMouseEvent; + m_MouseButton= mMouseEvent.Buttons; + mXDragSrcListener = listener; + mXCurrentContext = static_cast<XDragSourceContext*>(new DragSourceContext(this)); + auto_ptr<AquaClipboard> clipb(new AquaClipboard(NULL, false)); + g_XTransferable = transferable; + clipb->setContents(g_XTransferable, Reference<XClipboardOwner>()); + mDragSourceActions = sourceActions; + g_DragSourceView = mView; + + NSSize sz; + sz.width = 5; + sz.height = 5; + + NSImage* dragImage; + dragImage = [[NSImage alloc] initWithSize: sz]; + + NSRect bounds; + bounds.origin = NSMakePoint(0,0); + bounds.size = sz; + + [dragImage lockFocus]; + [[NSColor blackColor] set]; + [NSBezierPath fillRect: bounds]; + [dragImage unlockFocus]; + + NSPoint pInWnd = [mLastMouseEventBeforeStartDrag locationInWindow]; + NSPoint p; + p = [mView convertPoint: pInWnd fromView: nil]; + p.x = p.x - sz.width/2; + p.y = p.y - sz.height/2; + + // reset drop success flags + g_DropSuccessSet = false; + g_DropSuccess = false; + + [mView dragImage: dragImage + at: p + offset: NSMakeSize(0,0) + event: mLastMouseEventBeforeStartDrag + pasteboard: clipb->getPasteboard() + source: mDragSourceHelper + slideBack: 1]; + + [dragImage release]; + + g_XTransferable = Reference<XTransferable>(); + g_DragSourceView = nil; + + // reset drop success flags + g_DropSuccessSet = false; + g_DropSuccess = false; +} + + +// In order to initiate a D&D operation we need to +// provide the triggering mouse event which we get +// from the SalFrameView that is associated with +// this DragSource +void DragSource::saveMouseEvent(NSEvent* theEvent) +{ + if (mLastMouseEventBeforeStartDrag != nil) + { + [mLastMouseEventBeforeStartDrag release]; + } + + mLastMouseEventBeforeStartDrag = theEvent; +} + + +/* isLocal indicates whether or not the DnD operation is OOo + internal. + */ +unsigned int DragSource::getSupportedDragOperations(bool isLocal) const +{ + unsigned int srcActions = OfficeToSystemDragActions(mDragSourceActions); + + if (isLocal) + { + // Support NSDragOperation generic which means we can + // decide which D&D operation to choose. We map + // NSDragOperationGenric to DNDConstants::ACTION_DEFAULT + // in SystemToOfficeDragActions to signal this and + // use it in DropTarget::determineDropAction + srcActions |= NSDragOperationGeneric; + } + else + { + // Mask out link and move operations on external DnD + srcActions &= ~(NSDragOperationMove | NSDragOperationLink); + } + + return srcActions; +} + + +//################################ +// XServiceInfo +//################################ + +OUString SAL_CALL DragSource::getImplementationName( ) throw (RuntimeException) +{ + return dragSource_getImplementationName(); +} + + +sal_Bool SAL_CALL DragSource::supportsService( const OUString& ServiceName ) throw (RuntimeException) +{ + return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDragSource"))); +} + + +Sequence< OUString > SAL_CALL DragSource::getSupportedServiceNames() throw (RuntimeException) +{ + return dragSource_getSupportedServiceNames(); +} + + + + diff --git a/vcl/aqua/source/dtrans/DragSource.hxx b/vcl/aqua/source/dtrans/DragSource.hxx new file mode 100644 index 000000000000..1268a466adf3 --- /dev/null +++ b/vcl/aqua/source/dtrans/DragSource.hxx @@ -0,0 +1,143 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DragSource.hxx,v $ + * $Revision: 1.4 $ + * + * 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 _DRAGSOURCE_HXX_ +#define _DRAGSOURCE_HXX_ + +#include <com/sun/star/datatransfer/dnd/XDragSource.hpp> +#include <com/sun/star/datatransfer/dnd/XDragSourceContext.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <cppuhelper/compbase3.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/basemutex.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <osl/thread.h> +#include <com/sun/star/awt/MouseEvent.hpp> + +#include <boost/utility.hpp> + +#include <premac.h> +#import <Cocoa/Cocoa.h> +#include <postmac.h> + + +class DragSource; + +/* The functions declared in this protocol are actually + declared in vcl/aqua/inc/salframe.h. Because we want + to avoid importing VCL headers in UNO services and + on the other hand want to avoid warnings caused by + gcc complaining about unknowness of these functions + we declare them in a protocol here and cast at the + appropriate places. +*/ +@protocol MouseEventListener +-(void)registerMouseEventListener:(id)theHandler; +-(void)unregisterMouseEventListener:(id)theHandler; +@end + + +@interface DragSourceHelper : NSObject +{ + DragSource* mDragSource; +} + +-(DragSourceHelper*)initWithDragSource: (DragSource*) pds; + +-(void)mouseDown: (NSEvent*)theEvent; +-(void)mouseDragged: (NSEvent*)theEvent; + +-(unsigned int)draggingSourceOperationMaskForLocal:(MacOSBOOL)isLocal; +-(void)draggedImage:(NSImage*)anImage beganAt:(NSPoint)aPoint; +-(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation; +-(void)draggedImage:(NSImage *)draggedImage movedTo:(NSPoint)screenPoint; + +@end + + +class DragSource : public ::cppu::BaseMutex, + public ::cppu::WeakComponentImplHelper3< com::sun::star::datatransfer::dnd::XDragSource, + com::sun::star::lang::XInitialization, + com::sun::star::lang::XServiceInfo >, + private ::boost::noncopyable +{ +public: + DragSource(); + virtual ~DragSource(); + + // XInitialization + virtual void SAL_CALL initialize( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& aArguments ) + throw(com::sun::star::uno::Exception/*, com::sun::star::uno::RuntimeException*/); + + // XDragSource + virtual sal_Bool SAL_CALL isDragImageSupported( ) throw(com::sun::star::uno::RuntimeException); + + virtual sal_Int32 SAL_CALL getDefaultCursor(sal_Int8 dragAction) + throw(com::sun::star::lang::IllegalArgumentException, com::sun::star::uno::RuntimeException); + + 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(com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual rtl::OUString SAL_CALL getImplementationName() throw (com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService(const rtl::OUString& ServiceName) throw (com::sun::star::uno::RuntimeException); + virtual com::sun::star::uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames() throw (com::sun::star::uno::RuntimeException); + + virtual void saveMouseEvent(NSEvent* theEvent); + virtual unsigned int getSupportedDragOperations(bool isLocal) const; + +public: + // The context notifies the XDragSourceListeners + com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDragSourceContext > mXCurrentContext; + + id mView; + NSEvent* mLastMouseEventBeforeStartDrag; + DragSourceHelper* mDragSourceHelper; + com::sun::star::awt::MouseEvent mMouseEvent; + com::sun::star::uno::Reference< com::sun::star::datatransfer::XTransferable > mXTransferable; + com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDragSourceListener > mXDragSrcListener; + // The mouse button that set off the drag and drop operation + short m_MouseButton; + sal_Int8 mDragSourceActions; + + static com::sun::star::uno::Reference< com::sun::star::datatransfer::XTransferable > g_XTransferable; + static NSView* g_DragSourceView; + static bool g_DropSuccessSet; + static bool g_DropSuccess; + +}; + + +#endif diff --git a/vcl/aqua/source/dtrans/DragSourceContext.cxx b/vcl/aqua/source/dtrans/DragSourceContext.cxx new file mode 100644 index 000000000000..cd657a6147e9 --- /dev/null +++ b/vcl/aqua/source/dtrans/DragSourceContext.cxx @@ -0,0 +1,77 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DragSourceContext.cxx,v $ + * $Revision: 1.3 $ + * + * 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 <com/sun/star/datatransfer/dnd/DNDConstants.hpp> + +#include "DragSourceContext.hxx" +#include <rtl/unload.h> + + +using namespace com::sun::star::datatransfer::dnd; +using namespace com::sun::star::datatransfer::dnd::DNDConstants; +using namespace com::sun::star::uno; +using namespace cppu; + +DragSourceContext::DragSourceContext( DragSource* pSource) : + WeakComponentImplHelper1<XDragSourceContext>(m_aMutex), + m_pDragSource( pSource) +{ +} + +DragSourceContext::~DragSourceContext() +{ +} + +sal_Int32 SAL_CALL DragSourceContext::getCurrentCursor( ) + throw( RuntimeException) +{ + return 0; +} + +void SAL_CALL DragSourceContext::setCursor( sal_Int32 /*cursorId*/ ) + throw( RuntimeException) +{ +} + +void SAL_CALL DragSourceContext::setImage( sal_Int32 /*imageId*/ ) + throw( RuntimeException) +{ +} + +void SAL_CALL DragSourceContext::transferablesFlavorsChanged( ) + throw( RuntimeException) +{ +} + + diff --git a/vcl/aqua/source/dtrans/DragSourceContext.hxx b/vcl/aqua/source/dtrans/DragSourceContext.hxx new file mode 100644 index 000000000000..3526ec846fd6 --- /dev/null +++ b/vcl/aqua/source/dtrans/DragSourceContext.hxx @@ -0,0 +1,75 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DragSourceContext.hxx,v $ + * $Revision: 1.3 $ + * + * 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 _DRAGSOURCECONTEXT_HXX_ +#define _DRAGSOURCECONTEXT_HXX_ + +#include <cppuhelper/implbase1.hxx> +#include <com/sun/star/datatransfer/dnd/XDragSourceContext.hpp> +#include <cppuhelper/compbase1.hxx> +#include <cppuhelper/basemutex.hxx> + +#include <boost/utility.hpp> + +#include "DragSource.hxx" + +// This class fires events to XDragSourceListener implementations. +// Of that interface only dragDropEnd and dropActionChanged are called. +// The functions dragEnter, dragExit and dragOver are not supported +// currently. +// An instance of SourceContext only lives as long as the drag and drop +// operation lasts. +class DragSourceContext: public cppu::BaseMutex, + public cppu::WeakComponentImplHelper1<com::sun::star::datatransfer::dnd::XDragSourceContext>, + private ::boost::noncopyable +{ +public: + DragSourceContext(DragSource* pSource); + ~DragSourceContext(); + + virtual sal_Int32 SAL_CALL getCurrentCursor( ) + throw( com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL setCursor( sal_Int32 cursorId ) + throw( com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL setImage( sal_Int32 imageId ) + throw( com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL transferablesFlavorsChanged( ) + throw( com::sun::star::uno::RuntimeException); + +private: + DragSource* m_pDragSource; +}; + + + +#endif diff --git a/vcl/aqua/source/dtrans/DropTarget.cxx b/vcl/aqua/source/dtrans/DropTarget.cxx new file mode 100644 index 000000000000..88ffc1e51d02 --- /dev/null +++ b/vcl/aqua/source/dtrans/DropTarget.cxx @@ -0,0 +1,602 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DropTarget.cxx,v $ + * $Revision: 1.5 $ + * + * 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 <com/sun/star/datatransfer/dnd/DNDConstants.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp> +#include <rtl/unload.h> + +#ifndef COMPHELPER_MAKESEQUENCE_HXX_INCLUDED +#include "comphelper/makesequence.hxx" +#endif +#include <cppuhelper/interfacecontainer.hxx> + +#include "aqua_clipboard.hxx" +#include "DropTarget.hxx" +#include "DragActionConversion.hxx" + +#include "DragSource.hxx" + +#include <rtl/ustring.h> +#include <stdio.h> + +#include <premac.h> +#include <Carbon/Carbon.h> +#include <postmac.h> + + +using namespace rtl; +using namespace cppu; +using namespace osl; +using namespace com::sun::star::datatransfer; +using namespace com::sun::star::datatransfer::dnd; +using namespace com::sun::star::datatransfer::dnd::DNDConstants; +using namespace com::sun::star::datatransfer::clipboard; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace comphelper; + +OUString dropTarget_getImplementationName() +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1")); +} + + +Sequence<OUString> dropTarget_getSupportedServiceNames() +{ + return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget"))); +} + + +namespace /* private */ +{ + // Cocoa's coordinate system has its origin lower-left, VCL's + // coordinate system upper-left hence we need to transform + // coordinates + + inline void CocoaToVCL(NSPoint& rPoint, const NSRect& bounds) + { + rPoint.y = bounds.size.height - rPoint.y; + } + + inline void CocoaToVCL(NSRect& rRect, const NSRect& bounds) + { + rRect.origin.y = bounds.size.height - (rRect.origin.y + rRect.size.height); + } +} + + +@implementation DropTargetHelper + + +-(DropTargetHelper*)initWithDropTarget:(DropTarget*)pdt +{ + self = [super init]; + + if (self) + { + mDropTarget = pdt; + } + + return self; +} + + +-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender +{ + return mDropTarget->draggingEntered(sender); +} + + +-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender +{ + return mDropTarget->draggingUpdated(sender); +} + + +-(void)draggingExited:(id <NSDraggingInfo>)sender +{ + mDropTarget->draggingExited(sender); +} + + +-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender +{ + return mDropTarget->prepareForDragOperation(sender); +} + + +-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender +{ + return mDropTarget->performDragOperation(sender); +} + + +-(void)concludeDragOperation:(id <NSDraggingInfo>)sender +{ + mDropTarget->concludeDragOperation(sender); +} + + +@end + + +DropTarget::DropTarget() : + WeakComponentImplHelper5<XInitialization, XDropTarget, XDropTargetDragContext, XDropTargetDropContext, XServiceInfo>(m_aMutex), + mDropTargetHelper(nil), + mbActive(false), + mDragSourceSupportedActions(DNDConstants::ACTION_NONE), + mSelectedDropAction(DNDConstants::ACTION_NONE), + mDefaultActions(DNDConstants::ACTION_COPY_OR_MOVE | DNDConstants::ACTION_LINK | DNDConstants::ACTION_DEFAULT) +{ + mDataFlavorMapper = DataFlavorMapperPtr_t(new DataFlavorMapper()); +} + + +DropTarget::~DropTarget() +{ + [(id <DraggingDestinationHandler>)mView unregisterDraggingDestinationHandler:mDropTargetHelper]; + [mDropTargetHelper release]; +} + + +sal_Int8 DropTarget::determineDropAction(sal_Int8 dropActions, id sender) const +{ + sal_Int8 dropAct = dropActions; + bool srcAndDestEqual = false; + + if ([sender draggingSource] != nil) + { + // Internal DnD + NSView* destView = [[sender draggingDestinationWindow] contentView]; + srcAndDestEqual = (DragSource::g_DragSourceView == destView); + } + + // If ACTION_DEFAULT is set this means NSDragOperationGeneric + // has been set and we map this to ACTION_MOVE or ACTION_COPY + // depending on whether or not source and dest are equal, + // this hopefully satisfies all parties + if( (dropActions == DNDConstants::ACTION_DEFAULT) + || ((dropActions == mDragSourceSupportedActions) + && !(~mDragSourceSupportedActions & DNDConstants::ACTION_COPY_OR_MOVE ) ) ) + { + dropAct = srcAndDestEqual ? DNDConstants::ACTION_MOVE : + DNDConstants::ACTION_COPY; + } + // if more than one drop actions have been specified + // set ACTION_DEFAULT in order to let the drop target + // decide which one to use + else if (dropActions != DNDConstants::ACTION_NONE && + dropActions != DNDConstants::ACTION_MOVE && + dropActions != DNDConstants::ACTION_COPY && + dropActions != DNDConstants::ACTION_LINK) + { + if (srcAndDestEqual) + { + dropAct = dropActions; + } + else // source and destination are different + { + if (dropActions & DNDConstants::ACTION_COPY) + dropAct = DNDConstants::ACTION_COPY; + else if (dropActions & DNDConstants::ACTION_MOVE) + dropAct = DNDConstants::ACTION_MOVE; + else if (dropActions & DNDConstants::ACTION_LINK) + dropAct = DNDConstants::ACTION_LINK; + } + + dropAct |= DNDConstants::ACTION_DEFAULT; + } + + return dropAct; +} + + +NSDragOperation DropTarget::draggingEntered(id sender) +{ + // Initially when DnD will be started no modifier key can be pressed yet + // thus we are getting all actions that the drag source supports, we save + // this value because later the system masks the drag source actions if + // a modifier key will be pressed + mDragSourceSupportedActions = SystemToOfficeDragActions([sender draggingSourceOperationMask]); + + // Only if the drop target is really interessted in the drag actions + // supported by the source + if (mDragSourceSupportedActions & mDefaultActions) + { + sal_Int8 currentAction = determineDropAction(mDragSourceSupportedActions, sender); + + NSRect bounds = [mView bounds]; + NSPoint dragLocation = [sender draggedImageLocation]; + + CocoaToVCL(dragLocation, bounds); + + sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x); + sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y); + + NSPasteboard* dragPboard = [sender draggingPasteboard]; + mXCurrentDragClipboard = new AquaClipboard(dragPboard, false); + + Reference<XTransferable> xTransferable = DragSource::g_XTransferable.is() ? + DragSource::g_XTransferable : mXCurrentDragClipboard->getContents(); + + DropTargetDragEnterEvent dtdee(static_cast<OWeakObject*>(this), + 0, + this, + currentAction, + posX, + posY, + mDragSourceSupportedActions, + xTransferable->getTransferDataFlavors()); + + fire_dragEnter(dtdee); + } + + return OfficeToSystemDragActions(mSelectedDropAction); +} + + +NSDragOperation DropTarget::draggingUpdated(id sender) +{ + sal_Int8 currentDragSourceActions = + SystemToOfficeDragActions([sender draggingSourceOperationMask]); + NSDragOperation dragOp = NSDragOperationNone; + + if (currentDragSourceActions & mDefaultActions) + { + sal_Int8 currentAction = determineDropAction(currentDragSourceActions, sender); + NSRect bounds = [mView bounds]; + NSPoint dragLocation = [sender draggedImageLocation]; + + CocoaToVCL(dragLocation, bounds); + + sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x); + sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y); + + DropTargetDragEvent dtde(static_cast<OWeakObject*>(this), + 0, + this, + currentAction, + posX, + posY, + mDragSourceSupportedActions); + + fire_dragOver(dtde); + + // drag over callbacks likely have rendered something + [mView setNeedsDisplay: TRUE]; + + dragOp = OfficeToSystemDragActions(mSelectedDropAction); + + //NSLog(@"Drag update: Source actions: %x proposed action %x selected action %x", mDragSourceSupportedActions, currentAction, mSelectedDropAction); + } + + // Weird but it appears as if there is no method in Cocoa + // to create a kThemeCopyArrowCursor hence we have to use + // Carbon to do it + if (dragOp == NSDragOperationNone) + SetThemeCursor(kThemeNotAllowedCursor); + else if (dragOp == NSDragOperationCopy) + SetThemeCursor(kThemeCopyArrowCursor); + else + SetThemeCursor(kThemeArrowCursor); + + return dragOp; +} + + + void DropTarget::draggingExited(id sender) + { + DropTargetEvent dte(static_cast<OWeakObject*>(this), 0); + fire_dragExit(dte); + mDragSourceSupportedActions = DNDConstants::ACTION_NONE; + mSelectedDropAction = DNDConstants::ACTION_NONE; + SetThemeCursor(kThemeArrowCursor); + } + + + MacOSBOOL DropTarget::prepareForDragOperation(id sender) + { + return 1; + } + + +MacOSBOOL DropTarget::performDragOperation(id sender) +{ + bool bSuccess = false; + + if (mSelectedDropAction != DNDConstants::ACTION_NONE) + { + Reference<XTransferable> xTransferable = DragSource::g_XTransferable; + + if (!DragSource::g_XTransferable.is()) + { + xTransferable = mXCurrentDragClipboard->getContents(); + } + + NSRect bounds = [mView bounds]; + NSPoint dragLocation = [sender draggedImageLocation]; + + CocoaToVCL(dragLocation, bounds); + + sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x); + sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y); + + DropTargetDropEvent dtde(static_cast<OWeakObject*>(this), + 0, + this, + mSelectedDropAction, + posX, + posY, + mDragSourceSupportedActions, + xTransferable); + + fire_drop(dtde); + + bSuccess = true; + } + + return bSuccess; +} + + + void DropTarget::concludeDragOperation(id sender) + { + mDragSourceSupportedActions = DNDConstants::ACTION_NONE; + mSelectedDropAction = DNDConstants::ACTION_NONE; + mXCurrentDragClipboard = Reference<XClipboard>(); + SetThemeCursor(kThemeArrowCursor); + } + + + // called from WeakComponentImplHelperX::dispose + // WeakComponentImplHelper calls disposing before it destroys + // itself. + void SAL_CALL DropTarget::disposing() + { + } + + + void SAL_CALL DropTarget::initialize(const Sequence< Any >& aArguments) + throw(Exception) + { + if (aArguments.getLength() < 2) + { + throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("DropTarget::initialize: Cannot install window event handler")), + static_cast<OWeakObject*>(this)); + } + + Any pNSView = aArguments[0]; + sal_uInt64 tmp = 0; + pNSView >>= tmp; + mView = (id)tmp; + + mDropTargetHelper = [[DropTargetHelper alloc] initWithDropTarget: this]; + + [(id <DraggingDestinationHandler>)mView registerDraggingDestinationHandler:mDropTargetHelper]; + [mView registerForDraggedTypes: mDataFlavorMapper->getAllSupportedPboardTypes()]; + + id wnd = [mView window]; + NSWindow* parentWnd = [wnd parentWindow]; + unsigned int topWndStyle = (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask); + unsigned int wndStyles = [wnd styleMask] & topWndStyle; + + if (parentWnd == nil && (wndStyles == topWndStyle)) + { + [wnd registerDraggingDestinationHandler:mDropTargetHelper]; + [wnd registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]]; + } + } + + + void SAL_CALL DropTarget::addDropTargetListener(const Reference<XDropTargetListener>& dtl) + throw(RuntimeException) + { + rBHelper.addListener(::getCppuType(&dtl), dtl); + } + + + void SAL_CALL DropTarget::removeDropTargetListener(const Reference<XDropTargetListener>& dtl) + throw(RuntimeException) + { + rBHelper.removeListener(::getCppuType(&dtl), dtl); + } + + + sal_Bool SAL_CALL DropTarget::isActive( ) throw(RuntimeException) + { + return mbActive; + } + + + void SAL_CALL DropTarget::setActive(sal_Bool active) throw(RuntimeException) + { + mbActive = active; + } + + + sal_Int8 SAL_CALL DropTarget::getDefaultActions() throw(RuntimeException) + { + return mDefaultActions; + } + + + void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions) throw(RuntimeException) + { + OSL_ENSURE( actions < 8, "No valid default actions"); + mDefaultActions= actions; + } + + + // XDropTargetDragContext + + void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation) throw (RuntimeException) + { + mSelectedDropAction = dragOperation; + } + + + void SAL_CALL DropTarget::rejectDrag() throw (RuntimeException) + { + mSelectedDropAction = DNDConstants::ACTION_NONE; + } + + + //XDropTargetDropContext + + void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation) throw( RuntimeException) + { + mSelectedDropAction = dropOperation; + } + + + void SAL_CALL DropTarget::rejectDrop() throw (RuntimeException) + { + mSelectedDropAction = DNDConstants::ACTION_NONE; + } + + + void SAL_CALL DropTarget::dropComplete(sal_Bool success) throw (RuntimeException) + { + // Reset the internal transferable used as shortcut in case this is + // an internal D&D operation + DragSource::g_XTransferable = Reference<XTransferable>(); + DragSource::g_DropSuccessSet = true; + DragSource::g_DropSuccess = success; + } + + + void DropTarget::fire_drop( const DropTargetDropEvent& dte) + { + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) ); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); + + try { listener->drop( dte); } + catch(RuntimeException&) {} + } + } + } + + + void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e) + { + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) ); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); + + try { listener->dragEnter( e); } + catch (RuntimeException&) {} + } + } + } + + + void DropTarget::fire_dragExit(const DropTargetEvent& dte) + { + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) ); + + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); + + try { listener->dragExit( dte); } + catch (RuntimeException&) {} + } + } + } + + + void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde) + { + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) ); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer ); + while( iter.hasMoreElements()) + { + Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); + + try { listener->dragOver( dtde); } + catch (RuntimeException&) {} + } + } + } + + + void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde) + { + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) ); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); + + try { listener->dropActionChanged( dtde); } + catch (RuntimeException&) {} + } + } + } + + + // XServiceInfo + + OUString SAL_CALL DropTarget::getImplementationName() throw (RuntimeException) + { + return dropTarget_getImplementationName(); + } + + + sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) throw (RuntimeException) + { + return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget"))); + } + + + Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) throw (RuntimeException) + { + return dropTarget_getSupportedServiceNames(); + } + diff --git a/vcl/aqua/source/dtrans/DropTarget.hxx b/vcl/aqua/source/dtrans/DropTarget.hxx new file mode 100644 index 000000000000..91b50c041916 --- /dev/null +++ b/vcl/aqua/source/dtrans/DropTarget.hxx @@ -0,0 +1,172 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DropTarget.hxx,v $ + * $Revision: 1.3 $ + * + * 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 _DROPTARGET_HXX_ +#define _DROPTARGET_HXX_ + +#include "DataFlavorMapping.hxx" +#include <cppuhelper/compbase5.hxx> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp> + +#ifndef _COM_SUN_STAR_DATATRANSFER_DND_XDROPTARGETLISTENR_HPP_ +#include <com/sun/star/datatransfer/dnd/XDropTargetListener.hpp> +#endif +#include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp> +#include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp> +#include <com/sun/star/datatransfer/dnd/XDropTargetDropContext.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/basemutex.hxx> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> + +#include <boost/utility.hpp> + +#include <premac.h> +#import <Cocoa/Cocoa.h> +#include <postmac.h> + +class DropTarget; + +/* The functions declared in this protocol are actually + declared in vcl/aqua/inc/salframe.h. Because we want + to avoid importing VCL headers in UNO services and + on the other hand want to avoid warnings caused by + gcc complaining about unknowness of these functions + we declare them in a protocol here and cast at the + appropriate places. +*/ +@protocol DraggingDestinationHandler +-(void)registerDraggingDestinationHandler:(id)theHandler; +-(void)unregisterDraggingDestinationHandler:(id)theHandler; +@end + + +@interface DropTargetHelper : NSObject +{ + DropTarget* mDropTarget; +} + +-(DropTargetHelper*)initWithDropTarget:(DropTarget*)pdt; + +-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender; +-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender; +-(void)draggingExited:(id <NSDraggingInfo>)sender; +-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender; +-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender; +-(void)concludeDragOperation:(id <NSDraggingInfo>)sender; + +@end + + +class DropTarget: public cppu::BaseMutex, + public cppu::WeakComponentImplHelper5< com::sun::star::lang::XInitialization, + com::sun::star::datatransfer::dnd::XDropTarget, + com::sun::star::datatransfer::dnd::XDropTargetDragContext, + com::sun::star::datatransfer::dnd::XDropTargetDropContext, + com::sun::star::lang::XServiceInfo >, + private boost::noncopyable +{ +public: + DropTarget(); + virtual ~DropTarget(); + + // Overrides WeakComponentImplHelper::disposing which is called by + // WeakComponentImplHelper::dispose + // Must be called. + virtual void SAL_CALL disposing(); + + // XInitialization + virtual void SAL_CALL initialize( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& aArguments ) + throw(com::sun::star::uno::Exception); + + // XDropTarget + virtual void SAL_CALL addDropTargetListener( const com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDropTargetListener >& dtl ) + throw(com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL removeDropTargetListener( const com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDropTargetListener >& dtl ) + throw(com::sun::star::uno::RuntimeException); + + // Default is not active + virtual sal_Bool SAL_CALL isActive() throw(com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setActive(sal_Bool isActive) throw(com::sun::star::uno::RuntimeException); + virtual sal_Int8 SAL_CALL getDefaultActions() throw(com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setDefaultActions(sal_Int8 actions) throw(com::sun::star::uno::RuntimeException); + + // XDropTargetDragContext + virtual void SAL_CALL acceptDrag(sal_Int8 dragOperation) throw(com::sun::star::uno::RuntimeException); + virtual void SAL_CALL rejectDrag() throw(com::sun::star::uno::RuntimeException); + + // XDropTargetDragContext + virtual void SAL_CALL acceptDrop(sal_Int8 dropOperation) throw (com::sun::star::uno::RuntimeException); + virtual void SAL_CALL rejectDrop() throw (com::sun::star::uno::RuntimeException); + virtual void SAL_CALL dropComplete(sal_Bool success) throw (com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual rtl::OUString SAL_CALL getImplementationName() throw (com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService(const rtl::OUString& ServiceName) throw (com::sun::star::uno::RuntimeException); + virtual com::sun::star::uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames() throw (com::sun::star::uno::RuntimeException); + + // NSDraggingDestination protocol functions + virtual NSDragOperation draggingEntered(id sender); + virtual NSDragOperation draggingUpdated(id sender); + virtual void draggingExited(id sender); + virtual MacOSBOOL prepareForDragOperation(id sender); + virtual MacOSBOOL performDragOperation(id sender); + virtual void concludeDragOperation(id sender); + + /* If multiple actions are supported by the drag source and + the user did not choose a specific action by pressing a + modifier key choose a default action to be proposed to + the application. + */ + sal_Int8 determineDropAction(sal_Int8 dropActions, id sender) const; + +private: + void fire_drop(const com::sun::star::datatransfer::dnd::DropTargetDropEvent& dte); + void fire_dragEnter(const com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtdee); + void fire_dragExit(const com::sun::star::datatransfer::dnd::DropTargetEvent& dte); + void fire_dragOver(const com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde); + void fire_dropActionChanged(const com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde); + +private: + com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDropTargetDragContext > mXCurrentDragContext; + com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDropTargetDropContext > mXCurrentDropContext; + com::sun::star::uno::Reference< com::sun::star::datatransfer::clipboard::XClipboard > mXCurrentDragClipboard; + DataFlavorMapperPtr_t mDataFlavorMapper; + id mView; + DropTargetHelper* mDropTargetHelper; + bool mbActive; + sal_Int8 mDragSourceSupportedActions; + sal_Int8 mSelectedDropAction; + sal_Int8 mDefaultActions; +}; + +#endif diff --git a/vcl/aqua/source/dtrans/HtmlFmtFlt.cxx b/vcl/aqua/source/dtrans/HtmlFmtFlt.cxx new file mode 100644 index 000000000000..3f558b0a5b4f --- /dev/null +++ b/vcl/aqua/source/dtrans/HtmlFmtFlt.cxx @@ -0,0 +1,147 @@ +#include "HtmlFmtFlt.hxx" + +#include <rtl/string.h> + +#include <string> +#include <sstream> +#include <vector> +#include <iomanip> + +#include <boost/assert.hpp> + +using namespace com::sun::star::uno; + +//------------------------------------------------------------------------------ +// converts the openoffice text/html clipboard format to the HTML Format +// well known under MS Windows +// the MS HTML Format has a header before the real html data +// +// Version:1.0 Version number of the clipboard. Staring is 0.9 +// StartHTML: Byte count from the beginning of the clipboard to the start +// of the context, or -1 if no context +// EndHTML: Byte count from the beginning of the clipboard to the end +// of the context, or -1 if no context +// StartFragment: Byte count from the beginning of the clipboard to the +// start of the fragment +// EndFragment: Byte count from the beginning of the clipboard to the +// end of the fragment +// StartSelection: Byte count from the beginning of the clipboard to the +// start of the selection +// EndSelection: Byte count from the beginning of the clipboard to the +// end of the selection +// +// StartSelection and EndSelection are optional +// The fragment should be preceded and followed by the HTML comments +// <!--StartFragment--> and <!--EndFragment--> (no space between !-- and the +// text +//------------------------------------------------------------------------------ + +namespace // private +{ +std::string GetHtmlFormatHeader(size_t startHtml, size_t endHtml, size_t startFragment, size_t endFragment) +{ + std::ostringstream htmlHeader; + htmlHeader << "Version:1.0" << '\r' << '\n'; + htmlHeader << "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec << startHtml << '\r' << '\n'; + htmlHeader << "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec << endHtml << '\r' << '\n'; + htmlHeader << "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec << startFragment << '\r' << '\n'; + htmlHeader << "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec << endFragment << '\r' << '\n'; + return htmlHeader.str(); +} + +} // namespace private + + +// the office allways writes the start and end html tag in upper cases and +// without spaces both tags don't allow parameters +const std::string TAG_HTML = std::string("<HTML>"); +const std::string TAG_END_HTML = std::string("</HTML>"); + +// The body tag may have parameters so we need to search for the +// closing '>' manually e.g. <BODY param> #92840# +const std::string TAG_BODY = std::string("<BODY"); +const std::string TAG_END_BODY = std::string("</BODY"); + +Sequence<sal_Int8> SAL_CALL TextHtmlToHTMLFormat(Sequence<sal_Int8>& aTextHtml) +{ + OSL_ASSERT(aTextHtml.getLength() > 0); + + if (!(aTextHtml.getLength() > 0)) + return Sequence<sal_Int8>(); + + // fill the buffer with dummy values to calc the exact length + std::string dummyHtmlHeader = GetHtmlFormatHeader(0, 0, 0, 0); + size_t lHtmlFormatHeader = dummyHtmlHeader.length(); + + std::string textHtml( + reinterpret_cast<const sal_Char*>(aTextHtml.getConstArray()), + reinterpret_cast<const sal_Char*>(aTextHtml.getConstArray()) + aTextHtml.getLength()); + + std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader - 1; // we start one before '<HTML>' Word 2000 does also so + std::string::size_type nEndHtml = textHtml.find(TAG_END_HTML) + lHtmlFormatHeader + TAG_END_HTML.length() + 1; // our SOffice 5.2 wants 2 behind </HTML>? + + // The body tag may have parameters so we need to search for the + // closing '>' manually e.g. <BODY param> #92840# + std::string::size_type nStartFragment = textHtml.find(">", textHtml.find(TAG_BODY)) + lHtmlFormatHeader + 1; + std::string::size_type nEndFragment = textHtml.find(TAG_END_BODY) + lHtmlFormatHeader; + + std::string htmlFormat = GetHtmlFormatHeader(nStartHtml, nEndHtml, nStartFragment, nEndFragment); + htmlFormat += textHtml; + + Sequence<sal_Int8> byteSequence(htmlFormat.length() + 1); // space the trailing '\0' + rtl_zeroMemory(byteSequence.getArray(), byteSequence.getLength()); + + rtl_copyMemory( + static_cast<void*>(byteSequence.getArray()), + static_cast<const void*>(htmlFormat.c_str()), + htmlFormat.length()); + + return byteSequence; +} + +const char* HtmlStartTag = "<html"; + +Sequence<sal_Int8> HTMLFormatToTextHtml(const Sequence<sal_Int8>& aHTMLFormat) +{ + BOOST_ASSERT(isHTMLFormat(aHTMLFormat) && "No HTML Format provided"); + + Sequence<sal_Int8>& nonconstHTMLFormatRef = const_cast< Sequence<sal_Int8>& >(aHTMLFormat); + sal_Char* dataStart = reinterpret_cast<sal_Char*>(nonconstHTMLFormatRef.getArray()); + sal_Char* dataEnd = dataStart + nonconstHTMLFormatRef.getLength() - 1; + const sal_Char* htmlStartTag = strcasestr(dataStart, HtmlStartTag); + + BOOST_ASSERT(htmlStartTag && "Seems to be no HTML at all"); + + // It doesn't seem to be HTML? Well then simply return what has been + // provided in non-debug builds + if (htmlStartTag == NULL) + { + return aHTMLFormat; + } + + sal_Int32 len = dataEnd - htmlStartTag; + Sequence<sal_Int8> plainHtmlData(len); + + rtl_copyMemory(static_cast<void*>(plainHtmlData.getArray()), htmlStartTag, len); + + return plainHtmlData; +} + +/* A simple format detection. We are just comparing the first few bytes + of the provided byte sequence to see whether or not it is the MS + Office Html format. If it shows that this is not reliable enough we + can improve this +*/ +const char HtmlFormatStart[] = "Version:"; +int HtmlFormatStartLen = (sizeof(HtmlFormatStart) - 1); + +bool isHTMLFormat(const Sequence<sal_Int8>& aHtmlSequence) +{ + if (aHtmlSequence.getLength() < HtmlFormatStartLen) + return false; + + return rtl_str_compareIgnoreAsciiCase_WithLength(HtmlFormatStart, + HtmlFormatStartLen, + reinterpret_cast<const sal_Char*>(aHtmlSequence.getConstArray()), + HtmlFormatStartLen) == 0; +} diff --git a/vcl/aqua/source/dtrans/HtmlFmtFlt.hxx b/vcl/aqua/source/dtrans/HtmlFmtFlt.hxx new file mode 100644 index 000000000000..49f0cc70590c --- /dev/null +++ b/vcl/aqua/source/dtrans/HtmlFmtFlt.hxx @@ -0,0 +1,20 @@ +#ifndef INCLUDED_HTMLFMTFLT_HXX +#define INCLUDED_HTMLFMTFLT_HXX + +#include <com/sun/star/uno/Sequence.hxx> + +/* Transform plain HTML into the format expected by MS Office. + */ +com::sun::star::uno::Sequence<sal_Int8> TextHtmlToHTMLFormat(com::sun::star::uno::Sequence<sal_Int8>& aTextHtml); + +/* Transform the MS Office HTML format into plain HTML. + */ +com::sun::star::uno::Sequence<sal_Int8> HTMLFormatToTextHtml(const com::sun::star::uno::Sequence<sal_Int8>& aHTMLFormat); + +/* Detects whether the given byte sequence contains the MS Office Html format. + + @returns True if the MS Office Html format will be detected False otherwise. + */ +bool isHTMLFormat (const com::sun::star::uno::Sequence<sal_Int8>& aHtmlSequence); + +#endif diff --git a/vcl/aqua/source/dtrans/OSXTransferable.cxx b/vcl/aqua/source/dtrans/OSXTransferable.cxx new file mode 100644 index 000000000000..a893f09d89cc --- /dev/null +++ b/vcl/aqua/source/dtrans/OSXTransferable.cxx @@ -0,0 +1,215 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: OSXTransferable.cxx,v $ + * $Revision: 1.4 $ + * + * 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 <sal/types.h> + +#ifndef _TRANSFERABLE_HXX_ +#include "OSXTransferable.hxx" +#endif + +#include "DataFlavorMapping.hxx" + +using namespace rtl; +using namespace std; +using namespace osl; +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::datatransfer; +using namespace com::sun::star::io; +using namespace com::sun::star::lang; +using namespace com::sun::star::container; + +const Type CPPUTYPE_SEQINT8 = getCppuType((Sequence<sal_Int8>*)0); +const Type CPPUTYPE_OUSTRING = getCppuType((OUString*)0); + +namespace // private +{ + bool isValidFlavor( const DataFlavor& aFlavor ) + { + size_t len = aFlavor.MimeType.getLength(); + Type dtype = aFlavor.DataType; + return ((len > 0) && ((dtype == CPPUTYPE_SEQINT8) || (dtype == CPPUTYPE_OUSTRING))); + } + +} // namespace private + + +OSXTransferable::OSXTransferable(const Reference<XMimeContentTypeFactory> rXMimeCntFactory, + DataFlavorMapperPtr_t pDataFlavorMapper, + NSPasteboard* pasteboard) : + mrXMimeCntFactory(rXMimeCntFactory), + mDataFlavorMapper(pDataFlavorMapper), + mPasteboard(pasteboard) +{ + [mPasteboard retain]; + + initClipboardItemList(); +} + + +OSXTransferable::~OSXTransferable() +{ + [mPasteboard release]; +} + + +Any SAL_CALL OSXTransferable::getTransferData( const DataFlavor& aFlavor ) + throw( UnsupportedFlavorException, IOException, RuntimeException ) +{ + if (!isValidFlavor(aFlavor) || !isDataFlavorSupported(aFlavor)) + { + throw UnsupportedFlavorException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Unsupported data flavor")), + static_cast<XTransferable*>(this)); + } + + NSString* sysFormat = (NSString*)mDataFlavorMapper->openOfficeToSystemFlavor(aFlavor); + DataProviderPtr_t dp; + + if ([sysFormat caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame) + { + NSArray* sysData = [mPasteboard propertyListForType: sysFormat]; + dp = mDataFlavorMapper->getDataProvider(sysFormat, sysData); + } + else + { + NSData* sysData = [mPasteboard dataForType: sysFormat]; + dp = mDataFlavorMapper->getDataProvider(sysFormat, sysData); + } + + if (dp.get() == NULL) + { + throw UnsupportedFlavorException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Unsupported data flavor")), + static_cast<XTransferable*>(this)); + } + + return dp->getOOoData(); +} + + +bool OSXTransferable::isUnicodeText(const DataFlavor& flavor) +{ + return (flavor.DataType == CPPUTYPE_OUSTRING); +} + + +Sequence< DataFlavor > SAL_CALL OSXTransferable::getTransferDataFlavors( ) + throw( RuntimeException ) +{ + return mFlavorList; +} + + +sal_Bool SAL_CALL OSXTransferable::isDataFlavorSupported(const DataFlavor& aFlavor) + throw( RuntimeException ) +{ + for (sal_Int32 i = 0; i < mFlavorList.getLength(); i++) + if (compareDataFlavors(aFlavor, mFlavorList[i])) + return sal_True; + + return sal_False; +} + + +void OSXTransferable::initClipboardItemList() +{ + NSArray* pboardFormats = [mPasteboard types]; + + if (pboardFormats == NULL) + { + throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot get clipboard data")), + static_cast<XTransferable*>(this)); + } + + mFlavorList = mDataFlavorMapper->typesArrayToFlavorSequence(pboardFormats); +} + + +/* Compares two DataFlavors. Returns true if both DataFlavor have the same media type + and the number of parameter and all parameter values do match otherwise false + is returned. + */ +bool OSXTransferable::compareDataFlavors(const DataFlavor& lhs, const DataFlavor& rhs ) +{ + try + { + Reference<XMimeContentType> xLhs(mrXMimeCntFactory->createMimeContentType(lhs.MimeType)); + Reference<XMimeContentType> xRhs(mrXMimeCntFactory->createMimeContentType(rhs.MimeType)); + + if (!xLhs->getFullMediaType().equalsIgnoreAsciiCase(xRhs->getFullMediaType()) || + !cmpAllContentTypeParameter(xLhs, xRhs)) + { + return false; + } + } + catch( IllegalArgumentException& ) + { + OSL_ENSURE( sal_False, "Invalid content type detected" ); + return false; + } + + return true; +} + + +bool OSXTransferable::cmpAllContentTypeParameter(const Reference<XMimeContentType> xLhs, + const Reference<XMimeContentType> xRhs) const +{ + Sequence<OUString> xLhsFlavors = xLhs->getParameters(); + Sequence<OUString> xRhsFlavors = xRhs->getParameters(); + + // Stop here if the number of parameters is different already + if (xLhsFlavors.getLength() != xRhsFlavors.getLength()) + return false; + + try + { + OUString pLhs; + OUString pRhs; + + for (sal_Int32 i = 0; i < xLhsFlavors.getLength(); i++) + { + pLhs = xLhs->getParameterValue(xLhsFlavors[i]); + pRhs = xRhs->getParameterValue(xLhsFlavors[i]); + + if (!pLhs.equalsIgnoreAsciiCase(pRhs)) + { + return false; + } + } + } + catch(IllegalArgumentException&) + { + return false; + } + + return true; +} diff --git a/vcl/aqua/source/dtrans/OSXTransferable.hxx b/vcl/aqua/source/dtrans/OSXTransferable.hxx new file mode 100644 index 000000000000..9b371523c440 --- /dev/null +++ b/vcl/aqua/source/dtrans/OSXTransferable.hxx @@ -0,0 +1,103 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: OSXTransferable.hxx,v $ + * $Revision: 1.4 $ + * + * 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 _TRANSFERABLE_HXX_ +#define _TRANSFERABLE_HXX_ + +//------------------------------------------------------------------------ +// includes +//------------------------------------------------------------------------ + +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <cppuhelper/implbase1.hxx> +#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp> +#include <com/sun/star/datatransfer/XMimeContentType.hpp> + +#include "DataFlavorMapping.hxx" + +#include <premac.h> +#import <Cocoa/Cocoa.h> +#include <postmac.h> + +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> +#include <vector> + + +class OSXTransferable : public ::cppu::WeakImplHelper1<com::sun::star::datatransfer::XTransferable>, + private ::boost::noncopyable +{ +public: + typedef com::sun::star::uno::Sequence< sal_Int8 > ByteSequence_t; + + explicit OSXTransferable(com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XMimeContentTypeFactory> rXMimeCntFactory, + DataFlavorMapperPtr_t pDataFlavorMapper, + NSPasteboard* pasteboard); + + virtual ~OSXTransferable(); + + //------------------------------------------------------------------------ + // 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 ); + + //------------------------------------------------------------------------ + // Helper functions not part of the XTransferable interface + //------------------------------------------------------------------------ + + void initClipboardItemList(); + + //com::sun::star::uno::Any getClipboardItemData(ClipboardItemPtr_t clipboardItem); + + bool isUnicodeText(const com::sun::star::datatransfer::DataFlavor& flavor); + + bool compareDataFlavors( const com::sun::star::datatransfer::DataFlavor& lhs, + const com::sun::star::datatransfer::DataFlavor& rhs ); + + bool cmpAllContentTypeParameter( const com::sun::star::uno::Reference< com::sun::star::datatransfer::XMimeContentType > xLhs, + const com::sun::star::uno::Reference< com::sun::star::datatransfer::XMimeContentType > xRhs ) const; + +private: + com::sun::star::uno::Sequence< com::sun::star::datatransfer::DataFlavor > mFlavorList; + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XMimeContentTypeFactory> mrXMimeCntFactory; + DataFlavorMapperPtr_t mDataFlavorMapper; + NSPasteboard* mPasteboard; +}; + +#endif diff --git a/vcl/aqua/source/dtrans/PictToBmpFlt.cxx b/vcl/aqua/source/dtrans/PictToBmpFlt.cxx new file mode 100644 index 000000000000..0643efae33ca --- /dev/null +++ b/vcl/aqua/source/dtrans/PictToBmpFlt.cxx @@ -0,0 +1,114 @@ +#include "PictToBmpFlt.hxx" + +/* This is a work-around to prevent 'deprecated' warning for 'KillPicture' API + Hopefully we can get rid of this whole code again when the OOo PICT filter + are good enough to be used see #i78953 thus this hack would vanish to again. + */ +#include <AvailabilityMacros.h> +#undef DEPRECATED_ATTRIBUTE +#define DEPRECATED_ATTRIBUTE + +#include <premac.h> +#include <Carbon/Carbon.h> +#include <QuickTime/QuickTime.h> +#include <postmac.h> + + +bool PICTtoBMP(com::sun::star::uno::Sequence<sal_Int8>& aPict, + com::sun::star::uno::Sequence<sal_Int8>& aBmp) +{ + bool result = false; + + ComponentInstance bmpExporter; + if (OpenADefaultComponent(GraphicsExporterComponentType, + kQTFileTypeBMP, + &bmpExporter) != noErr) + { + return result; + } + + Handle hPict; + if (PtrToHand(aPict.getArray(), &hPict, aPict.getLength()) != noErr) + { + return result; + } + + Handle hBmp; + if ((GraphicsExportSetInputPicture(bmpExporter, (PicHandle)hPict) != noErr) || + ((hBmp = NewHandleClear(0)) == NULL)) + { + CloseComponent(bmpExporter); + DisposeHandle(hPict); + return result; + } + + if ((GraphicsExportSetOutputHandle(bmpExporter, hBmp) == noErr) && + (GraphicsExportDoExport(bmpExporter, NULL) == noErr)) + { + size_t sz = GetHandleSize(hBmp); + aBmp.realloc(sz); + + HLock(hBmp); + rtl_copyMemory(aBmp.getArray(), ((sal_Int8*)*hBmp), sz); + HUnlock(hBmp); + + result = true; + } + + DisposeHandle(hPict); + DisposeHandle(hBmp); + CloseComponent(bmpExporter); + + return result; +} + +bool BMPtoPICT(com::sun::star::uno::Sequence<sal_Int8>& aBmp, + com::sun::star::uno::Sequence<sal_Int8>& aPict) +{ + bool result = false; + + Handle hBmp; + ComponentInstance pictExporter; + if ((PtrToHand(aBmp.getArray(), &hBmp, aBmp.getLength()) != noErr)) + { + return result; + } + + if (OpenADefaultComponent(GraphicsImporterComponentType, + kQTFileTypeBMP, + &pictExporter) != noErr) + { + DisposeHandle(hBmp); + return result; + } + + if (GraphicsImportSetDataHandle(pictExporter, hBmp) != noErr) + { + DisposeHandle(hBmp); + CloseComponent(pictExporter); + return result; + } + + PicHandle hPict; + if (GraphicsImportGetAsPicture(pictExporter, &hPict) == noErr) + { + size_t sz = GetHandleSize((Handle)hPict); + aPict.realloc(sz); + + HLock((Handle)hPict); + rtl_copyMemory(aPict.getArray(), ((sal_Int8*)*hPict), sz); + HUnlock((Handle)hPict); + + // Release the data associated with the picture + // Note: This function is deprecated in Mac OS X + // 10.4. + KillPicture(hPict); + + result = true; + } + + DisposeHandle(hBmp); + CloseComponent(pictExporter); + + return result; +} diff --git a/vcl/aqua/source/dtrans/PictToBmpFlt.hxx b/vcl/aqua/source/dtrans/PictToBmpFlt.hxx new file mode 100644 index 000000000000..29e9c535546f --- /dev/null +++ b/vcl/aqua/source/dtrans/PictToBmpFlt.hxx @@ -0,0 +1,22 @@ +#ifndef INCLUDED_PICTTOBMPFLT_HXX +#define INCLUDED_PICTTOBMPFLT_HXX + +#include <com/sun/star/uno/Sequence.hxx> + +/* Transform PICT into the a Window BMP. + + Returns true if the conversion was successful false + otherwise. + */ +bool PICTtoBMP(com::sun::star::uno::Sequence<sal_Int8>& aPict, + com::sun::star::uno::Sequence<sal_Int8>& aBmp); + +/* Transform a Windows BMP to a PICT. + + Returns true if the conversion was successful false + otherwise. + */ +bool BMPtoPICT(com::sun::star::uno::Sequence<sal_Int8>& aBmp, + com::sun::star::uno::Sequence<sal_Int8>& aPict); + +#endif diff --git a/vcl/aqua/source/dtrans/aqua_clipboard.cxx b/vcl/aqua/source/dtrans/aqua_clipboard.cxx new file mode 100644 index 000000000000..27bf308dce9b --- /dev/null +++ b/vcl/aqua/source/dtrans/aqua_clipboard.cxx @@ -0,0 +1,385 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: aqua_clipboard.cxx,v $ + * $Revision: 1.8 $ + * + * 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 "aqua_clipboard.hxx" + +#include "DataFlavorMapping.hxx" +#include "OSXTransferable.hxx" + +#include "vcl/unohelp.hxx" + +#include "comphelper/makesequence.hxx" + +#include <boost/assert.hpp> + +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 cppu; +using namespace osl; +using namespace rtl; +using namespace std; +using namespace comphelper; + + +@implementation EventListener; + +-(EventListener*)initWithAquaClipboard: (AquaClipboard*) pcb +{ + self = [super init]; + + if (self) + pAquaClipboard = pcb; + + return self; +} + +-(void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString*)type +{ + if( pAquaClipboard ) + pAquaClipboard->provideDataForType(sender, type); +} + +-(void)applicationDidBecomeActive:(NSNotification*)aNotification +{ + if( pAquaClipboard ) + pAquaClipboard->applicationDidBecomeActive(aNotification); +} + +-(void)disposing +{ + pAquaClipboard = NULL; +} + +@end + + +OUString clipboard_getImplementationName() +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.clipboard.AquaClipboard")); +} + +Sequence<OUString> clipboard_getSupportedServiceNames() +{ + return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.clipboard.SystemClipboard"))); +} + + +AquaClipboard::AquaClipboard(NSPasteboard* pasteboard, bool bUseSystemPasteboard) : + WeakComponentImplHelper4<XClipboardEx, XClipboardNotifier, XFlushableClipboard, XServiceInfo>(m_aMutex), + mIsSystemPasteboard(bUseSystemPasteboard) +{ + Reference<XMultiServiceFactory> mrServiceMgr = vcl::unohelper::GetMultiServiceFactory(); + + mrXMimeCntFactory = Reference<XMimeContentTypeFactory>(mrServiceMgr->createInstance( + OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.MimeContentTypeFactory"))), UNO_QUERY); + + if (!mrXMimeCntFactory.is()) + { + throw RuntimeException(OUString( + RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create com.sun.star.datatransfer.MimeContentTypeFactory")), + static_cast<XClipboardEx*>(this)); + } + + mpDataFlavorMapper = DataFlavorMapperPtr_t(new DataFlavorMapper()); + + if (pasteboard != NULL) + { + mPasteboard = pasteboard; + mIsSystemPasteboard = false; + } + else + { + mPasteboard = bUseSystemPasteboard ? [NSPasteboard generalPasteboard] : + [NSPasteboard pasteboardWithName: NSDragPboard]; + + if (mPasteboard == nil) + { + throw RuntimeException(OUString( + RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create Cocoa pasteboard")), + static_cast<XClipboardEx*>(this)); + } + } + + [mPasteboard retain]; + + mEventListener = [[EventListener alloc] initWithAquaClipboard: this]; + + if (mEventListener == nil) + { + [mPasteboard release]; + + throw RuntimeException( + OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create pasteboard change listener")), + static_cast<XClipboardEx*>(this)); + } + + if (mIsSystemPasteboard) + { + NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter]; + + [notificationCenter addObserver: mEventListener + selector: @selector(applicationDidBecomeActive:) + name: @"NSApplicationDidBecomeActiveNotification" + object: [NSApplication sharedApplication]]; + } + + mPasteboardChangeCount = [mPasteboard changeCount]; +} + + +AquaClipboard::~AquaClipboard() +{ + if (mIsSystemPasteboard) + { + [[NSNotificationCenter defaultCenter] removeObserver: mEventListener]; + } + + [mEventListener disposing]; + [mEventListener release]; + [mPasteboard release]; +} + + +Reference<XTransferable> SAL_CALL AquaClipboard::getContents() throw(RuntimeException) +{ + MutexGuard aGuard(m_aMutex); + + // Shortcut: If we are clipboard owner already we don't need + // to drag the data through the system clipboard + if (mXClipboardContent.is()) + { + return mXClipboardContent; + } + + return Reference<XTransferable>(new OSXTransferable(mrXMimeCntFactory, + mpDataFlavorMapper, + mPasteboard)); +} + + +void SAL_CALL AquaClipboard::setContents(const Reference<XTransferable>& xTransferable, + const Reference<XClipboardOwner>& xClipboardOwner) + throw( RuntimeException ) +{ + ClearableMutexGuard aGuard(m_aMutex); + + Reference<XClipboardOwner> oldOwner(mXClipboardOwner); + mXClipboardOwner = xClipboardOwner; + + Reference<XTransferable> oldContent(mXClipboardContent); + mXClipboardContent = xTransferable; + + NSArray* types = mXClipboardContent.is() ? + mpDataFlavorMapper->flavorSequenceToTypesArray(mXClipboardContent->getTransferDataFlavors()) : + [NSArray array]; + mPasteboardChangeCount = [mPasteboard declareTypes: types owner: mEventListener]; + + // if we are already the owner of the clipboard + // then fire lost ownership event + if (oldOwner.is()) + { + fireLostClipboardOwnershipEvent(oldOwner, oldContent); + } + + fireClipboardChangedEvent(); +} + + +OUString SAL_CALL AquaClipboard::getName() throw( RuntimeException ) +{ + return OUString(); +} + + +sal_Int8 SAL_CALL AquaClipboard::getRenderingCapabilities() throw( RuntimeException ) +{ + return 0; +} + + +void SAL_CALL AquaClipboard::addClipboardListener(const Reference< XClipboardListener >& listener) + throw( RuntimeException ) +{ + MutexGuard aGuard(m_aMutex); + + if (!listener.is()) + throw IllegalArgumentException(OUString(RTL_CONSTASCII_USTRINGPARAM("empty reference")), + static_cast<XClipboardEx*>(this), 1); + + mClipboardListeners.push_back(listener); +} + + +void SAL_CALL AquaClipboard::removeClipboardListener(const Reference< XClipboardListener >& listener) + throw( RuntimeException ) +{ + MutexGuard aGuard(m_aMutex); + + if (!listener.is()) + throw IllegalArgumentException(OUString(RTL_CONSTASCII_USTRINGPARAM("empty reference")), + static_cast<XClipboardEx*>(this), 1); + + mClipboardListeners.remove(listener); +} + + +void AquaClipboard::applicationDidBecomeActive(NSNotification* aNotification) +{ + MutexGuard aGuard(m_aMutex); + + int currentPboardChgCount = [mPasteboard changeCount]; + + if (currentPboardChgCount != mPasteboardChangeCount) + { + mPasteboardChangeCount = currentPboardChgCount; + + // Clear clipboard content and owner and send lostOwnership + // notification to the old clipboard owner as well as + // ClipboardChanged notification to any clipboard listener + Reference<XClipboardOwner> oldOwner(mXClipboardOwner); + mXClipboardOwner = Reference<XClipboardOwner>(); + + Reference<XTransferable> oldContent(mXClipboardContent); + mXClipboardContent = Reference<XTransferable>(); + + if (oldOwner.is()) + { + fireLostClipboardOwnershipEvent(oldOwner, oldContent); + } + + fireClipboardChangedEvent(); + } +} + + +void AquaClipboard::fireClipboardChangedEvent() +{ + ClearableMutexGuard aGuard(m_aMutex); + + list<Reference< XClipboardListener > > listeners(mClipboardListeners); + ClipboardEvent aEvent; + + if (listeners.begin() != listeners.end()) + { + aEvent = ClipboardEvent(static_cast<OWeakObject*>(this), getContents()); + } + + aGuard.clear(); + + while (listeners.begin() != listeners.end()) + { + if (listeners.front().is()) + { + try { listeners.front()->changedContents(aEvent); } + catch (RuntimeException&) { } + } + listeners.pop_front(); + } +} + + +void AquaClipboard::fireLostClipboardOwnershipEvent(Reference<XClipboardOwner> oldOwner, Reference<XTransferable> oldContent) +{ + BOOST_ASSERT(oldOwner.is()); + + try { oldOwner->lostOwnership(static_cast<XClipboardEx*>(this), oldContent); } + catch(RuntimeException&) { } +} + + +void AquaClipboard::provideDataForType(NSPasteboard* sender, NSString* type) +{ + DataProviderPtr_t dp = mpDataFlavorMapper->getDataProvider(type, mXClipboardContent); + NSData* pBoardData = NULL; + + if (dp.get() != NULL) + { + pBoardData = (NSData*)dp->getSystemData(); + [sender setData: pBoardData forType: type]; + } +} + + +//------------------------------------------------ +// XFlushableClipboard +//------------------------------------------------ + +void SAL_CALL AquaClipboard::flushClipboard() + throw(RuntimeException) +{ + if (mXClipboardContent.is()) + { + Sequence<DataFlavor> flavorList = mXClipboardContent->getTransferDataFlavors(); + sal_uInt32 nFlavors = flavorList.getLength(); + + for (sal_uInt32 i = 0; i < nFlavors; i++) + { + NSString* sysType = mpDataFlavorMapper->openOfficeToSystemFlavor(flavorList[i]); + + if (sysType != NULL) + { + provideDataForType(mPasteboard, sysType); + } + } + } +} + + +NSPasteboard* AquaClipboard::getPasteboard() const +{ + return mPasteboard; +} + + +//------------------------------------------------- +// XServiceInfo +//------------------------------------------------- + +OUString SAL_CALL AquaClipboard::getImplementationName() throw( RuntimeException ) +{ + return clipboard_getImplementationName(); +} + + +sal_Bool SAL_CALL AquaClipboard::supportsService( const OUString& ServiceName ) throw( RuntimeException ) +{ + return sal_False; +} + + +Sequence< OUString > SAL_CALL AquaClipboard::getSupportedServiceNames() throw( RuntimeException ) +{ + return clipboard_getSupportedServiceNames(); +} + diff --git a/vcl/aqua/source/dtrans/aqua_clipboard.hxx b/vcl/aqua/source/dtrans/aqua_clipboard.hxx new file mode 100644 index 000000000000..90bb404fdb36 --- /dev/null +++ b/vcl/aqua/source/dtrans/aqua_clipboard.hxx @@ -0,0 +1,184 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: aqua_clipboard.hxx,v $ + * $Revision: 1.9 $ + * + * 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 _AQUA_CLIPBOARD_HXX_ +#define _AQUA_CLIPBOARD_HXX_ + +#include "DataFlavorMapping.hxx" +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <cppuhelper/compbase4.hxx> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboardListener.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp> +#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp> +#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/basemutex.hxx> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> + +#include <boost/utility.hpp> +#include <list> + +#include <premac.h> +#import <Cocoa/Cocoa.h> +#include <postmac.h> + +class AquaClipboard; + +@interface EventListener : NSObject +{ + AquaClipboard* pAquaClipboard; +} + +// Init the pasteboard change listener with a reference to the OfficeClipboard +// instance +- (EventListener*)initWithAquaClipboard: (AquaClipboard*) pcb; + +// Promiss resolver function +- (void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString *)type; + +-(void)applicationDidBecomeActive:(NSNotification*)aNotification; + +-(void)disposing; +@end + + +class AquaClipboard : public ::cppu::BaseMutex, + public ::cppu::WeakComponentImplHelper4< com::sun::star::datatransfer::clipboard::XClipboardEx, + com::sun::star::datatransfer::clipboard::XClipboardNotifier, + com::sun::star::datatransfer::clipboard::XFlushableClipboard, + com::sun::star::lang::XServiceInfo >, + private ::boost::noncopyable +{ +public: + /* Create a clipboard instance. + + @param pasteboard + If not equal NULL the instance will be instantiated with the provided + pasteboard reference and 'bUseSystemClipboard' will be ignored + + @param bUseSystemClipboard + If 'pasteboard' is NULL 'bUseSystemClipboard' determines whether the + system clipboard will be created (bUseSystemClipboard == true) or if + the DragPasteboard if bUseSystemClipboard == false + */ + AquaClipboard(NSPasteboard* pasteboard = NULL, + bool bUseSystemClipboard = true); + + ~AquaClipboard(); + + //------------------------------------------------ + // XClipboard + //------------------------------------------------ + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > SAL_CALL getContents() + throw( ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL setContents( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTransferable, + const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner ) + throw( ::com::sun::star::uno::RuntimeException ); + + virtual ::rtl::OUString SAL_CALL getName() + throw( ::com::sun::star::uno::RuntimeException ); + + //------------------------------------------------ + // XClipboardEx + //------------------------------------------------ + + virtual sal_Int8 SAL_CALL getRenderingCapabilities() + throw( ::com::sun::star::uno::RuntimeException ); + + //------------------------------------------------ + // XClipboardNotifier + //------------------------------------------------ + + virtual void SAL_CALL addClipboardListener( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener ) + throw( ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL removeClipboardListener( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener ) + throw( ::com::sun::star::uno::RuntimeException ); + + //------------------------------------------------ + // XFlushableClipboard + //------------------------------------------------ + + virtual void SAL_CALL flushClipboard( ) throw( com::sun::star::uno::RuntimeException ); + + //------------------------------------------------ + // XServiceInfo + //------------------------------------------------ + + virtual ::rtl::OUString SAL_CALL getImplementationName() + throw(::com::sun::star::uno::RuntimeException); + + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw(::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() + throw(::com::sun::star::uno::RuntimeException); + + /* Get a reference to the used pastboard. + */ + NSPasteboard* getPasteboard() const; + + /* Notify the current clipboard owner that he is no longer the clipboard owner. + */ + void fireLostClipboardOwnershipEvent(::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner> oldOwner, + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > oldContent); + + void pasteboardChangedOwner(); + + void provideDataForType(NSPasteboard* sender, NSString* type); + + void applicationDidBecomeActive(NSNotification* aNotification); + +private: + + /* Notify all registered XClipboardListener that the clipboard content + has changed. + */ + void fireClipboardChangedEvent(); + +private: + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XMimeContentTypeFactory > mrXMimeCntFactory; + ::std::list< ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener > > mClipboardListeners; + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > mXClipboardContent; + com::sun::star::uno::Reference< com::sun::star::datatransfer::clipboard::XClipboardOwner > mXClipboardOwner; + DataFlavorMapperPtr_t mpDataFlavorMapper; + bool mIsSystemPasteboard; + NSPasteboard* mPasteboard; + int mPasteboardChangeCount; + EventListener* mEventListener; +}; + +#endif diff --git a/vcl/aqua/source/dtrans/aqua_service.cxx b/vcl/aqua/source/dtrans/aqua_service.cxx new file mode 100644 index 000000000000..aeaf697670ef --- /dev/null +++ b/vcl/aqua/source/dtrans/aqua_service.cxx @@ -0,0 +1,111 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: aqua_service.cxx,v $ + * $Revision: 1.8 $ + * + * 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 "aqua_clipboard.hxx" +#include <cppuhelper/factory.hxx> +#include <com/sun/star/container/XSet.hpp> +#include <osl/diagnose.h> + +using namespace rtl; +using namespace com::sun::star::uno; +using namespace com::sun::star::registry; +using namespace cppu; +using namespace com::sun::star::lang; +using namespace com::sun::star::datatransfer::clipboard; +using namespace aqua; + +namespace aqua { + +Reference< XInterface > SAL_CALL createInstance( const Reference< XMultiServiceFactory >& rServiceManager ) +{ + return Reference< XInterface >( static_cast< XClipboard* >( new AquaClipboard(rServiceManager) ) ); +} + +} // namespace aqua + +extern "C" +{ + +void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +sal_Bool SAL_CALL component_writeInfo( void* pServiceManager, void* pRegistryKey ) +{ + sal_Bool bRetVal = sal_False; + + if ( pRegistryKey ) + { + try + { + Reference< XRegistryKey > pXNewKey( static_cast< XRegistryKey* >( pRegistryKey ) ); + pXNewKey->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM( AQUA_CLIPBOARD_REGKEY_NAME ) ) ); + bRetVal = sal_True; + } + catch( InvalidRegistryException& ) + { + OSL_ENSURE(sal_False, "InvalidRegistryException caught"); + bRetVal = sal_False; + } + } + + return bRetVal; +} + +void* SAL_CALL component_getFactory( const sal_Char* pImplName, uno_Interface* pSrvManager, uno_Interface* pRegistryKey ) +{ + void* pRet = 0; + + if ( pSrvManager && ( 0 == rtl_str_compare( pImplName, AQUA_CLIPBOARD_IMPL_NAME ) ) ) + { + Sequence< OUString > aSNS( 1 ); + aSNS.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( AQUA_CLIPBOARD_SERVICE_NAME ) ); + + //OUString( RTL_CONSTASCII_USTRINGPARAM( FPS_IMPL_NAME ) ) + Reference< XSingleServiceFactory > xFactory ( createOneInstanceFactory( + reinterpret_cast< XMultiServiceFactory* > ( pSrvManager ), + OUString::createFromAscii( pImplName ), + createInstance, + aSNS ) ); + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +} + +} // extern "C" diff --git a/vcl/aqua/source/dtrans/makefile.mk b/vcl/aqua/source/dtrans/makefile.mk new file mode 100644 index 000000000000..e802c98abf64 --- /dev/null +++ b/vcl/aqua/source/dtrans/makefile.mk @@ -0,0 +1,72 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.14 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=vcl +TARGET=dtransaqua +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# ------------------------------------------------------------------ + +.IF "$(OS)"!="MACOSX" +dummy: + @echo "Nothing to build for this platform" +.ELSE # "$(OS)"!="MACOSX" +.IF "$(GUIBASE)"!="aqua" +dummy: + @echo "Nothing to build for GUIBASE $(GUIBASE)" +.ELSE + +CFLAGSCXX+=-fconstant-cfstrings -x objective-c++ -fobjc-exceptions + +SLOFILES= \ + $(SLO)$/aqua_clipboard.obj \ + $(SLO)$/DataFlavorMapping.obj \ + $(SLO)$/OSXTransferable.obj \ + $(SLO)$/HtmlFmtFlt.obj \ + $(SLO)$/PictToBmpFlt.obj \ + $(SLO)$/DropTarget.obj \ + $(SLO)$/DragSource.obj \ + $(SLO)$/service_entry.obj \ + $(SLO)$/DragSourceContext.obj \ + $(SLO)$/DragActionConversion.obj + +# --- Targets ------------------------------------------------------ +.INCLUDE : target.mk + +.ENDIF # "$(GUIBASE)"!="aqua" +.ENDIF # "$(OS)"!="MACOSX" + diff --git a/vcl/aqua/source/dtrans/service_entry.cxx b/vcl/aqua/source/dtrans/service_entry.cxx new file mode 100644 index 000000000000..38784ecb53dd --- /dev/null +++ b/vcl/aqua/source/dtrans/service_entry.cxx @@ -0,0 +1,67 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: service_entry.cxx,v $ + * $Revision: 1.3 $ + * + * 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 "saldata.hxx" +#include "salinst.h" +#include "DragSource.hxx" +#include "DropTarget.hxx" +#include "aqua_clipboard.hxx" +#include "osl/diagnose.h" + +using namespace ::osl; +using namespace ::rtl; +using namespace ::com::sun::star::uno; +using namespace ::cppu; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::datatransfer::clipboard; + + +Reference< XInterface > AquaSalInstance::CreateClipboard( const Sequence< Any >& i_rArguments ) +{ + SalData* pSalData = GetSalData(); + if( ! pSalData->mxClipboard.is() ) + pSalData->mxClipboard = Reference<XInterface>(static_cast< XClipboard* >(new AquaClipboard()), UNO_QUERY); + return pSalData->mxClipboard; +} + + +Reference<XInterface> AquaSalInstance::CreateDragSource() +{ + return Reference<XInterface>(static_cast< XInitialization* >(new DragSource()), UNO_QUERY); +} + +Reference<XInterface> AquaSalInstance::CreateDropTarget() +{ + return Reference<XInterface>(static_cast< XInitialization* >(new DropTarget()), UNO_QUERY); +} + diff --git a/vcl/aqua/source/dtrans/test_aquacb.cxx b/vcl/aqua/source/dtrans/test_aquacb.cxx new file mode 100644 index 000000000000..db60712ce852 --- /dev/null +++ b/vcl/aqua/source/dtrans/test_aquacb.cxx @@ -0,0 +1,211 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: test_aquacb.cxx,v $ + * $Revision: 1.6 $ + * + * 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 "aqua_clipboard.hxx" +#include <cppuhelper/servicefactory.hxx> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp> +#include <com/sun/star/lang/XComponent.hpp> + +#ifndef _CPPUHELPER_IMPLBASE1_HXX_ +#include <cppuhelper/implbase2.hxx> +#endif +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <osl/diagnose.h> + +#include <stdio.h> + +using namespace ::rtl; +using namespace ::std; +using namespace ::cppu; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::clipboard; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; + +Reference< XTransferable > rXTransfRead; + +class TestTransferable : public WeakImplHelper2< XClipboardOwner, XTransferable > +{ +public: + TestTransferable(); + virtual Any SAL_CALL getTransferData( const DataFlavor& aFlavor ) throw(UnsupportedFlavorException, IOException, RuntimeException); + virtual Sequence< DataFlavor > SAL_CALL getTransferDataFlavors() throw(RuntimeException); + virtual sal_Bool SAL_CALL isDataFlavorSupported( const DataFlavor& aFlavor ) throw(RuntimeException); + virtual void SAL_CALL lostOwnership( const Reference< XClipboard >& xClipboard, const Reference< XTransferable >& xTrans ) throw(RuntimeException); + +private: + Sequence< DataFlavor > m_seqDFlv; + OUString m_Data; +}; + +TestTransferable::TestTransferable() : + m_seqDFlv( 1 ), + m_Data( RTL_CONSTASCII_USTRINGPARAM( "This is a test string" ) ) +{ + DataFlavor df; + + df.MimeType = OUString::createFromAscii( "text/html" ); + df.DataType = getCppuType( ( Sequence< sal_Int8 >* )0 ); + + m_seqDFlv[0] = df; +} + +Any SAL_CALL TestTransferable::getTransferData( const DataFlavor& aFlavor ) + throw(UnsupportedFlavorException, IOException, RuntimeException) +{ + Any anyData; + + if ( aFlavor.MimeType == m_seqDFlv[0].MimeType ) + { + OString aStr( m_Data.getStr(), m_Data.getLength(), 1252 ); + Sequence< sal_Int8 > sOfChars( aStr.getLength() ); + sal_Int32 lenStr = aStr.getLength(); + + for ( sal_Int32 i = 0; i < lenStr; ++i ) + sOfChars[i] = aStr[i]; + + anyData = makeAny( sOfChars ); + } + + return anyData; +} + +Sequence< DataFlavor > SAL_CALL TestTransferable::getTransferDataFlavors() + throw(RuntimeException) +{ + return m_seqDFlv; +} + +sal_Bool SAL_CALL TestTransferable::isDataFlavorSupported( const DataFlavor& aFlavor ) + throw(RuntimeException) +{ + sal_Int32 nLength = m_seqDFlv.getLength(); + sal_Bool bRet = sal_False; + + for ( sal_Int32 i = 0; i < nLength; ++i ) + { + if ( m_seqDFlv[i].MimeType == aFlavor.MimeType ) + { + bRet = sal_True; + break; + } + } + + return bRet; +} + +void SAL_CALL TestTransferable::lostOwnership( const Reference< XClipboard >& xClipboard, const Reference< XTransferable >& xTrans ) + throw(RuntimeException) +{ +} + +int SAL_CALL main( int argc, char** argv ) +{ + if(argc != 2) + { + fprintf( stderr, "usage: %s <my rdb file>\n", argv[0] ); + return 1; + } + + //------------------------------------------------- + // get the global service-manager + //------------------------------------------------- + OUString rdbName = OUString::createFromAscii( argv[1] ); + Reference< XMultiServiceFactory > g_xFactory( createRegistryServiceFactory( rdbName ) ); + + // Print a message if an error occured. + if ( !g_xFactory.is() ) + { + OSL_ENSURE(sal_False, "Can't create RegistryServiceFactory"); + return(-1); + } + + //------------------------------------------------- + // try to get an Interface to a XFilePicker Service + //------------------------------------------------- + + Reference< XTransferable > rXTransf( static_cast< XTransferable* >( new TestTransferable ) ); + + Reference< XClipboard > xClipboard( g_xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( AQUA_CLIPBOARD_SERVICE_NAME ) ) ), UNO_QUERY ); + if ( !xClipboard.is() ) + { + OSL_ENSURE( sal_False, "Error creating FolderPicker Service" ); + return(-1); + } + + Reference< XTypeProvider > rXTypProv( xClipboard, UNO_QUERY ); + + if ( rXTypProv.is() ) + { + Sequence< Type > seqType = rXTypProv->getTypes(); + sal_Int32 nLen = seqType.getLength(); + for ( sal_Int32 i = 0; i < nLen; i++ ) + { + Type nxtType = seqType[i]; + } + + Sequence< sal_Int8 > seqInt8 = rXTypProv->getImplementationId(); + } + + xClipboard->setContents( rXTransf, Reference< XClipboardOwner >( rXTransf, UNO_QUERY ) ); + + rXTransfRead = xClipboard->getContents(); + + // destroy the transferable explicitly + rXTransfRead = Reference< XTransferable>(); + + // destroy the clipboard + xClipboard = Reference< XClipboard >(); + + //-------------------------------------------------- + // shutdown the service manager + //-------------------------------------------------- + + // Cast factory to XComponent + Reference< XComponent > xComponent( g_xFactory, UNO_QUERY ); + + if ( !xComponent.is() ) + OSL_ENSURE(sal_False, "Error shuting down"); + + // Dispose and clear factory + xComponent->dispose(); + g_xFactory.clear(); + g_xFactory = Reference< XMultiServiceFactory >(); + + return 0; +} diff --git a/vcl/aqua/source/gdi/salbmp.cxx b/vcl/aqua/source/gdi/salbmp.cxx index 42f29d677b52..8b7b23a681a0 100644 --- a/vcl/aqua/source/gdi/salbmp.cxx +++ b/vcl/aqua/source/gdi/salbmp.cxx @@ -214,16 +214,26 @@ bool AquaSalBitmap::CreateContext() { // convert user data to 32 bit nContextBytesPerRow = mnWidth << 2; - maContextBuffer.reset( new sal_uInt8[ mnHeight * nContextBytesPerRow ] ); + try + { + maContextBuffer.reset( new sal_uInt8[ mnHeight * nContextBytesPerRow ] ); - if( !bSkipConversion ) - ConvertBitmapData( mnWidth, mnHeight, - 32, nContextBytesPerRow, maPalette, maContextBuffer.get(), - mnBits, mnBytesPerRow, maPalette, maUserBuffer.get() ); + if( !bSkipConversion ) + ConvertBitmapData( mnWidth, mnHeight, + 32, nContextBytesPerRow, maPalette, maContextBuffer.get(), + mnBits, mnBytesPerRow, maPalette, maUserBuffer.get() ); + } + catch( std::bad_alloc ) + { + mxGraphicContext = 0; + } } - mxGraphicContext = ::CGBitmapContextCreate( maContextBuffer.get(), mnWidth, mnHeight, - bitsPerComponent, nContextBytesPerRow, aCGColorSpace, aCGBmpInfo ); + if( maContextBuffer.get() ) + { + mxGraphicContext = ::CGBitmapContextCreate( maContextBuffer.get(), mnWidth, mnHeight, + bitsPerComponent, nContextBytesPerRow, aCGColorSpace, aCGBmpInfo ); + } if( !mxGraphicContext ) maContextBuffer.reset(); diff --git a/vcl/aqua/source/window/salframe.cxx b/vcl/aqua/source/window/salframe.cxx index 9c713ea26a52..b942c97cead1 100644 --- a/vcl/aqua/source/window/salframe.cxx +++ b/vcl/aqua/source/window/salframe.cxx @@ -43,6 +43,7 @@ #include "aqua11yfactory.h" #include "vcl/salwtype.hxx" #include "vcl/window.hxx" +#include "vcl/timer.hxx" #include "premac.h" // needed for theming @@ -749,16 +750,37 @@ void AquaSalFrame::ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay ) // ----------------------------------------------------------------------- +class PreventSleepTimer : public AutoTimer +{ +public: + PreventSleepTimer() + { + SetTimeout( 30000 ); + Start(); + } + + virtual ~PreventSleepTimer() + { + } + + virtual void Timeout() + { + UpdateSystemActivity(OverallAct); + } +}; + void AquaSalFrame::StartPresentation( BOOL bStart ) { if( bStart ) { + mpActivityTimer.reset( new PreventSleepTimer() ); [mpWindow setLevel: NSScreenSaverWindowLevel]; if( mbShown ) [mpWindow makeMainWindow]; } else { + mpActivityTimer.reset(); [mpWindow setLevel: NSNormalWindowLevel]; } } @@ -1173,6 +1195,7 @@ void AquaSalFrame::UpdateSettings( AllSettings& rSettings ) Color aMenuTextColor( getColor( [NSColor textColor], aStyleSettings.GetMenuTextColor(), mpWindow ) ); aStyleSettings.SetMenuTextColor( aMenuTextColor ); + aStyleSettings.SetMenuBarTextColor( aMenuTextColor ); aStyleSettings.SetCursorBlinkTime( 500 ); diff --git a/vcl/aqua/source/window/salframeview.mm b/vcl/aqua/source/window/salframeview.mm index c7facd8c6c09..68ea2c2062f2 100755 --- a/vcl/aqua/source/window/salframeview.mm +++ b/vcl/aqua/source/window/salframeview.mm @@ -184,6 +184,8 @@ static AquaSalFrame* getMouseContainerFrame() return YES; if( mpFrame->mbFullScreen ) return YES; + if( (mpFrame->mnStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) ) + return YES; return [super canBecomeKeyWindow]; } @@ -1420,7 +1422,7 @@ private: return 0; } -#ifdef MAC_OS_X_VERSION_10_5 +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) /* build target 10.5 or greater */ - (NSInteger)conversationIdentifier #else diff --git a/vcl/inc/vcl/floatwin.hxx b/vcl/inc/vcl/floatwin.hxx index 8dcba41e2a8e..02ac18ac28f8 100644 --- a/vcl/inc/vcl/floatwin.hxx +++ b/vcl/inc/vcl/floatwin.hxx @@ -157,6 +157,8 @@ public: const Link& GetPopupModeEndHdl() const { return maPopupModeEndHdl; } BOOL GrabsFocus() const { return mbGrabFocus; } + + static Point CalcFloatingPosition( Window* pWindow, const Rectangle& rRect, ULONG nFlags, USHORT& rArrangeIndex ); }; #endif // _SV_FLOATWIN_HXX diff --git a/vcl/inc/vcl/lazydelete.hxx b/vcl/inc/vcl/lazydelete.hxx index a0acba21fefa..4821492af1f8 100644 --- a/vcl/inc/vcl/lazydelete.hxx +++ b/vcl/inc/vcl/lazydelete.hxx @@ -225,7 +225,7 @@ namespace vcl SomeWindow::Paint() { - static vcl::DeleteOnDeinitBase< BitmapEx > aBmp( new BitmapEx( ResId( 1000, myResMgr ) ) ); + static vcl::DeleteOnDeinit< BitmapEx > aBmp( new BitmapEx( ResId( 1000, myResMgr ) ) ); if( aBmp.get() ) // check whether DeInitVCL has been called already DrawBitmapEx( Point( 10, 10 ), *aBmp.get() ); @@ -244,7 +244,7 @@ namespace vcl }; template < typename T > - class VCL_DLLPUBLIC DeleteOnDeinit : public DeleteOnDeinitBase + class DeleteOnDeinit : public DeleteOnDeinitBase { T* m_pT; virtual void doCleanup() { delete m_pT; m_pT = NULL; } diff --git a/vcl/inc/vcl/ppdparser.hxx b/vcl/inc/vcl/ppdparser.hxx index 5fa47d412f26..ed9f91b97d99 100644 --- a/vcl/inc/vcl/ppdparser.hxx +++ b/vcl/inc/vcl/ppdparser.hxx @@ -202,7 +202,7 @@ public: static const PPDParser* getParser( const String& rFile ); static String getPPDPrinterName( const String& rFile ); static void freeAll(); - static void getKnownPPDDrivers( std::list< rtl::OUString >& o_rDrivers ); + static void getKnownPPDDrivers( std::list< rtl::OUString >& o_rDrivers, bool bRefresh = false ); const String& getFilename() const { return m_aFile; } diff --git a/vcl/inc/vcl/salframe.hxx b/vcl/inc/vcl/salframe.hxx index 7a99442ebd5b..0e3f4e94a0b3 100644 --- a/vcl/inc/vcl/salframe.hxx +++ b/vcl/inc/vcl/salframe.hxx @@ -102,6 +102,8 @@ struct SystemEnvData; #define SAL_FRAME_STYLE_SYSTEMCHILD ((ULONG)0x08000000) // floating window #define SAL_FRAME_STYLE_FLOAT ((ULONG)0x20000000) +// floating window that needs to be focusable +#define SAL_FRAME_STYLE_FLOAT_FOCUSABLE ((ULONG)0x04000000) // toolwindows should be painted with a smaller decoration #define SAL_FRAME_STYLE_TOOLWINDOW ((ULONG)0x40000000) // the window containing the intro bitmap, aka splashscreen diff --git a/vcl/inc/vcl/salinst.hxx b/vcl/inc/vcl/salinst.hxx index 221c9e370ea6..650e57cdccc4 100644 --- a/vcl/inc/vcl/salinst.hxx +++ b/vcl/inc/vcl/salinst.hxx @@ -31,6 +31,8 @@ #ifndef _SV_SALINST_HXX #define _SV_SALINST_HXX +#include "com/sun/star/uno/Reference.hxx" + #include "vcl/sv.h" #include "vcl/dllapi.h" @@ -176,6 +178,12 @@ public: // this is only necessary because PrintFontManager is an exported vcl API and therefore // needs to be in libvcl while libvclplug_* do not contain exported C++ API virtual void FillFontPathList( std::list< rtl::OString >& o_rFontPaths ); + + // dtrans implementation + virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > + CreateClipboard( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& i_rArguments ); + virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDragSource(); + virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDropTarget(); }; // called from SVMain diff --git a/vcl/inc/vcl/settings.hxx b/vcl/inc/vcl/settings.hxx index a7cd61477519..decb7d01b2d4 100644 --- a/vcl/inc/vcl/settings.hxx +++ b/vcl/inc/vcl/settings.hxx @@ -379,6 +379,7 @@ private: Color maMenuHighlightColor; Color maMenuHighlightTextColor; Color maMenuTextColor; + Color maMenuBarTextColor; Color maMonoColor; Color maRadioCheckTextColor; Color maShadowColor; @@ -689,6 +690,10 @@ public: { CopyData(); mpData->maMenuTextColor = rColor; } const Color& GetMenuTextColor() const { return mpData->maMenuTextColor; } + void SetMenuBarTextColor( const Color& rColor ) + { CopyData(); mpData->maMenuBarTextColor = rColor; } + const Color& GetMenuBarTextColor() const + { return mpData->maMenuBarTextColor; } void SetMenuHighlightColor( const Color& rColor ) { CopyData(); mpData->maMenuHighlightColor = rColor; } const Color& GetMenuHighlightColor() const diff --git a/vcl/inc/vcl/vclevent.hxx b/vcl/inc/vcl/vclevent.hxx index a28127dd6f82..ff0639d70e82 100644 --- a/vcl/inc/vcl/vclevent.hxx +++ b/vcl/inc/vcl/vclevent.hxx @@ -150,6 +150,7 @@ class Menu; #define VCLEVENT_LISTBOX_ENTRY_EXPANDED 1174 #define VCLEVENT_LISTBOX_ENTRY_COLLAPSED 1175 // <-- +#define VCLEVENT_DROPDOWN_PRE_OPEN 1176 // VclMenuEvent #define VCLEVENT_MENU_ACTIVATE 1200 diff --git a/vcl/inc/vcl/wintypes.hxx b/vcl/inc/vcl/wintypes.hxx index f5869eca55e4..968f0e1d255f 100644 --- a/vcl/inc/vcl/wintypes.hxx +++ b/vcl/inc/vcl/wintypes.hxx @@ -194,6 +194,7 @@ typedef sal_Int64 WinBits; #define WB_TOOLTIPWIN ((WinBits)SAL_CONST_INT64(0x800000000)) #define WB_OWNERDRAWDECORATION ((WinBits)SAL_CONST_INT64(0x2000000000)) #define WB_DEFAULTWIN ((WinBits)SAL_CONST_INT64(0x4000000000)) +#define WB_NEEDSFOCUS ((WinBits)SAL_CONST_INT64(0x1000000000)) #define WB_HIDE ((WinBits)SAL_CONST_INT64(0x80000000)) #define WB_HSCROLL WB_HORZ diff --git a/vcl/os2/source/window/salframe.cxx b/vcl/os2/source/window/salframe.cxx index 8860d68d683e..345573b268c3 100644 --- a/vcl/os2/source/window/salframe.cxx +++ b/vcl/os2/source/window/salframe.cxx @@ -2172,6 +2172,7 @@ void Os2SalFrame::UpdateSettings( AllSettings& rSettings ) aStyleSettings.SetDeactiveBorderColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_INACTIVEBORDER, 0 ) ) ); aStyleSettings.SetMenuColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_MENU, 0 ) ) ); aStyleSettings.SetMenuTextColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_MENUTEXT, 0 ) ) ); + aStyleSettings.SetMenuBarTextColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_MENUTEXT, 0 ) ) ); } aStyleSettings.SetDialogTextColor( aStyleSettings.GetButtonTextColor() ); aStyleSettings.SetRadioCheckTextColor( aStyleSettings.GetButtonTextColor() ); diff --git a/vcl/prj/build.lst b/vcl/prj/build.lst index 52b444164029..908dd1eafd72 100644 --- a/vcl/prj/build.lst +++ b/vcl/prj/build.lst @@ -14,13 +14,15 @@ vc vcl\os2\source\app nmake - p vc__appp vc_inc NULL vc vcl\os2\source\gdi nmake - p vc__gdip vc_inc NULL vc vcl\os2\source\window nmake - p vc__winp vc_inc NULL vc vcl\os2\source\src nmake - p vc__srcp vc_inc NULL -vc vcl\source\components nmake - all vc_components NULL +vc vcl\source\components nmake - all vc_components vc_inc NULL vc vcl\win\source\app nmake - w vc__appw vc_inc NULL vc vcl\win\source\gdi nmake - w vc__gdiw vc_inc NULL vc vcl\win\source\window nmake - w vc__winw vc_inc NULL vc vcl\win\source\src nmake - w vc__srcw vc_inc NULL vc vcl\unx\source\plugadapt nmake - u vc__plug vc_inc NULL +vc vcl\unx\source\desktopdetect nmake - u vc__desk vc_inc NULL vc vcl\unx\source\app nmake - u vc__appu vc_inc NULL +vc vcl\unx\source\dtrans nmake - u vc__dtru vc_inc NULL vc vcl\unx\source\fontmanager nmake - u vc__ftmu vc_inc NULL vc vcl\unx\source\gdi nmake - u vc__gdiu vc_inc NULL vc vcl\unx\source\printer nmake - u vc__prnu vc_inc NULL @@ -35,6 +37,7 @@ vc vcl\unx\kde nmake - u vc__kde vc_inc NULL vc vcl\unx\kde4 nmake - u vc__kde4 vc_inc NULL vc vcl\aqua\source\a11y nmake - u vc__aquy vc_inc NULL vc vcl\aqua\source\app nmake - u vc__appa vc_inc NULL +vc vcl\aqua\source\dtrans nmake - u vc__dtra vc_inc NULL vc vcl\aqua\source\gdi nmake - u vc__gdia vc_inc NULL vc vcl\aqua\source\res nmake - u vc__resa NULL vc vcl\aqua\source\window nmake - u vc__wina vc_inc NULL @@ -42,6 +45,6 @@ vc vcl\mac\source\app nmake - m vc__appm vc_inc NULL vc vcl\mac\source\gdi nmake - m vc__gdim vc_inc NULL vc vcl\mac\source\window nmake - m vc__winm vc_inc NULL vc vcl\mac\source\src nmake - m vc__srcm vc_inc NULL -vc vcl\util nmake - all vc_util vc__plug.u vc__aquy.u vc__appa.u vc__appm.m vc__appu.u vc__appw.w vc__appp.p vc__gdia.u vc__gdim.m vc__gdiu.u vc__gdiw.w vc__gdip.p vc__srcm.m vc__srcw.w vc__srcp.p vc__wina.u vc__winm.m vc__winu.u vc__winw.w vc__winp.p vc__gtka.u vc__gtky.u vc__gtkw.u vc__gtkg.u vc__kde.u vc__kde4.u vc__hl.u vc__ftmu.u vc__prgu.u vc__prnu.u vc_app vc_ctrl vc_gdi vc_hlp vc_src vc_win vc_glyphs vc_fts vc_components NULL +vc vcl\util nmake - all vc_util vc__plug.u vc__desk.u vc__aquy.u vc__appa.u vc__dtra.u vc__appm.m vc__appu.u vc__dtru.u vc__appw.w vc__appp.p vc__gdia.u vc__gdim.m vc__gdiu.u vc__gdiw.w vc__gdip.p vc__srcm.m vc__srcw.w vc__srcp.p vc__wina.u vc__winm.m vc__winu.u vc__winw.w vc__winp.p vc__gtka.u vc__gtky.u vc__gtkw.u vc__gtkg.u vc__kde.u vc__kde4.u vc__hl.u vc__ftmu.u vc__prgu.u vc__prnu.u vc_app vc_ctrl vc_gdi vc_hlp vc_src vc_win vc_glyphs vc_fts vc_components NULL vc vcl\util\linksvp nmake - u vc_lsvp vc_util NULL vc vcl\workben nmake - all vc_wrkb vc_util vc_salmain NULL diff --git a/vcl/prj/d.lst b/vcl/prj/d.lst index d9c14f46b8d1..983628184177 100644 --- a/vcl/prj/d.lst +++ b/vcl/prj/d.lst @@ -1,14 +1,12 @@ mkdir: %COMMON_DEST%\bin%_EXT%\hid mkdir: %_DEST%\inc%_EXT%\vcl -mkdir: %_DEST%\inc%_EXT%\vcl\plug -mkdir: %_DEST%\inc%_EXT%\vcl\plug\vcl ..\%COMMON_OUTDIR%\bin\*.zip %COMMON_DEST%\bin%_EXT%\*.zip ..\%COMMON_OUTDIR%\misc\*.hid %COMMON_DEST%\bin%_EXT%\hid\*.hid ..\%__SRC%\bin\vcl*.res %_DEST%\bin%_EXT%\vcl*.res ..\%__SRC%\bin\vcl?????.dll %_DEST%\bin%_EXT%\vcl?????.dll ..\%__SRC%\bin\vcl?????.sym %_DEST%\bin%_EXT%\vcl?????.sym -..\%__SRC%\lib\libvcl*.so %_DEST%\lib%_EXT%\libvcl*.so +..\%__SRC%\lib\lib*.so %_DEST%\lib%_EXT%\lib*.so ..\%__SRC%\lib\*.dylib %_DEST%\lib%_EXT%\*.dylib ..\%__SRC%\lib\ivcl.lib %_DEST%\lib%_EXT%\ivcl.lib ..\%__SRC%\misc\vcl?????.map %_DEST%\bin%_EXT%\vcl?????.map @@ -153,3 +151,4 @@ mkdir: %_DEST%\inc%_EXT%\vcl\plug\vcl ..\inc\vcl\ppdparser.hxx %_DEST%\inc%_EXT%\vcl\ppdparser.hxx ..\inc\vcl\helper.hxx %_DEST%\inc%_EXT%\vcl\helper.hxx ..\inc\vcl\strhelper.hxx %_DEST%\inc%_EXT%\vcl\strhelper.hxx +..\inc\vcl\lazydelete.hxx %_DEST%\inc%_EXT%\vcl\lazydelete.hxx
\ No newline at end of file diff --git a/vcl/source/app/settings.cxx b/vcl/source/app/settings.cxx index 444f1f58c8fb..6aa453563596 100644 --- a/vcl/source/app/settings.cxx +++ b/vcl/source/app/settings.cxx @@ -478,6 +478,7 @@ ImplStyleData::ImplStyleData( const ImplStyleData& rData ) : maMenuHighlightColor( rData.maMenuHighlightColor ), maMenuHighlightTextColor( rData.maMenuHighlightTextColor ), maMenuTextColor( rData.maMenuTextColor ), + maMenuBarTextColor( rData.maMenuBarTextColor ), maMonoColor( rData.maMonoColor ), maRadioCheckTextColor( rData.maRadioCheckTextColor ), maShadowColor( rData.maShadowColor ), @@ -597,6 +598,7 @@ void ImplStyleData::SetStandardStyles() maMenuBarColor = Color( COL_LIGHTGRAY ); maMenuBorderColor = Color( COL_LIGHTGRAY ); maMenuTextColor = Color( COL_BLACK ); + maMenuBarTextColor = Color( COL_BLACK ); maMenuHighlightColor = Color( COL_BLUE ); maMenuHighlightTextColor = Color( COL_WHITE ); maHighlightColor = Color( COL_BLUE ); @@ -1028,6 +1030,7 @@ BOOL StyleSettings::operator ==( const StyleSettings& rSet ) const (mpData->maMenuBarColor == rSet.mpData->maMenuBarColor) && (mpData->maMenuBorderColor == rSet.mpData->maMenuBorderColor) && (mpData->maMenuTextColor == rSet.mpData->maMenuTextColor) && + (mpData->maMenuBarTextColor == rSet.mpData->maMenuBarTextColor) && (mpData->maMenuHighlightColor == rSet.mpData->maMenuHighlightColor) && (mpData->maMenuHighlightTextColor == rSet.mpData->maMenuHighlightTextColor) && (mpData->maHighlightColor == rSet.mpData->maHighlightColor) && diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx index 262910d18c82..b53ceceeb757 100644 --- a/vcl/source/app/svapp.cxx +++ b/vcl/source/app/svapp.cxx @@ -674,11 +674,11 @@ void Application::MergeSystemSettings( AllSettings& rSettings ) ImplSVData* pSVData = ImplGetSVData(); if ( !pSVData->maAppData.mbSettingsInit ) { - pWindow->ImplGetFrame()->UpdateSettings( *pSVData->maAppData.mpSettings ); + // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings pWindow->ImplUpdateGlobalSettings( *pSVData->maAppData.mpSettings ); pSVData->maAppData.mbSettingsInit = TRUE; } - pWindow->ImplGetFrame()->UpdateSettings( rSettings ); + // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings pWindow->ImplUpdateGlobalSettings( rSettings, FALSE ); } } diff --git a/vcl/source/components/dtranscomp.cxx b/vcl/source/components/dtranscomp.cxx new file mode 100644 index 000000000000..58792cd4fbdb --- /dev/null +++ b/vcl/source/components/dtranscomp.cxx @@ -0,0 +1,556 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: fontident.cxx,v $ + * + * $Revision: 1.3 $ + * + * 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 "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/lang/XSingleServiceFactory.hpp" +#include "com/sun/star/lang/XInitialization.hpp" +#include "com/sun/star/lang/DisposedException.hpp" +#include "com/sun/star/datatransfer/XTransferable.hpp" +#include "com/sun/star/datatransfer/clipboard/XClipboard.hpp" +#include "com/sun/star/datatransfer/clipboard/XClipboardEx.hpp" +#include "com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp" +#include "com/sun/star/datatransfer/clipboard/XClipboardListener.hpp" +#include "com/sun/star/datatransfer/dnd/XDragSource.hpp" +#include "com/sun/star/datatransfer/dnd/XDropTarget.hpp" +#include "com/sun/star/datatransfer/dnd/DNDConstants.hpp" + +#include "vcl/svapp.hxx" +#include "vcl/svdata.hxx" +#include "vcl/salinst.hxx" +#include "vos/mutex.hxx" +#include "osl/mutex.hxx" + +#include "cppuhelper/compbase1.hxx" +#include "cppuhelper/compbase2.hxx" +#include "cppuhelper/compbase3.hxx" +#include "cppuhelper/implbase1.hxx" + +using rtl::OUString; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; + +// ----------------------------------------------------------------------- + +namespace vcl +{ +// generic implementation to satisfy SalInstance +class GenericClipboard : + public cppu::WeakComponentImplHelper3 < + datatransfer::clipboard::XClipboardEx, + datatransfer::clipboard::XClipboardNotifier, + XServiceInfo + > +{ + osl::Mutex m_aMutex; + Reference< ::com::sun::star::datatransfer::XTransferable > m_aContents; + Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner > m_aOwner; + std::list< Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener > > m_aListeners; + + void fireChangedContentsEvent(); + void clearContents(); + +public: + + GenericClipboard() : cppu::WeakComponentImplHelper3< + datatransfer::clipboard::XClipboardEx, + datatransfer::clipboard::XClipboardNotifier, + XServiceInfo + >( m_aMutex ) + {} + virtual ~GenericClipboard(); + + /* + * 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 ); + + static rtl::OUString getImplementationName_static(); + static Sequence< rtl::OUString > getSupportedServiceNames_static(); + + /* + * XClipboard + */ + + virtual Reference< ::com::sun::star::datatransfer::XTransferable > SAL_CALL getContents() + throw(RuntimeException); + + virtual void SAL_CALL setContents( + const Reference< ::com::sun::star::datatransfer::XTransferable >& xTrans, + const 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 Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener ) + throw(RuntimeException); + + virtual void SAL_CALL removeClipboardListener( + const Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener ) + throw(RuntimeException); +}; + +GenericClipboard::~GenericClipboard() +{ +} + +rtl::OUString GenericClipboard::getImplementationName_static() +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.datatransfer.VCLGenericClipboard" ) ); +} + +Sequence< rtl::OUString > GenericClipboard::getSupportedServiceNames_static() +{ + Sequence< OUString > aRet(1); + aRet[0] = OUString::createFromAscii("com.sun.star.datatransfer.clipboard.SystemClipboard"); + return aRet; +} + +rtl::OUString GenericClipboard::getImplementationName() throw( RuntimeException ) +{ + return getImplementationName_static(); +} + +Sequence< rtl::OUString > GenericClipboard::getSupportedServiceNames() throw( RuntimeException ) +{ + return getSupportedServiceNames_static(); +} + +sal_Bool GenericClipboard::supportsService( const ::rtl::OUString& ServiceName ) throw( RuntimeException ) +{ + Sequence< OUString > aServices( getSupportedServiceNames() ); + sal_Int32 nServices = aServices.getLength(); + for( sal_Int32 i = 0; i < nServices; i++ ) + { + if( aServices[i] == ServiceName ) + return sal_True; + } + return sal_False; +} + +Reference< ::com::sun::star::datatransfer::XTransferable > GenericClipboard::getContents() throw( RuntimeException ) +{ + return m_aContents; +} + +void GenericClipboard::setContents( + const Reference< ::com::sun::star::datatransfer::XTransferable >& xTrans, + const Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner ) + throw( RuntimeException ) +{ + osl::ClearableMutexGuard aGuard( m_aMutex ); + Reference< datatransfer::clipboard::XClipboardOwner > xOldOwner( m_aOwner ); + Reference< datatransfer::XTransferable > xOldContents( m_aContents ); + m_aContents = xTrans; + m_aOwner = xClipboardOwner; + + std::list< Reference< datatransfer::clipboard::XClipboardListener > > xListeners( m_aListeners ); + datatransfer::clipboard::ClipboardEvent aEv; + aEv.Contents = m_aContents; + + aGuard.clear(); + + if( xOldOwner.is() && xOldOwner != xClipboardOwner ) + xOldOwner->lostOwnership( this, xOldContents ); + for( std::list< Reference< datatransfer::clipboard::XClipboardListener > >::iterator it = + xListeners.begin(); it != xListeners.end() ; ++it ) + { + (*it)->changedContents( aEv ); + } +} + +rtl::OUString GenericClipboard::getName() throw( RuntimeException ) +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CLIPBOARD" ) ); +} + +sal_Int8 GenericClipboard::getRenderingCapabilities() throw( RuntimeException ) +{ + return 0; +} + +void GenericClipboard::addClipboardListener( const Reference< datatransfer::clipboard::XClipboardListener >& listener ) + throw( RuntimeException ) +{ + osl::ClearableMutexGuard aGuard( m_aMutex ); + + m_aListeners.push_back( listener ); +} + +void GenericClipboard::removeClipboardListener( const Reference< datatransfer::clipboard::XClipboardListener >& listener ) + throw( RuntimeException ) +{ + osl::ClearableMutexGuard aGuard( m_aMutex ); + + m_aListeners.remove( listener ); +} + +// ------------------------------------------------------------------------ + +class ClipboardFactory : public ::cppu::WeakComponentImplHelper1< + com::sun::star::lang::XSingleServiceFactory +> +{ + osl::Mutex m_aMutex; +public: + ClipboardFactory(); + virtual ~ClipboardFactory(); + + /* + * XSingleServiceFactory + */ + virtual Reference< XInterface > SAL_CALL createInstance() throw(); + virtual Reference< XInterface > SAL_CALL createInstanceWithArguments( const Sequence< Any >& rArgs ) throw(); +}; + +// ------------------------------------------------------------------------ + +ClipboardFactory::ClipboardFactory() : + cppu::WeakComponentImplHelper1< + com::sun::star::lang::XSingleServiceFactory +>( m_aMutex ) +{ +} + +// ------------------------------------------------------------------------ + +ClipboardFactory::~ClipboardFactory() +{ +} + +// ------------------------------------------------------------------------ + +Reference< XInterface > ClipboardFactory::createInstance() throw() +{ + return createInstanceWithArguments( Sequence< Any >() ); +} + +// ------------------------------------------------------------------------ + +Reference< XInterface > ClipboardFactory::createInstanceWithArguments( const Sequence< Any >& arguments ) throw() +{ + vos::OGuard aGuard( Application::GetSolarMutex() ); + Reference< XInterface > xResult = ImplGetSVData()->mpDefInst->CreateClipboard( arguments ); + return xResult; +} + +// ------------------------------------------------------------------------ + +Sequence< OUString > SAL_CALL Clipboard_getSupportedServiceNames() +{ + Sequence< OUString > aRet(1); + aRet[0] = OUString::createFromAscii("com.sun.star.datatransfer.clipboard.SystemClipboard"); + return aRet; +} + +OUString SAL_CALL Clipboard_getImplementationName() +{ + #if defined UNX + return OUString( RTL_CONSTASCII_USTRINGPARAM( + #if ! defined QUARTZ + "com.sun.star.datatransfer.X11ClipboardSupport" + #else + "com.sun.star.datatransfer.clipboard.AquaClipboard" + #endif + ) ); + #else + return GenericClipboard::getImplementationName_static(); + #endif +} + +Reference< XSingleServiceFactory > SAL_CALL Clipboard_createFactory( const Reference< XMultiServiceFactory > & ) +{ + return Reference< XSingleServiceFactory >( new ClipboardFactory() ); +} + +/* +* generic DragSource dummy +*/ +class GenericDragSource : public cppu::WeakComponentImplHelper2< + datatransfer::dnd::XDragSource, + XInitialization + > +{ + osl::Mutex m_aMutex; +public: + GenericDragSource() : cppu::WeakComponentImplHelper2< datatransfer::dnd::XDragSource, XInitialization >( m_aMutex ) {} + virtual ~GenericDragSource(); + + // XDragSource + virtual sal_Bool SAL_CALL isDragImageSupported() throw(); + virtual sal_Int32 SAL_CALL getDefaultCursor( sal_Int8 dragAction ) throw(); + virtual void SAL_CALL startDrag( + const datatransfer::dnd::DragGestureEvent& trigger, + sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image, + const Reference< datatransfer::XTransferable >& transferable, + const Reference< datatransfer::dnd::XDragSourceListener >& listener + ) throw(); + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception ); + + static Sequence< OUString > getSupportedServiceNames_static() + { + Sequence< OUString > aRet( 1 ); + aRet[0] = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.GenericDragSource" ); + return aRet; + } + + static OUString getImplementationName_static() + { + return OUString::createFromAscii( "com.sun.star.datatransfer.dnd.VclGenericDragSource" ); + } +}; + +GenericDragSource::~GenericDragSource() +{ +} + +sal_Bool GenericDragSource::isDragImageSupported() throw() +{ + return sal_False; +} + +sal_Int32 GenericDragSource::getDefaultCursor( sal_Int8 ) throw() +{ + return 0; +} + +void GenericDragSource::startDrag( const datatransfer::dnd::DragGestureEvent&, + sal_Int8 /*sourceActions*/, sal_Int32 /*cursor*/, sal_Int32 /*image*/, + const Reference< datatransfer::XTransferable >&, + const Reference< datatransfer::dnd::XDragSourceListener >& listener + ) throw() +{ + datatransfer::dnd::DragSourceDropEvent aEv; + aEv.DropAction = datatransfer::dnd::DNDConstants::ACTION_COPY; + aEv.DropSuccess = sal_False; + listener->dragDropEnd( aEv ); +} + +void GenericDragSource::initialize( const Sequence< Any >& ) throw( Exception ) +{ +} + + +Sequence< OUString > SAL_CALL DragSource_getSupportedServiceNames() +{ + #if defined UNX + static OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( + #if ! defined QUARTZ + "com.sun.star.datatransfer.dnd.X11DragSource" + #else + "com.sun.star.datatransfer.dnd.OleDragSource" + #endif + ) ); + static Sequence< OUString > aServiceNames( &aServiceName, 1 ); + return aServiceNames; + #else + return GenericDragSource::getSupportedServiceNames_static(); + #endif +} + +OUString SAL_CALL DragSource_getImplementationName() +{ + #if defined UNX + return OUString( RTL_CONSTASCII_USTRINGPARAM( + #if ! defined QUARTZ + "com.sun.star.datatransfer.dnd.XdndSupport" + #else + "com.sun.star.comp.datatransfer.dnd.OleDragSource_V1" + #endif + ) ); + #else + return GenericDragSource::getImplementationName_static(); + #endif +} + +Reference< XInterface > SAL_CALL DragSource_createInstance( const Reference< XMultiServiceFactory >& ) +{ + vos::OGuard aGuard( Application::GetSolarMutex() ); + Reference< XInterface > xResult = ImplGetSVData()->mpDefInst->CreateDragSource(); + return xResult; +} + +/* +* generic DragSource dummy +*/ + +class GenericDropTarget : public cppu::WeakComponentImplHelper2< + datatransfer::dnd::XDropTarget, + XInitialization + > +{ + osl::Mutex m_aMutex; +public: + GenericDropTarget() : cppu::WeakComponentImplHelper2< + datatransfer::dnd::XDropTarget, + XInitialization + > ( m_aMutex ) + {} + virtual ~GenericDropTarget(); + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& args ) throw ( Exception ); + + // XDropTarget + virtual void SAL_CALL addDropTargetListener( const Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw(); + virtual void SAL_CALL removeDropTargetListener( const 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(); + + static Sequence< OUString > getSupportedServiceNames_static() + { + Sequence< OUString > aRet( 1 ); + aRet[0] = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.GenericDropTarget" ); + return aRet; + } + + static OUString getImplementationName_static() + { + return OUString::createFromAscii( "com.sun.star.datatransfer.dnd.VclGenericDropTarget" ); + } +}; + +GenericDropTarget::~GenericDropTarget() +{ +} + +void GenericDropTarget::initialize( const Sequence< Any >& ) throw( Exception ) +{ +} + +void GenericDropTarget::addDropTargetListener( const Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw() +{ +} + +void GenericDropTarget::removeDropTargetListener( const Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw() +{ +} + +sal_Bool GenericDropTarget::isActive() throw() +{ + return sal_False; +} + +void GenericDropTarget::setActive( sal_Bool ) throw() +{ +} + +sal_Int8 GenericDropTarget::getDefaultActions() throw() +{ + return 0; +} + +void GenericDropTarget::setDefaultActions( sal_Int8) throw() +{ +} + +Sequence< OUString > SAL_CALL DropTarget_getSupportedServiceNames() +{ + #if defined UNX + static OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( + #if ! defined QUARTZ + "com.sun.star.datatransfer.dnd.X11DropTarget" + #else + "com.sun.star.datatransfer.dnd.OleDropTarget" + #endif + ) ); + static Sequence< OUString > aServiceNames( &aServiceName, 1 ); + return aServiceNames; + #else + return GenericDropTarget::getSupportedServiceNames_static(); + #endif +} + +OUString SAL_CALL DropTarget_getImplementationName() +{ + #if defined UNX + return OUString( RTL_CONSTASCII_USTRINGPARAM( + #if ! defined QUARTZ + "com.sun.star.datatransfer.dnd.XdndDropTarget" + #else + "com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1" + #endif + ) ); + #else + return GenericDropTarget::getImplementationName_static(); + #endif +} + +Reference< XInterface > SAL_CALL DropTarget_createInstance( const Reference< XMultiServiceFactory >& ) +{ + vos::OGuard aGuard( Application::GetSolarMutex() ); + Reference< XInterface > xResult = ImplGetSVData()->mpDefInst->CreateDropTarget(); + return xResult; +} + + +} // namespace vcl + +/* +* SalInstance generic +*/ +Reference< XInterface > SalInstance::CreateClipboard( const Sequence< Any >& ) +{ + return Reference< XInterface >( ( cppu::OWeakObject * )new vcl::GenericClipboard() ); +} + +Reference< XInterface > SalInstance::CreateDragSource() +{ + return Reference< XInterface >( ( cppu::OWeakObject * )new vcl::GenericDragSource() ); +} + +Reference< XInterface > SalInstance::CreateDropTarget() +{ + return Reference< XInterface >( ( cppu::OWeakObject * )new vcl::GenericDropTarget() ); +} + diff --git a/vcl/source/components/factory.cxx b/vcl/source/components/factory.cxx index ef2e5c3b85fd..e816c31c613a 100644 --- a/vcl/source/components/factory.cxx +++ b/vcl/source/components/factory.cxx @@ -59,11 +59,23 @@ namespace vcl { extern Sequence< OUString > SAL_CALL DisplayAccess_getSupportedServiceNames(); extern OUString SAL_CALL DisplayAccess_getImplementationName(); -extern Reference< XInterface > SAL_CALL DisplayAccess_createInstance( const Reference< XMultiServiceFactory > & ); +extern Reference< XInterface > SAL_CALL DisplayAccess_createInstance( const Reference< XMultiServiceFactory > & ); extern Sequence< OUString > SAL_CALL FontIdentificator_getSupportedServiceNames(); extern OUString SAL_CALL FontIdentificator_getImplementationName(); -extern Reference< XInterface > SAL_CALL FontIdentificator_createInstance( const Reference< XMultiServiceFactory > & ); +extern Reference< XInterface > SAL_CALL FontIdentificator_createInstance( const Reference< XMultiServiceFactory > & ); + +extern Sequence< OUString > SAL_CALL Clipboard_getSupportedServiceNames(); +extern OUString SAL_CALL Clipboard_getImplementationName(); +extern Reference< XSingleServiceFactory > SAL_CALL Clipboard_createFactory( const Reference< XMultiServiceFactory > & ); + +extern Sequence< OUString > SAL_CALL DragSource_getSupportedServiceNames(); +extern OUString SAL_CALL DragSource_getImplementationName(); +extern Reference< XInterface > SAL_CALL DragSource_createInstance( const Reference< XMultiServiceFactory > & ); + +extern Sequence< OUString > SAL_CALL DropTarget_getSupportedServiceNames(); +extern OUString SAL_CALL DropTarget_getImplementationName(); +extern Reference< XInterface > SAL_CALL DropTarget_createInstance( const Reference< XMultiServiceFactory > & ); } extern "C" { @@ -102,6 +114,26 @@ extern "C" { aImplName.append( vcl::FontIdentificator_getSupportedServiceNames()[0] ); xKey->createKey( aImplName.makeStringAndClear() ); + #if defined UNX + aImplName.appendAscii( "/" ); + aImplName.append( vcl::Clipboard_getImplementationName() ); + aImplName.appendAscii( "/UNO/SERVICES/" ); + aImplName.append( vcl::Clipboard_getSupportedServiceNames()[0] ); + xKey->createKey( aImplName.makeStringAndClear() ); + + aImplName.appendAscii( "/" ); + aImplName.append( vcl::DragSource_getImplementationName() ); + aImplName.appendAscii( "/UNO/SERVICES/" ); + aImplName.append( vcl::DragSource_getSupportedServiceNames()[0] ); + xKey->createKey( aImplName.makeStringAndClear() ); + + aImplName.appendAscii( "/" ); + aImplName.append( vcl::DropTarget_getImplementationName() ); + aImplName.appendAscii( "/UNO/SERVICES/" ); + aImplName.append( vcl::DropTarget_getSupportedServiceNames()[0] ); + xKey->createKey( aImplName.makeStringAndClear() ); + #endif + return sal_True; } catch( ::com::sun::star::registry::InvalidRegistryException& ) @@ -143,6 +175,22 @@ extern "C" { xMgr, vcl::FontIdentificator_getImplementationName(), vcl::FontIdentificator_createInstance, vcl::FontIdentificator_getSupportedServiceNames() ); } + else if( vcl::Clipboard_getImplementationName().equalsAscii( pImplementationName ) ) + { + xFactory = vcl::Clipboard_createFactory( xMgr ); + } + else if( vcl::DragSource_getImplementationName().equalsAscii( pImplementationName ) ) + { + xFactory = ::cppu::createSingleFactory( + xMgr, vcl::DragSource_getImplementationName(), vcl::DragSource_createInstance, + vcl::DragSource_getSupportedServiceNames() ); + } + else if( vcl::DropTarget_getImplementationName().equalsAscii( pImplementationName ) ) + { + xFactory = ::cppu::createSingleFactory( + xMgr, vcl::DropTarget_getImplementationName(), vcl::DropTarget_createInstance, + vcl::DropTarget_getSupportedServiceNames() ); + } if( xFactory.is() ) { xFactory->acquire(); diff --git a/vcl/source/components/makefile.mk b/vcl/source/components/makefile.mk index 9158d33bb888..8cc836fe5424 100644 --- a/vcl/source/components/makefile.mk +++ b/vcl/source/components/makefile.mk @@ -44,6 +44,7 @@ ENABLE_EXCEPTIONS=TRUE # --- Files -------------------------------------------------------- SLOFILES= $(SLO)$/display.obj \ + $(SLO)$/dtranscomp.obj \ $(SLO)$/fontident.obj \ $(SLO)$/factory.obj diff --git a/vcl/source/control/button.cxx b/vcl/source/control/button.cxx index 2e2342fc6fc8..e7a4aadb8694 100644 --- a/vcl/source/control/button.cxx +++ b/vcl/source/control/button.cxx @@ -420,10 +420,9 @@ void Button::ImplDrawAlignedImage( OutputDevice* pDev, Point& rPos, Image *pImage = &(mpButtonData->maImage); BitmapEx *pBitmapEx = mpButtonData->mpBitmapEx; - Color aBackCol; - if( !!(mpButtonData->maImageHC) && ImplGetCurrentBackgroundColor( aBackCol ) ) + if( !!(mpButtonData->maImageHC) ) { - if( aBackCol.IsDark() ) + if( GetSettings().GetStyleSettings().GetHighContrastMode() ) { pImage = &(mpButtonData->maImageHC); pBitmapEx = mpButtonData->mpBitmapExHC; @@ -2375,14 +2374,10 @@ if ( bNativeOK == FALSE ) // check for HC mode Image *pImage = &maImage; - Color aBackCol; - if( !!maImageHC && ImplGetCurrentBackgroundColor( aBackCol ) ) + if( !!maImageHC ) { - if( aBackCol.IsDark() ) + if( rStyleSettings.GetHighContrastMode() ) pImage = &maImageHC; - // #99902 no col transform required - //if( aBackCol.IsBright() ) - // nStyle |= IMAGE_DRAW_COLORTRANSFORM; } Point aImagePos( aImageRect.TopLeft() ); diff --git a/vcl/source/control/combobox.cxx b/vcl/source/control/combobox.cxx index 49c7e5457da7..f83e46e38302 100644 --- a/vcl/source/control/combobox.cxx +++ b/vcl/source/control/combobox.cxx @@ -287,6 +287,7 @@ BOOL ComboBox::IsAutocompleteEnabled() const IMPL_LINK( ComboBox, ImplClickBtnHdl, void*, EMPTYARG ) { + ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN ); mpSubEdit->GrabFocus(); if ( !mpImplLB->GetEntryList()->GetMRUCount() ) ImplUpdateFloatSelection(); @@ -523,6 +524,7 @@ void ComboBox::ToggleDropDown() ImplUpdateFloatSelection(); else mpImplLB->SelectEntry( 0 , TRUE ); + ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN ); mpBtn->SetPressed( TRUE ); SetSelection( Selection( 0, SELECTION_MAX ) ); mpFloatWin->StartFloat( TRUE ); @@ -800,14 +802,8 @@ void ComboBox::DataChanged( const DataChangedEvent& rDCEvt ) long ComboBox::PreNotify( NotifyEvent& rNEvt ) { - long nDone = 0; - - if( ( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN ) && ( rNEvt.GetWindow() == mpImplLB->GetMainWindow() ) ) - { - mpSubEdit->GrabFocus(); - } - return nDone ? nDone : Edit::PreNotify( rNEvt ); + return Edit::PreNotify( rNEvt ); } // ----------------------------------------------------------------------- @@ -830,6 +826,7 @@ long ComboBox::Notify( NotifyEvent& rNEvt ) ImplUpdateFloatSelection(); if( ( nKeyCode == KEY_DOWN ) && mpFloatWin && !mpFloatWin->IsInPopupMode() && aKeyEvt.GetKeyCode().IsMod2() ) { + ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN ); mpBtn->SetPressed( TRUE ); if ( mpImplLB->GetEntryList()->GetMRUCount() ) mpImplLB->SelectEntry( 0 , TRUE ); @@ -886,6 +883,10 @@ long ComboBox::Notify( NotifyEvent& rNEvt ) nDone = 0; // don't eat this event, let the default handling happen (i.e. scroll the context) } } + else if( ( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN ) && ( rNEvt.GetWindow() == mpImplLB->GetMainWindow() ) ) + { + mpSubEdit->GrabFocus(); + } return nDone ? nDone : Edit::Notify( rNEvt ); } diff --git a/vcl/source/control/field.cxx b/vcl/source/control/field.cxx index 1bc6af51f369..3cb6e45f0400 100644 --- a/vcl/source/control/field.cxx +++ b/vcl/source/control/field.cxx @@ -503,6 +503,9 @@ void NumericFormatter::ImplLoadRes( const ResId& rResId ) mnFieldValue = mnMin; mnLastValue = mnFieldValue; } + + if ( NUMERICFORMATTER_NOTHOUSANDSEP & nMask ) + SetUseThousandSep( !(BOOL)pMgr->ReadShort() ); } } diff --git a/vcl/source/control/fixed.cxx b/vcl/source/control/fixed.cxx index 530e928532e1..ecb066d107ce 100644 --- a/vcl/source/control/fixed.cxx +++ b/vcl/source/control/fixed.cxx @@ -804,13 +804,10 @@ void FixedBitmap::ImplDraw( OutputDevice* pDev, ULONG /* nDrawFlags */, USHORT nStyle = 0; Bitmap* pBitmap = &maBitmap; Color aCol; - if( !!maBitmapHC && ImplGetCurrentBackgroundColor( aCol ) ) + if( !!maBitmapHC ) { - if( aCol.IsDark() ) + if( GetSettings().GetStyleSettings().GetHighContrastMode() ) pBitmap = &maBitmapHC; - // #99902 no col transform required - //if( aCol.IsBright() ) - // nStyle |= IMAGE_DRAW_COLORTRANSFORM; } if( nStyle & IMAGE_DRAW_COLORTRANSFORM ) @@ -1058,13 +1055,10 @@ void FixedImage::ImplDraw( OutputDevice* pDev, ULONG nDrawFlags, Image *pImage = &maImage; Color aCol; - if( !!maImageHC && ImplGetCurrentBackgroundColor( aCol ) ) + if( !!maImageHC ) { - if( aCol.IsDark() ) + if( GetSettings().GetStyleSettings().GetHighContrastMode() ) pImage = &maImageHC; - // #99902 no col transform required - //if( aCol.IsBright() ) - // nStyle |= IMAGE_DRAW_COLORTRANSFORM; } // Haben wir ueberhaupt ein Image diff --git a/vcl/source/control/ilstbox.cxx b/vcl/source/control/ilstbox.cxx index a25ddbb68e8b..c0a28c8b03fd 100644 --- a/vcl/source/control/ilstbox.cxx +++ b/vcl/source/control/ilstbox.cxx @@ -2899,23 +2899,8 @@ void ImplWin::DrawEntry( BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImageP if( !!maImageHC ) { - // determine backgroundcolor as done in Paint() - Color aBackCol; - if( IsEnabled() ) - { - if( HasFocus() ) - aBackCol = GetSettings().GetStyleSettings().GetHighlightColor(); - else - aBackCol = GetBackground().GetColor(); - } - else // Disabled - aBackCol = GetBackground().GetColor(); - - if( aBackCol.IsDark() ) + if( GetSettings().GetStyleSettings().GetHighContrastMode() ) pImage = &maImageHC; - // #99902 no col transform required - //if( aBackCol.IsBright() ) - // nStyle |= IMAGE_DRAW_COLORTRANSFORM; } if ( !IsZoom() ) diff --git a/vcl/source/control/imgctrl.cxx b/vcl/source/control/imgctrl.cxx index 6d4777013a73..73b5154d32ac 100644 --- a/vcl/source/control/imgctrl.cxx +++ b/vcl/source/control/imgctrl.cxx @@ -93,14 +93,10 @@ void ImageControl::UserDraw( const UserDrawEvent& rUDEvt ) { USHORT nStyle = 0; BitmapEx* pBitmap = &maBmp; - Color aCol; - if( !!maBmpHC && ImplGetCurrentBackgroundColor( aCol ) ) + if( !!maBmpHC ) { - if( aCol.IsDark() ) + if( GetSettings().GetStyleSettings().GetHighContrastMode() ) pBitmap = &maBmpHC; - // #99902 no col transform required - //if( aCol.IsBright() ) - // nStyle |= IMAGE_DRAW_COLORTRANSFORM; } if ( !*pBitmap ) diff --git a/vcl/source/control/lstbox.cxx b/vcl/source/control/lstbox.cxx index a5e9ff1cc7d0..a4d3cbc22544 100644 --- a/vcl/source/control/lstbox.cxx +++ b/vcl/source/control/lstbox.cxx @@ -303,6 +303,7 @@ IMPL_LINK( ListBox, ImplClickBtnHdl, void*, EMPTYARG ) { if( !mpFloatWin->IsInPopupMode() ) { + ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN ); mpImplWin->GrabFocus(); mpBtn->SetPressed( TRUE ); mpFloatWin->StartFloat( TRUE ); @@ -363,6 +364,7 @@ void ListBox::ToggleDropDown() mpFloatWin->EndPopupMode(); else { + ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN ); mpImplWin->GrabFocus(); mpBtn->SetPressed( TRUE ); mpFloatWin->StartFloat( TRUE ); @@ -919,6 +921,7 @@ long ListBox::PreNotify( NotifyEvent& rNEvt ) if( mpFloatWin && !mpFloatWin->IsInPopupMode() && aKeyEvt.GetKeyCode().IsMod2() ) { + ImplCallEventListeners( VCLEVENT_DROPDOWN_PRE_OPEN ); mpBtn->SetPressed( TRUE ); mpFloatWin->StartFloat( FALSE ); ImplCallEventListeners( VCLEVENT_DROPDOWN_OPEN ); diff --git a/vcl/source/fontsubset/cff.cxx b/vcl/source/fontsubset/cff.cxx index 7af7e7e9c9e0..e5d83dc0733a 100644 --- a/vcl/source/fontsubset/cff.cxx +++ b/vcl/source/fontsubset/cff.cxx @@ -42,8 +42,10 @@ typedef long long S64; typedef sal_Int32 GlyphWidth; +typedef float RealType; +typedef RealType ValType; #include <vector> -typedef std::vector<int> IntVector; +typedef std::vector<ValType> ValVector; // ==================================================================== @@ -310,8 +312,8 @@ struct CffGlobal int mnFontDictBase; int mnFDAryCount; - IntVector maFontBBox; - //FloatVector maFontMatrix; + ValVector maFontBBox; + ValVector maFontMatrix; int mnFontNameSID; int mnFullNameSID; @@ -336,16 +338,16 @@ struct CffLocal // ATM hinting related values int mnStemStdHW; int mnStemStdVW; - IntVector maStemSnapH; - IntVector maStemSnapV; - IntVector maBlueValues; - IntVector maOtherBlues; - IntVector maFamilyBlues; - IntVector maFamilyOtherBlues; - double mfBlueScale; - double mfBlueShift; - double mfBlueFuzz; - double mfExpFactor; + ValVector maStemSnapH; + ValVector maStemSnapV; + ValVector maBlueValues; + ValVector maOtherBlues; + ValVector maFamilyBlues; + ValVector maFamilyOtherBlues; + RealType mfBlueScale; + RealType mfBlueShift; + RealType mfBlueFuzz; + RealType mfExpFactor; int mnLangGroup; bool mbForceBold; }; @@ -422,7 +424,7 @@ private: CffLocal* mpCffLocal; void readDictOp( void); - double readRealVal( void); + RealType readRealVal( void); const char* getString( int nStringID); int getFDSelect( int nGlyphIndex) const; int getGlyphSID( int nGlyphIndex) const; @@ -431,7 +433,7 @@ private: void readTypeOp( void); void read2push( void); void pop2write( void); - void writeType1Val( int/*TODO: double*/ nVal); + void writeType1Val( ValType); void writeTypeOp( int nTypeOp); void writeTypeEsc( int nTypeOp); void writeCurveTo( int nStackPos, int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3); @@ -441,10 +443,13 @@ private: public: // TODO: is public really needed? // accessing the value stack // TODO: add more checks - void push( int nVal) { mnValStack[ mnStackIdx++] = nVal;} - int pop( void) { return ((mnStackIdx>0) ? mnValStack[ --mnStackIdx] : 0);} - int peek( void) { return ((mnStackIdx>0) ? mnValStack[ mnStackIdx-1] : 0);} - int get( int nIndex) { return mnValStack[ nIndex];} + void push( ValType nVal) { mnValStack[ mnStackIdx++] = nVal;} + ValType popVal( void) { return ((mnStackIdx>0) ? mnValStack[ --mnStackIdx] : 0);} + ValType peekVal( void) const { return ((mnStackIdx>0) ? mnValStack[ mnStackIdx-1] : 0);} + ValType getVal( int nIndex) const { return mnValStack[ nIndex];} + int popInt( void); + int peekInt( void) const; + int getInt( int nIndex) const; int size( void) const { return mnStackIdx;} bool empty( void) const { return !mnStackIdx;} void clear( void) { mnStackIdx = 0;} @@ -453,7 +458,7 @@ public: // TODO: is public really needed? void addHints( bool bVerticalHints); int getHorzHintCount( void) const { return (mnHorzHintSize/2);} int getVertHintCount( void) const { return (mnHintSize-mnHorzHintSize)/2;} - void getHintPair( int nIndex, int* nMin, int* nEnd) const; + void getHintPair( int nIndex, ValType* nMin, ValType* nEnd) const; // accessing other charstring specifics bool hasCharWidth( void) const { return (mnCharWidth != -1);} @@ -465,12 +470,12 @@ public: // TODO: is public really needed? private: // typeop exceution context int mnStackIdx; - int mnValStack[ NMAXSTACK]; - int mnTransVals[ NMAXTRANS]; + ValType mnValStack[ NMAXSTACK]; + ValType mnTransVals[ NMAXTRANS]; int mnHintSize; int mnHorzHintSize; - int mnHintStack[ NMAXHINTS]; + ValType mnHintStack[ NMAXHINTS]; int mnCharWidth; }; @@ -499,6 +504,36 @@ CffSubsetterContext::~CffSubsetterContext( void) // -------------------------------------------------------------------- +inline int CffSubsetterContext::popInt( void) +{ + const ValType aVal = popVal(); + const int nInt = static_cast<int>(aVal); + assert( nInt == aVal); + return nInt; +} + +// -------------------------------------------------------------------- + +inline int CffSubsetterContext::peekInt( void) const +{ + const ValType aVal = peekVal(); + const int nInt = static_cast<int>(aVal); + assert( nInt == aVal); + return nInt; +} + +// -------------------------------------------------------------------- + +inline int CffSubsetterContext::getInt( int nIndex) const +{ + const ValType aVal = getVal( nIndex); + const int nInt = static_cast<int>(aVal); + assert( nInt == aVal); + return nInt; +} + +// -------------------------------------------------------------------- + inline void CffSubsetterContext::updateWidth( bool bUseFirstVal) { #if 1 // TODO: is this still needed? @@ -507,7 +542,7 @@ inline void CffSubsetterContext::updateWidth( bool bUseFirstVal) return; #endif if( bUseFirstVal) { - mnCharWidth = mpCffLocal->mnNominalWidth + mnValStack[0]; + mnCharWidth = static_cast<int>(mpCffLocal->mnNominalWidth + mnValStack[0]); // remove bottom stack entry --mnStackIdx; for( int i = 0; i < mnStackIdx; ++i) @@ -535,16 +570,16 @@ void CffSubsetterContext::addHints( bool bVerticalHints) assert( (mnHintSize + mnStackIdx) <= 2*NMAXHINTS); #ifdef IGNORE_HINTS - mnHorzHintSize += mnStackIdx; + mnHintSize += mnStackIdx; #else - int nHintOfs = 0; + ValType nHintOfs = 0; for( int i = 0; i < mnStackIdx; ++i) { - nHintOfs += mnValStack[ i]; + nHintOfs += mnValStack[ i ]; mnHintStack[ mnHintSize++] = nHintOfs; } +#endif // IGNORE_HINTS if( !bVerticalHints) mnHorzHintSize = mnHintSize; -#endif // IGNORE_HINTS // clear all values from the stack mnStackIdx = 0; @@ -552,12 +587,12 @@ void CffSubsetterContext::addHints( bool bVerticalHints) // -------------------------------------------------------------------- -void CffSubsetterContext::getHintPair( int nIndex, int* pMin, int* pEnd) const +void CffSubsetterContext::getHintPair( int nIndex, ValType* pMin, ValType* pEnd) const { nIndex *= 2; assert( nIndex < mnHintSize); assert( nIndex >= 0); - const int* pHint = &mnHintStack[ nIndex]; + const ValType* pHint = &mnHintStack[ nIndex ]; *pMin = pHint[0]; *pEnd = pHint[1]; } @@ -596,7 +631,8 @@ void CffSubsetterContext::readCharString( const U8* pTypeOps, int nTypeLen) void CffSubsetterContext::readDictOp( void) { - int nVal = 0; + ValType nVal = 0; + int nInt = 0; const U8 c = *mpReadPtr; if( c <= 21 ) { int nOpId = *(mpReadPtr++); @@ -613,41 +649,45 @@ void CffSubsetterContext::readDictOp( void) switch( *pCmdName) { default: fprintf( stderr, "unsupported DictOp.type=\'%c\'\n", *pCmdName); break; case 'b': // bool - nVal = pop(); + nInt = popInt(); switch( nOpId) { - case 915: mpCffLocal->mbForceBold = nVal; break; // "ForceBold" + case 915: mpCffLocal->mbForceBold = nInt; break; // "ForceBold" default: break; // TODO: handle more boolean dictops? } break; case 'n': // dict-op number - nVal = pop(); + nVal = popVal(); + nInt = static_cast<int>(nVal); switch( nOpId) { - case 10: mpCffLocal->mnStemStdHW = nVal; break; // "StdHW" - case 11: mpCffLocal->mnStemStdVW = nVal; break; // "StdVW" - case 15: mnCharsetBase = nVal; break; // "charset" - case 16: mnEncodingBase = nVal; break; // "nEncoding" - case 17: mnCharStrBase = nVal; break; // "nCharStrings" - case 19: mpCffLocal->mnLocalSubrOffs = nVal; break;// "nSubrs" - case 20: setDefaultWidth( nVal); break; // "defaultWidthX" - case 21: setNominalWidth( nVal); break; // "nominalWidthX" + case 10: mpCffLocal->mnStemStdHW = nInt; break; // "StdHW" + case 11: mpCffLocal->mnStemStdVW = nInt; break; // "StdVW" + case 15: mnCharsetBase = nInt; break; // "charset" + case 16: mnEncodingBase = nInt; break; // "nEncoding" + case 17: mnCharStrBase = nInt; break; // "nCharStrings" + case 19: mpCffLocal->mnLocalSubrOffs = nInt; break;// "nSubrs" + case 20: setDefaultWidth( nInt ); break; // "defaultWidthX" + case 21: setNominalWidth( nInt ); break; // "nominalWidthX" case 909: mpCffLocal->mfBlueScale = nVal; break; // "BlueScale" case 910: mpCffLocal->mfBlueShift = nVal; break; // "BlueShift" case 911: mpCffLocal->mfBlueFuzz = nVal; break; // "BlueFuzz" case 912: mpCffLocal->mfExpFactor = nVal; break; // "ExpansionFactor" - case 917: mpCffLocal->mnLangGroup = nVal; break; // "LanguageGroup" - case 936: mnFontDictBase = nVal; break; // "nFDArray" - case 937: mnFDSelectBase = nVal; break; // "nFDSelect" + case 917: mpCffLocal->mnLangGroup = nInt; break; // "LanguageGroup" + case 936: mnFontDictBase = nInt; break; // "nFDArray" + case 937: mnFDSelectBase = nInt; break; // "nFDSelect" default: break; // TODO: handle more numeric dictops? } break; case 'a': { // array + switch( nOpId) { + case 5: maFontBBox.clear(); break; // "FontBBox" + case 907: maFontMatrix.clear(); break; // "FontMatrix" + default: break; // TODO: reset other arrays? + } for( int i = 0; i < size(); ++i ) { - nVal = get(i); + nVal = getVal(i); switch( nOpId) { case 5: maFontBBox.push_back( nVal); break; // "FontBBox" -#if 0 // TODO case 907: maFontMatrix.push_back( nVal); break; // "FontMatrix" -#endif default: break; // TODO: handle more array dictops? } } @@ -656,7 +696,7 @@ void CffSubsetterContext::readDictOp( void) case 'd': { // delta array nVal = 0; for( int i = 0; i < size(); ++i ) { - nVal += get(i); + nVal += getVal(i); switch( nOpId) { case 6: mpCffLocal->maBlueValues.push_back( nVal); break; // "BlueValues" case 7: mpCffLocal->maOtherBlues.push_back( nVal); break; // "OtherBlues" @@ -670,39 +710,39 @@ void CffSubsetterContext::readDictOp( void) clear(); } break; case 's': // stringid (SID) - nVal = pop(); - switch( nOpId) { - case 2: mnFullNameSID = nVal; break; // "FullName" - case 3: mnFamilyNameSID = nVal; break; // "FamilyName" - case 938: mnFontNameSID = nVal; break; // "FontName" + nInt = popInt(); + switch( nOpId ) { + case 2: mnFullNameSID = nInt; break; // "FullName" + case 3: mnFamilyNameSID = nInt; break; // "FamilyName" + case 938: mnFontNameSID = nInt; break; // "FontName" default: break; // TODO: handle more string dictops? } break; case 'P': // private dict - mpCffLocal->mnPrivDictBase = pop(); - mpCffLocal->mnPrivDictSize = pop(); + mpCffLocal->mnPrivDictBase = popInt(); + mpCffLocal->mnPrivDictSize = popInt(); break; case 'r': { // ROS operands - int nSid1 = pop(); - int nSid2 = pop(); + int nSid1 = popInt(); + int nSid2 = popInt(); (void)nSid1; // TODO: use (void)nSid2; // TODO: use - nVal = pop(); + nVal = popVal(); mbCIDFont = true; } break; case 't': // CharstringType - nVal = pop(); - setCharStringType( nVal); + nInt = popInt(); + setCharStringType( nInt ); break; } return; } - if( (c >= 32) || (c == 28)) { + if( (c >= 32) || (c == 28) ) { // --mpReadPtr; read2push(); - } else if( c == 29) { // longint + } else if( c == 29 ) { // longint ++mpReadPtr; // skip 29 int nS32 = mpReadPtr[0] << 24; nS32 += mpReadPtr[1] << 16; @@ -711,13 +751,13 @@ void CffSubsetterContext::readDictOp( void) if( (sizeof(nS32) != 4) && (nS32 & (1<<31))) nS32 |= (~0U) << 31; // assuming 2s complement mpReadPtr += 4; - nVal = nS32; - push( nVal); + nVal = static_cast<ValType>(nS32); + push( nVal ); } else if( c == 30) { // real number ++mpReadPtr; // skip 30 - const double fReal = readRealVal(); + const RealType fReal = readRealVal(); // push value onto stack - nVal = static_cast<int>(fReal+0.5); //TODO!!! allow float on operand stack! + nVal = fReal; push( nVal); } } @@ -759,12 +799,12 @@ void CffSubsetterContext::readTypeOp( void) case 'C': nMinStack = 6; nMaxStack = 999; break; case 'E': nMinStack = 1; nMaxStack = 999; break; case 'G': nMinStack = 1; nMaxStack = 999; // global subr - nVal = peek(); + nVal = peekInt(); // TODO global subr break; case 'L': // local subr nMinStack = 1; nMaxStack = 999; - nVal = peek(); + nVal = peekInt(); // TODO local subr break; case 'I': // operands for "index" @@ -830,57 +870,70 @@ void CffSubsetterContext::readTypeOp( void) // -------------------------------------------------------------------- -void CffSubsetterContext::read2push( void) +void CffSubsetterContext::read2push() { - int nVal = 0; + ValType aVal = 0; const U8*& p = mpReadPtr; const U8 c = *p; - if( c == 28) { + if( c == 28 ) { short nS16 = (p[1] << 8) + p[2]; if( (sizeof(nS16) != 2) && (nS16 & (1<<15))) nS16 |= (~0U) << 15; // assuming 2s complement - nVal = nS16; + aVal = nS16; p += 3; - } else if( c <= 246) { // -107..+107 - nVal = p[0] - 139; + } else if( c <= 246 ) { // -107..+107 + aVal = static_cast<ValType>(p[0] - 139); p += 1; - } else if( c <= 250) { // +108..+1131 - nVal = ((p[0] << 8) + p[1]) - 63124; + } else if( c <= 250 ) { // +108..+1131 + aVal = static_cast<ValType>(((p[0] << 8) + p[1]) - 63124); p += 2; - } else if( c <= 254) { // -108..-1131 - nVal = 64148 - ((p[0] << 8) + p[1]); + } else if( c <= 254 ) { // -108..-1131 + aVal = static_cast<ValType>(64148 - ((p[0] << 8) + p[1])); p += 2; } else /*if( c == 255)*/ { // Fixed16.16 - nVal = (p[1] << 8) + p[2]; - // TODO: read non-integer part + int nS32 = (p[1] << 24) + (p[2] << 16) + (p[3] << 8) + p[4]; + if( (sizeof(nS32) != 2) && (nS32 & (1<<31))) + nS32 |= (~0U) << 31; // assuming 2s complement + aVal = static_cast<ValType>(nS32 * (1.0 / 0x10000)); p += 5; } - push( nVal); + push( aVal); } // -------------------------------------------------------------------- -void CffSubsetterContext::writeType1Val( int/*TODO: double*/ nVal) +void CffSubsetterContext::writeType1Val( ValType aVal) { U8* pOut = mpWritePtr; - if( (nVal >= -107) && (nVal <= +107)) { - *(pOut++) = static_cast<U8>(nVal + 139); // -107..+107 - } else if( (nVal >= -1131) && (nVal <= +1131)) { - if( nVal >= 0) - nVal += 63124; // +108..+1131 + + int nInt = static_cast<int>(aVal); + static const int nOutCharstrType = 1; + if( (nInt != aVal) && (nOutCharstrType == 2)) { + // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!! + *(pOut++) = 255; // Fixed 16.16 + *(pOut++) = static_cast<U8>(nInt >> 8); + *(pOut++) = static_cast<U8>(nInt); + nInt = static_cast<int>(aVal * 0x10000) & 0xFFFF; + *(pOut++) = static_cast<U8>(nInt >> 8); + *(pOut++) = static_cast<U8>(nInt); + } else if( (nInt >= -107) && (nInt <= +107)) { + *(pOut++) = static_cast<U8>(nInt + 139); // -107..+107 + } else if( (nInt >= -1131) && (nInt <= +1131)) { + if( nInt >= 0) + nInt += 63124; // +108..+1131 else - nVal = 64148 - nVal; // -108..-1131 - *(pOut++) = static_cast<U8>(nVal >> 8); - *(pOut++) = static_cast<U8>(nVal); - } else { + nInt = 64148 - nInt; // -108..-1131 + *(pOut++) = static_cast<U8>(nInt >> 8); + *(pOut++) = static_cast<U8>(nInt); + } else if( nOutCharstrType == 1) { // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!! *(pOut++) = 255; - *(pOut++) = static_cast<U8>(nVal >> 24); - *(pOut++) = static_cast<U8>(nVal >> 16); - *(pOut++) = static_cast<U8>(nVal >> 8); - *(pOut++) = static_cast<U8>(nVal); + *(pOut++) = static_cast<U8>(nInt >> 24); + *(pOut++) = static_cast<U8>(nInt >> 16); + *(pOut++) = static_cast<U8>(nInt >> 8); + *(pOut++) = static_cast<U8>(nInt); } mpWritePtr = pOut; @@ -890,8 +943,8 @@ void CffSubsetterContext::writeType1Val( int/*TODO: double*/ nVal) inline void CffSubsetterContext::pop2write( void) { - int nVal = pop(); - writeType1Val( nVal); + const ValType aVal = popVal(); + writeType1Val( aVal); } // -------------------------------------------------------------------- @@ -915,8 +968,8 @@ void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTy { for( int i = 0; i < mnStackIdx;) { for( int j = 0; j < nArgsPerTypo; ++j) { - int nVal = mnValStack[i+j]; - writeType1Val( nVal); + const ValType aVal = mnValStack[i+j]; + writeType1Val( aVal); } i += nArgsPerTypo; writeTypeOp( nTypeOp); @@ -931,8 +984,8 @@ void CffSubsetterContext::popAll2Write( int nTypeOp) { // pop in reverse order, then write for( int i = 0; i < mnStackIdx; ++i) { - int nVal = mnValStack[i]; - writeType1Val( nVal); + const ValType aVal = mnValStack[i]; + writeType1Val( aVal); } clear(); writeTypeOp( nTypeOp); @@ -944,23 +997,23 @@ void CffSubsetterContext::writeCurveTo( int nStackPos, int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3) { // get the values from the stack - const int nDX1 = nIX1 ? mnValStack[ nStackPos+nIX1] : 0; - const int nDY1 = nIY1 ? mnValStack[ nStackPos+nIY1] : 0; - const int nDX2 = nIX2 ? mnValStack[ nStackPos+nIX2] : 0; - const int nDY2 = nIY2 ? mnValStack[ nStackPos+nIY2] : 0; - const int nDX3 = nIX3 ? mnValStack[ nStackPos+nIX3] : 0; - const int nDY3 = nIY3 ? mnValStack[ nStackPos+nIY3] : 0; + const ValType nDX1 = nIX1 ? mnValStack[ nStackPos+nIX1 ] : 0; + const ValType nDY1 = nIY1 ? mnValStack[ nStackPos+nIY1 ] : 0; + const ValType nDX2 = nIX2 ? mnValStack[ nStackPos+nIX2 ] : 0; + const ValType nDY2 = nIY2 ? mnValStack[ nStackPos+nIY2 ] : 0; + const ValType nDX3 = nIX3 ? mnValStack[ nStackPos+nIX3 ] : 0; + const ValType nDY3 = nIY3 ? mnValStack[ nStackPos+nIY3 ] : 0; // emit the curveto operator and operands // TODO: determine the most efficient curveto operator // TODO: depending on type1op or type2op target - writeType1Val( nDX1); - writeType1Val( nDY1); - writeType1Val( nDX2); - writeType1Val( nDY2); - writeType1Val( nDX3); - writeType1Val( nDY3); - writeTypeOp( TYPE1OP::RCURVETO); + writeType1Val( nDX1 ); + writeType1Val( nDY1 ); + writeType1Val( nDX2 ); + writeType1Val( nDY2 ); + writeType1Val( nDX3 ); + writeType1Val( nDY3 ); + writeTypeOp( TYPE1OP::RCURVETO ); } // -------------------------------------------------------------------- @@ -969,7 +1022,7 @@ void CffSubsetterContext::convertOneTypeOp( void) { const int nType2Op = *(mpReadPtr++); - int i, nVal; // prevent WAE for declarations inside switch cases + int i, nInt; // prevent WAE for declarations inside switch cases // convert each T2op switch( nType2Op) { case TYPE2OP::T2ESC: @@ -977,12 +1030,12 @@ void CffSubsetterContext::convertOneTypeOp( void) break; case TYPE2OP::HSTEM: case TYPE2OP::VSTEM: - addHints( nType2Op == TYPE2OP::VSTEM); + addHints( nType2Op == TYPE2OP::VSTEM ); #ifndef IGNORE_HINTS - for( i = 0; i < mnHintSize; i+=2) { + for( i = 0; i < mnHintSize; i+=2 ) { writeType1Val( mnHintStack[i]); writeType1Val( mnHintStack[i+1] - mnHintStack[i]); - writeTypeOp( nType2Op); + writeTypeOp( nType2Op ); } #endif // IGNORE_HINTS break; @@ -1063,9 +1116,9 @@ void CffSubsetterContext::convertOneTypeOp( void) case TYPE2OP::CALLSUBR: case TYPE2OP::CALLGSUBR: { - nVal = pop(); + nInt = popInt(); const bool bGlobal = (nType2Op == TYPE2OP::CALLGSUBR); - callType2Subr( bGlobal, nVal); + callType2Subr( bGlobal, nInt); } break; case TYPE2OP::RETURN: @@ -1131,19 +1184,19 @@ void CffSubsetterContext::convertOneTypeOp( void) { bool bVert = (nType2Op == TYPE2OP::VHCURVETO); i = 0; - nVal = 0; - if( mnStackIdx & 1) - nVal = mnValStack[ --mnStackIdx]; + nInt = 0; + if( mnStackIdx & 1 ) + nInt = static_cast<int>(mnValStack[ --mnStackIdx ]); while( (i += 4) <= mnStackIdx) { // TODO: use writeCurveTo() - if( bVert) writeType1Val( 0); - writeType1Val( mnValStack[i-4]); - if( !bVert) writeType1Val( 0); - writeType1Val( mnValStack[i-3]); - writeType1Val( mnValStack[i-2]); - if( !bVert) writeType1Val( (i==mnStackIdx) ? nVal : 0); - writeType1Val( mnValStack[i-1]); - if( bVert) writeType1Val( (i==mnStackIdx) ? nVal : 0 ); + if( bVert ) writeType1Val( 0 ); + writeType1Val( mnValStack[i-4] ); + if( !bVert ) writeType1Val( 0); + writeType1Val( mnValStack[i-3] ); + writeType1Val( mnValStack[i-2] ); + if( !bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) ); + writeType1Val( mnValStack[i-1] ); + if( bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) ); bVert = !bVert; writeTypeOp( TYPE2OP::RCURVETO); } @@ -1195,83 +1248,83 @@ void CffSubsetterContext::convertOneTypeOp( void) void CffSubsetterContext::convertOneTypeEsc( void) { const int nType2Esc = *(mpReadPtr++); - int* pTop = &mnValStack[ mnStackIdx-1]; + ValType* pTop = &mnValStack[ mnStackIdx-1]; // convert each T2op switch( nType2Esc) { case TYPE2OP::AND: - assert( mnStackIdx >= 2); - pTop[0] &= pTop[-1]; + assert( mnStackIdx >= 2 ); + pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) & static_cast<int>(pTop[-1])); --mnStackIdx; break; case TYPE2OP::OR: - assert( mnStackIdx >= 2); - pTop[0] |= pTop[-1]; + assert( mnStackIdx >= 2 ); + pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) | static_cast<int>(pTop[-1])); --mnStackIdx; break; case TYPE2OP::NOT: - assert( mnStackIdx >= 1); - pTop[0] = !pTop[0]; + assert( mnStackIdx >= 1 ); + pTop[0] = (pTop[0] == 0); break; case TYPE2OP::ABS: - assert( mnStackIdx >= 1); + assert( mnStackIdx >= 1 ); if( pTop[0] >= 0) break; // fall through case TYPE2OP::NEG: - assert( mnStackIdx >= 1); + assert( mnStackIdx >= 1 ); pTop[0] = -pTop[0]; break; case TYPE2OP::ADD: - assert( mnStackIdx >= 2); + assert( mnStackIdx >= 2 ); pTop[0] += pTop[-1]; --mnStackIdx; break; case TYPE2OP::SUB: - assert( mnStackIdx >= 2); + assert( mnStackIdx >= 2 ); pTop[0] -= pTop[-1]; --mnStackIdx; break; case TYPE2OP::MUL: - assert( mnStackIdx >= 2); + assert( mnStackIdx >= 2 ); if( pTop[-1]) pTop[0] *= pTop[-1]; --mnStackIdx; break; case TYPE2OP::DIV: - assert( mnStackIdx >= 2); + assert( mnStackIdx >= 2 ); if( pTop[-1]) pTop[0] /= pTop[-1]; --mnStackIdx; break; case TYPE2OP::EQ: - assert( mnStackIdx >= 2); + assert( mnStackIdx >= 2 ); pTop[0] = (pTop[0] == pTop[-1]); --mnStackIdx; break; case TYPE2OP::DROP: - assert( mnStackIdx >= 1); + assert( mnStackIdx >= 1 ); --mnStackIdx; break; case TYPE2OP::PUT: { - assert( mnStackIdx >= 2); - const int nIdx = pTop[0]; - assert( nIdx >= 0); - assert( nIdx < NMAXTRANS); + assert( mnStackIdx >= 2 ); + const int nIdx = static_cast<int>(pTop[0]); + assert( nIdx >= 0 ); + assert( nIdx < NMAXTRANS ); mnTransVals[ nIdx] = pTop[-1]; mnStackIdx -= 2; break; } case TYPE2OP::GET: { - assert( mnStackIdx >= 1); - const int nIdx = pTop[0]; - assert( nIdx >= 0); - assert( nIdx < NMAXTRANS); - pTop[0] = mnTransVals[ nIdx]; + assert( mnStackIdx >= 1 ); + const int nIdx = static_cast<int>(pTop[0]); + assert( nIdx >= 0 ); + assert( nIdx < NMAXTRANS ); + pTop[0] = mnTransVals[ nIdx ]; break; } case TYPE2OP::IFELSE: { - assert( mnStackIdx >= 4); - if( pTop[-1] > pTop[0]) + assert( mnStackIdx >= 4 ); + if( pTop[-1] > pTop[0] ) pTop[-3] = pTop[-2]; mnStackIdx -= 3; break; @@ -1284,69 +1337,69 @@ void CffSubsetterContext::convertOneTypeEsc( void) // TODO: implement break; case TYPE2OP::DUP: - assert( mnStackIdx >= 1); + assert( mnStackIdx >= 1 ); pTop[+1] = pTop[0]; ++mnStackIdx; break; case TYPE2OP::EXCH: { - assert( mnStackIdx >= 2); - const int nVal = pTop[0]; + assert( mnStackIdx >= 2 ); + const ValType nVal = pTop[0]; pTop[0] = pTop[-1]; pTop[-1] = nVal; break; } case TYPE2OP::INDEX: { - assert( mnStackIdx >= 1); - const int nVal = pTop[0]; - assert( nVal >= 0); - assert( nVal < mnStackIdx-1); + assert( mnStackIdx >= 1 ); + const int nVal = static_cast<int>(pTop[0]); + assert( nVal >= 0 ); + assert( nVal < mnStackIdx-1 ); pTop[0] = pTop[-1-nVal]; break; } case TYPE2OP::ROLL: { - assert( mnStackIdx >= 1); - const int nNum = pTop[0]; + assert( mnStackIdx >= 1 ); + const int nNum = static_cast<int>(pTop[0]); assert( nNum >= 0); - assert( nNum < mnStackIdx-2); + assert( nNum < mnStackIdx-2 ); (void)nNum; // TODO: implement - const int nOfs = pTop[-1]; + const int nOfs = static_cast<int>(pTop[-1]); mnStackIdx -= 2; (void)nOfs;// TODO: implement break; } case TYPE2OP::HFLEX1: { - assert( mnStackIdx == 9); - writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5, -6); - writeCurveTo( mnStackIdx, -4, -6, -3, -2, -1, -8); + assert( mnStackIdx == 9 ); + writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5, -6 ); + writeCurveTo( mnStackIdx, -4, -6, -3, -2, -1, -8 ); mnStackIdx -= 9; } break; case TYPE2OP::HFLEX: { - assert( mnStackIdx == 7); - writeCurveTo( mnStackIdx, -7, 0, -6, -5, -4, -5); - writeCurveTo( mnStackIdx, -3, -5, -2, 0, -1, 0); + assert( mnStackIdx == 7 ); + writeCurveTo( mnStackIdx, -7, 0, -6, -5, -4, -5 ); + writeCurveTo( mnStackIdx, -3, -5, -2, 0, -1, 0 ); mnStackIdx -= 7; } break; case TYPE2OP::FLEX: { - assert( mnStackIdx == 13); - writeCurveTo( mnStackIdx, -13, -12, -11, -10, -9, -8); - writeCurveTo( mnStackIdx, -7, -6, -5, -4, -3, -2); - const int nFlexDepth = mnValStack[ mnStackIdx-1]; + assert( mnStackIdx == 13 ); + writeCurveTo( mnStackIdx, -13, -12, -11, -10, -9, -8 ); + writeCurveTo( mnStackIdx, -7, -6, -5, -4, -3, -2 ); + const ValType nFlexDepth = mnValStack[ mnStackIdx-1 ]; (void)nFlexDepth; // ignoring nFlexDepth mnStackIdx -= 13; } break; case TYPE2OP::FLEX1: { - assert( mnStackIdx == 11); + assert( mnStackIdx == 11 ); // write the first part of the flex1-hinted curve - writeCurveTo( mnStackIdx, -11, -10, -9, -8, -7, -6); + writeCurveTo( mnStackIdx, -11, -10, -9, -8, -7, -6 ); // determine if nD6 is horizontal or vertical const int i = mnStackIdx; - int nDeltaX = mnValStack[i-11] + mnValStack[i-9] + mnValStack[i-7] + mnValStack[i-5] + mnValStack[i-3]; + ValType nDeltaX = mnValStack[i-11] + mnValStack[i-9] + mnValStack[i-7] + mnValStack[i-5] + mnValStack[i-3]; if( nDeltaX < 0 ) nDeltaX = -nDeltaX; - int nDeltaY = mnValStack[i-10] + mnValStack[i-8] + mnValStack[i-6] + mnValStack[i-4] + mnValStack[i-2]; + ValType nDeltaY = mnValStack[i-10] + mnValStack[i-8] + mnValStack[i-6] + mnValStack[i-4] + mnValStack[i-2]; if( nDeltaY < 0 ) nDeltaY = -nDeltaY; const bool bVertD6 = (nDeltaY > nDeltaX); @@ -1473,14 +1526,14 @@ if( mbSawError) { // -------------------------------------------------------------------- -double CffSubsetterContext::readRealVal() +RealType CffSubsetterContext::readRealVal() { // TODO: more thorough number validity test bool bComma = false; int nExpVal = 0; int nExpSign = 0; S64 nNumber = 0; - double fReal = +1.0; + RealType fReal = +1.0; for(;;){ const U8 c = *(mpReadPtr++); // read nibbles // parse high nibble @@ -1548,6 +1601,7 @@ double CffSubsetterContext::readRealVal() // prepare to access an element inside a CFF/CID index table int CffSubsetterContext::seekIndexData( int nIndexBase, int nDataIndex) { + assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd)); if( nDataIndex < 0) return -1; mpReadPtr = mpBasePtr + nIndexBase; @@ -1578,6 +1632,7 @@ int CffSubsetterContext::seekIndexData( int nIndexBase, int nDataIndex) mpReadEnd = mpReadPtr + (nOfs2 - nOfs1); assert( nOfs1 >= 0); assert( nOfs2 >= nOfs1); + assert( mpReadPtr <= mpBaseEnd); assert( mpReadEnd <= mpBaseEnd); return (nOfs2 - nOfs1); } @@ -1587,10 +1642,12 @@ int CffSubsetterContext::seekIndexData( int nIndexBase, int nDataIndex) // skip over a CFF/CID index table void CffSubsetterContext::seekIndexEnd( int nIndexBase) { + assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd)); mpReadPtr = mpBasePtr + nIndexBase; const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1]; const int nDataOfsSz = mpReadPtr[2]; mpReadPtr += 3 + nDataOfsSz * nDataCount; + assert( mpReadPtr <= mpBaseEnd); int nEndOfs = 0; switch( nDataOfsSz) { default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return; @@ -1602,6 +1659,8 @@ void CffSubsetterContext::seekIndexEnd( int nIndexBase) mpReadPtr += nDataOfsSz; mpReadPtr += nEndOfs - 1; mpReadEnd = mpBaseEnd; + assert( nEndOfs >= 0); + assert( mpReadEnd <= mpBaseEnd); } // ==================================================================== @@ -1944,7 +2003,7 @@ public: void emitAllCrypted( void); int tellPos( void) const; void updateLen( int nTellPos, int nLength); - void emitIntVector( const char* pLineHead, const char* pLineTail, const IntVector&); + void emitValVector( const char* pLineHead, const char* pLineTail, const ValVector&); private: FILE* mpFileOut; bool mbCloseOutfile; @@ -2095,8 +2154,8 @@ void Type1Emitter::emitAllCrypted( void) // -------------------------------------------------------------------- -void Type1Emitter::emitIntVector( const char* pLineHead, const char* pLineTail, - const IntVector& rVector) +void Type1Emitter::emitValVector( const char* pLineHead, const char* pLineTail, + const ValVector& rVector) { // ignore empty vectors if( rVector.empty()) @@ -2105,15 +2164,15 @@ void Type1Emitter::emitIntVector( const char* pLineHead, const char* pLineTail, // emit the line head mpPtr += sprintf( mpPtr, pLineHead); // emit the vector values - IntVector::value_type nVal = 0; - for( IntVector::const_iterator it = rVector.begin();;) { - nVal = *it; + ValVector::value_type aVal = 0; + for( ValVector::const_iterator it = rVector.begin();;) { + aVal = *it; if( ++it == rVector.end() ) break; - mpPtr += sprintf( mpPtr, "%d ", nVal); + mpPtr += sprintf( mpPtr, "%g ", aVal); } // emit the last value - mpPtr += sprintf( mpPtr, "%d", nVal); + mpPtr += sprintf( mpPtr, "%g", aVal); // emit the line tail mpPtr += sprintf( mpPtr, pLineTail); } @@ -2178,12 +2237,16 @@ bool CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter, "/PaintType 0 def\n"); pOut += sprintf( pOut, "/FontName /%s def\n", rEmitter.maSubsetName); pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId); - pOut += sprintf( pOut, "/FontMatrix [0.001 0 0 0.001 0 0 ]readonly def\n"); + // emit FontMatrix + if( maFontMatrix.size() == 6) + rEmitter.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix); + else // emit default FontMatrix if needed + pOut += sprintf( pOut, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n"); + // emit FontBBox if( maFontBBox.size() == 4) - pOut += sprintf( pOut, "/FontBBox [%d %d %d %d ]readonly def\n", - maFontBBox[0], maFontBBox[1], maFontBBox[2], maFontBBox[3]); - else - pOut += sprintf( pOut, "/FontBBox [0 0 999 999]readonly def\n"); + rEmitter.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox); + else // emit default FontBBox if needed + pOut += sprintf( pOut, "/FontBBox {0 0 999 999}readonly def\n"); // emit FONTINFO into TOPDICT pOut += sprintf( pOut, "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count @@ -2259,12 +2322,12 @@ bool CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter, #else // emit blue hint related privdict entries if( !mpCffLocal->maBlueValues.empty()) - rEmitter.emitIntVector( "/BlueValues [", "]ND\n", mpCffLocal->maBlueValues); + rEmitter.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal->maBlueValues); else pOut += sprintf( pOut, "/BlueValues []ND\n"); // default to empty BlueValues - rEmitter.emitIntVector( "/OtherBlues [", "]ND\n", mpCffLocal->maOtherBlues); - rEmitter.emitIntVector( "/FamilyBlues [", "]ND\n", mpCffLocal->maFamilyBlues); - rEmitter.emitIntVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal->maFamilyOtherBlues); + rEmitter.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal->maOtherBlues); + rEmitter.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal->maFamilyBlues); + rEmitter.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal->maFamilyOtherBlues); if( mpCffLocal->mfBlueScale) pOut += sprintf( pOut, "/BlueScale %.6f def\n", mpCffLocal->mfBlueScale); @@ -2278,8 +2341,8 @@ bool CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter, pOut += sprintf( pOut, "/StdHW [%d] def\n", mpCffLocal->mnStemStdHW); if( mpCffLocal->mnStemStdVW) pOut += sprintf( pOut, "/StdVW [%d] def\n", mpCffLocal->mnStemStdVW); - rEmitter.emitIntVector( "/StemSnapH [", "]ND\n", mpCffLocal->maStemSnapH); - rEmitter.emitIntVector( "/StemSnapV [", "]ND\n", mpCffLocal->maStemSnapV); + rEmitter.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal->maStemSnapH); + rEmitter.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal->maStemSnapV); // emit other hints if( mpCffLocal->mbForceBold) @@ -2383,7 +2446,8 @@ bool CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter, // provide details to the subset requesters, TODO: move into own method? // note: Top and Bottom are flipped between Type1 and VCL - rFSInfo.m_aFontBBox = Rectangle( Point( maFontBBox[0], maFontBBox[1] ), Point( maFontBBox[2], maFontBBox[3] ) ); + rFSInfo.m_aFontBBox = Rectangle( Point( static_cast<long>(maFontBBox[0]), static_cast<long>(maFontBBox[1]) ), + Point( static_cast<long>(maFontBBox[2]), static_cast<long>(maFontBBox[3]) ) ); // PDF-Spec says the values below mean the ink bounds! // TODO: use better approximations for these ink bounds rFSInfo.m_nAscent = +rFSInfo.m_aFontBBox.Bottom(); // for capital letters diff --git a/vcl/source/fontsubset/fontsubset.cxx b/vcl/source/fontsubset/fontsubset.cxx index e203feed1645..84f548d0a32f 100644 --- a/vcl/source/fontsubset/fontsubset.cxx +++ b/vcl/source/fontsubset/fontsubset.cxx @@ -40,7 +40,7 @@ FontSubsetInfo::FontSubsetInfo() , m_nCapHeight( 0) , m_nFontType( FontSubsetInfo::NO_FONT) , mpInFontBytes( NULL) -, mnInByteLength( NULL) +, mnInByteLength( 0) , meInFontType( FontSubsetInfo::NO_FONT) , mpSftTTFont( NULL) {} diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx index 345dc162e67e..0a7a8b765b6b 100644 --- a/vcl/source/gdi/outdev3.cxx +++ b/vcl/source/gdi/outdev3.cxx @@ -6,8 +6,6 @@ * * OpenOffice.org - a multi-platform office productivity suite * - * $RCSfile: outdev3.cxx,v $ - * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify @@ -4498,71 +4496,78 @@ void OutputDevice::ImplDrawStrikeoutChar( long nBaseX, long nBaseY, FontStrikeout eStrikeout, Color aColor ) { - BOOL bOldMap = IsMapModeEnabled(); - EnableMapMode( FALSE ); - - Color aOldColor = GetTextColor(); - SetTextColor( aColor ); - ImplInitTextColor(); + // PDF-export does its own strikeout drawing... why again? + if( mpPDFWriter && mpPDFWriter->isBuiltinFont(mpFontEntry->maFontSelData.mpFontData) ) + return; - xub_Unicode pChars[5]; + // prepare string for strikeout measurement + static char cStrikeoutChar; if ( eStrikeout == STRIKEOUT_SLASH ) - pChars[0] = '/'; + cStrikeoutChar = '/'; else // ( eStrikeout == STRIKEOUT_X ) - pChars[0] = 'X'; - pChars[3]=pChars[2]=pChars[1]=pChars[0]; + cStrikeoutChar = 'X'; + static const int nTestStrLen = 4; + static const int nMaxStrikeStrLen = 2048; + xub_Unicode aChars[ nMaxStrikeStrLen +1]; // +1 for valgrind... + for( int i = 0; i < nTestStrLen; ++i) + aChars[i] = cStrikeoutChar; + const String aStrikeoutTest( aChars, nTestStrLen ); // calculate approximation of strikeout atom size long nStrikeoutWidth = nWidth; - String aStrikeoutTest( pChars, 4 ); - SalLayout* pLayout = ImplLayout( aStrikeoutTest, 0, 4 ); - if ( pLayout ) + SalLayout* pLayout = ImplLayout( aStrikeoutTest, 0, nTestStrLen ); + if( pLayout ) { - nStrikeoutWidth = (pLayout->GetTextWidth() + 2) / 4; + nStrikeoutWidth = (pLayout->GetTextWidth() +nTestStrLen/2) / (nTestStrLen * pLayout->GetUnitsPerPixel()); pLayout->Release(); - if ( nStrikeoutWidth <= 0 ) // sanity check - nStrikeoutWidth = 1; } + if( nStrikeoutWidth <= 0 ) // sanity check + return; // calculate acceptable strikeout length // allow the strikeout to be one pixel larger than the text it strikes out - long nMaxWidth = nStrikeoutWidth/2; + long nMaxWidth = nStrikeoutWidth / 2; if ( nMaxWidth < 2 ) nMaxWidth = 2; nMaxWidth += nWidth + 1; - // build strikeout string - long nFullStrikeoutWidth = 0; - String aStrikeoutText( pChars, 0 ); - while ( (nFullStrikeoutWidth+=nStrikeoutWidth) < nMaxWidth+1 ) - aStrikeoutText += pChars[0]; - + int nStrikeStrLen = (nMaxWidth + nStrikeoutWidth - 1) / nStrikeoutWidth; // if the text width is smaller than the strikeout text, then do not // strike out at all. This case requires user interaction, e.g. adding // a space to the text - if ( (aStrikeoutText.Len() > 0) - && !(mpPDFWriter && mpPDFWriter->isBuiltinFont(mpFontEntry->maFontSelData.mpFontData) ) ) - { - if ( mpFontEntry->mnOrientation ) - ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation ); + if( nStrikeStrLen <= 0 ) + return; + if( nStrikeStrLen > nMaxStrikeStrLen ) + nStrikeStrLen = nMaxStrikeStrLen; - // strikeout text has to be left aligned - ULONG nOrigTLM = mnTextLayoutMode; - mnTextLayoutMode = TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_COMPLEX_DISABLED; - SalLayout* pSalLayout = ImplLayout( aStrikeoutText, 0, STRING_LEN ); - mnTextLayoutMode = nOrigTLM; + // build the strikeout string + for( int i = nTestStrLen; i < nStrikeStrLen; ++i) + aChars[i] = cStrikeoutChar; + const String aStrikeoutText( aChars, xub_StrLen(nStrikeStrLen) ); - if ( pSalLayout ) - { - pSalLayout->DrawBase() = Point( nX+mnTextOffX, nY+mnTextOffY ); - pSalLayout->DrawText( *mpGraphics ); - pSalLayout->Release(); - } - } + if( mpFontEntry->mnOrientation ) + ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation ); + + // strikeout text has to be left aligned + ULONG nOrigTLM = mnTextLayoutMode; + mnTextLayoutMode = TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_COMPLEX_DISABLED; + pLayout = ImplLayout( aStrikeoutText, 0, STRING_LEN ); + mnTextLayoutMode = nOrigTLM; + + if( !pLayout ) + return; + + // draw the strikeout text + const Color aOldColor = GetTextColor(); + SetTextColor( aColor ); + ImplInitTextColor(); + + pLayout->DrawBase() = Point( nX+mnTextOffX, nY+mnTextOffY ); + pLayout->DrawText( *mpGraphics ); + pLayout->Release(); SetTextColor( aOldColor ); ImplInitTextColor(); - EnableMapMode( bOldMap ); } // ----------------------------------------------------------------------- @@ -6777,17 +6782,21 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect, { BOOL bHighContrastBlack = FALSE; BOOL bHighContrastWhite = FALSE; - Color aCol; - if( IsBackground() ) - aCol = GetBackground().GetColor(); - else - // best guess is the face color here - // but it may be totally wrong. the background color - // was typically already reset - aCol = GetSettings().GetStyleSettings().GetFaceColor(); + const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() ); + if( rStyleSettings.GetHighContrastMode() ) + { + Color aCol; + if( IsBackground() ) + aCol = GetBackground().GetColor(); + else + // best guess is the face color here + // but it may be totally wrong. the background color + // was typically already reset + aCol = rStyleSettings.GetFaceColor(); - bHighContrastBlack = aCol.IsDark(); - bHighContrastWhite = aCol.IsBright() && GetSettings().GetStyleSettings().GetHighContrastMode(); + bHighContrastBlack = aCol.IsDark(); + bHighContrastWhite = aCol.IsBright(); + } aOldTextColor = GetTextColor(); if ( IsTextFillColor() ) @@ -6795,8 +6804,6 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect, bRestoreFillColor = TRUE; aOldTextFillColor = GetTextFillColor(); } - else - bRestoreFillColor = FALSE; if( bHighContrastBlack ) SetTextColor( COL_GREEN ); else if( bHighContrastWhite ) @@ -6811,7 +6818,7 @@ void OutputDevice::ImplDrawText( const Rectangle& rRect, aRect.Move( 1, 1 ); DrawText( aRect, rOrigStr, nStyle & ~TEXT_DRAW_DISABLE ); */ - SetTextColor( GetSettings().GetStyleSettings().GetShadowColor() ); + SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() ); } } @@ -7445,13 +7452,18 @@ void OutputDevice::DrawCtrlText( const Point& rPos, const XubString& rStr, BOOL bRestoreFillColor; BOOL bHighContrastBlack = FALSE; BOOL bHighContrastWhite = FALSE; - if( IsBackground() ) + const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() ); + if( rStyleSettings.GetHighContrastMode() ) { - Wallpaper aWall = GetBackground(); - Color aCol = aWall.GetColor(); - bHighContrastBlack = aCol.IsDark(); - bHighContrastWhite = aCol.IsBright() && GetSettings().GetStyleSettings().GetHighContrastMode(); + if( IsBackground() ) + { + Wallpaper aWall = GetBackground(); + Color aCol = aWall.GetColor(); + bHighContrastBlack = aCol.IsDark(); + bHighContrastWhite = aCol.IsBright(); + } } + aOldTextColor = GetTextColor(); if ( IsTextFillColor() ) { @@ -7466,7 +7478,7 @@ void OutputDevice::DrawCtrlText( const Point& rPos, const XubString& rStr, else if( bHighContrastWhite ) SetTextColor( COL_LIGHTGREEN ); else - SetTextColor( GetSettings().GetStyleSettings().GetShadowColor() ); + SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() ); DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText ); if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector ) diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 2cbebf6f23e2..e7ee18ec7705 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -805,7 +805,7 @@ class Matrix3 { double f[6]; - void set( double *pn ) { for( int i = 0 ; i < 5; i++ ) f[i] = pn[i]; } + void set( double *pn ) { for( int i = 0 ; i < 6; i++ ) f[i] = pn[i]; } public: Matrix3(); ~Matrix3() {} @@ -6787,14 +6787,15 @@ void PDFWriterImpl::drawHorizontalGlyphs( for( sal_uInt32 nPos = nBeginRun+1; nPos < aRunEnds[nRun]; nPos++ ) { appendHex( rGlyphs[nPos].m_nMappedGlyphId, aUnkernedLine ); - // check if glyph advance matches with the width of the previous glyph, else adjust + // check if default glyph positioning is sufficient const Point aThisPos = aMat.transform( rGlyphs[nPos].m_aPos ); const Point aPrevPos = aMat.transform( rGlyphs[nPos-1].m_aPos ); double fAdvance = aThisPos.X() - aPrevPos.X(); - fAdvance *= 1000.0 / (fXScale * nPixelFontHeight); - const sal_Int32 nAdjustment = rGlyphs[nPos-1].m_nNativeWidth - sal_Int32(fAdvance+0.5); + fAdvance *= 1000.0 / nPixelFontHeight; + const sal_Int32 nAdjustment = (sal_Int32)(rGlyphs[nPos-1].m_nNativeWidth - fAdvance + 0.5); if( nAdjustment != 0 ) { + // apply individual glyph positioning bNeedKern = true; aKernedLine.append( ">" ); aKernedLine.append( nAdjustment ); @@ -8643,6 +8644,8 @@ void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const PDFWriter::ExtLine for(sal_uInt32 a(0); a < nEdgeCount; a++) { + if( a > 0 ) + aLine.append( " " ); const sal_uInt32 nNextIndex((a + 1) % nPointCount); const basegfx::B2DPoint aNext(aPoly.getB2DPoint(nNextIndex)); diff --git a/vcl/source/gdi/wall.cxx b/vcl/source/gdi/wall.cxx index e0c69ce582f4..587395fa783f 100644 --- a/vcl/source/gdi/wall.cxx +++ b/vcl/source/gdi/wall.cxx @@ -469,7 +469,7 @@ Gradient Wallpaper::ImplGetApplicationGradient() const g.SetStyle( GRADIENT_LINEAR ); g.SetStartColor( Application::GetSettings().GetStyleSettings().GetFaceColor() ); // no 'extreme' gradient when high contrast - if( Application::GetSettings().GetStyleSettings().GetFaceColor().IsDark() ) + if( Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) g.SetEndColor( Application::GetSettings().GetStyleSettings().GetFaceColor() ); else g.SetEndColor( Application::GetSettings().GetStyleSettings().GetFaceGradientColor() ); diff --git a/vcl/source/glyphs/graphite_adaptors.cxx b/vcl/source/glyphs/graphite_adaptors.cxx index 67330698ffdf..9b16318fdc40 100644 --- a/vcl/source/glyphs/graphite_adaptors.cxx +++ b/vcl/source/glyphs/graphite_adaptors.cxx @@ -47,7 +47,7 @@ #include <rtl/ustring.hxx> #include <i18npool/mslangid.hxx> // Platform -#ifndef MSC +#ifndef WNT #include <saldisp.hxx> #include <vcl/salgdi.hxx> diff --git a/vcl/source/glyphs/graphite_cache.cxx b/vcl/source/glyphs/graphite_cache.cxx index c1bca0f87cb8..8c514c611d2c 100644 --- a/vcl/source/glyphs/graphite_cache.cxx +++ b/vcl/source/glyphs/graphite_cache.cxx @@ -28,7 +28,7 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" -#ifdef MSC +#ifdef WNT #include <tools/svwin.h> #include <svsys.h> #endif diff --git a/vcl/source/glyphs/graphite_features.cxx b/vcl/source/glyphs/graphite_features.cxx index 3c5214d3c420..dae1bfc2866e 100644 --- a/vcl/source/glyphs/graphite_features.cxx +++ b/vcl/source/glyphs/graphite_features.cxx @@ -38,7 +38,7 @@ #include <sal/types.h> -#ifdef MSC +#ifdef WNT #include <tools/svwin.h> #include <svsys.h> #endif diff --git a/vcl/source/glyphs/graphite_layout.cxx b/vcl/source/glyphs/graphite_layout.cxx index 751c3694d033..86dee2749efa 100644 --- a/vcl/source/glyphs/graphite_layout.cxx +++ b/vcl/source/glyphs/graphite_layout.cxx @@ -54,7 +54,7 @@ #include <deque> // Platform -#ifdef MSC +#ifdef WNT #include <tools/svwin.h> #include <svsys.h> #endif @@ -86,7 +86,7 @@ FILE * grLogFile = NULL; FILE * grLog() { -#ifdef MSC +#ifdef WNT std::string logFileName(getenv("TEMP")); logFileName.append("\\graphitelayout.log"); if (grLogFile == NULL) grLogFile = fopen(logFileName.c_str(),"w"); @@ -135,7 +135,7 @@ namespace UErrorCode status = U_ZERO_ERROR; UBiDi *ubidi = ubidi_openSized(charCount, 0, &status); int limit = 0; - ubidi_setPara(ubidi, buffer, charCount, + ubidi_setPara(ubidi, reinterpret_cast<const UChar *>(buffer), charCount, (rtl)?UBIDI_DEFAULT_RTL:UBIDI_DEFAULT_LTR, NULL, &status); UBiDiLevel level = 0; ubidi_getLogicalRun(ubidi, 0, &limit, &level); diff --git a/vcl/source/glyphs/graphite_serverfont.cxx b/vcl/source/glyphs/graphite_serverfont.cxx index e8cd152b43ac..be424c94b9d2 100644 --- a/vcl/source/glyphs/graphite_serverfont.cxx +++ b/vcl/source/glyphs/graphite_serverfont.cxx @@ -45,7 +45,7 @@ #include "graphite_textsrc.hxx" #include <vcl/graphite_serverfont.hxx> -#ifndef MSC +#ifndef WNT // // An implementation of the GraphiteLayout interface to enable Graphite enabled fonts to be used. diff --git a/vcl/source/helper/lazydelete.cxx b/vcl/source/helper/lazydelete.cxx index f5a8d8fbb14e..a300aedf8175 100644 --- a/vcl/source/helper/lazydelete.cxx +++ b/vcl/source/helper/lazydelete.cxx @@ -84,6 +84,9 @@ template<> bool LazyDeletor<Menu>::is_less( Menu* left, Menu* right ) DeleteOnDeinitBase::~DeleteOnDeinitBase() { + ImplSVData* pSVData = ImplGetSVData(); + if( pSVData && pSVData->mpDeinitDeleteList != NULL ) + pSVData->mpDeinitDeleteList->remove( this ); } void DeleteOnDeinitBase::addDeinitContainer( DeleteOnDeinitBase* i_pContainer ) diff --git a/vcl/source/window/brdwin.cxx b/vcl/source/window/brdwin.cxx index f8baad0b4137..c9e8d11557e8 100644 --- a/vcl/source/window/brdwin.cxx +++ b/vcl/source/window/brdwin.cxx @@ -1840,7 +1840,7 @@ void ImplBorderWindow::ImplInit( Window* pParent, { // Alle WindowBits entfernen, die wir nicht haben wollen WinBits nOrgStyle = nStyle; - WinBits nTestStyle = (WB_MOVEABLE | WB_SIZEABLE | WB_ROLLABLE | WB_PINABLE | WB_CLOSEABLE | WB_STANDALONE | WB_DIALOGCONTROL | WB_NODIALOGCONTROL | WB_SYSTEMFLOATWIN | WB_INTROWIN | WB_DEFAULTWIN | WB_TOOLTIPWIN | WB_NOSHADOW | WB_OWNERDRAWDECORATION | WB_SYSTEMCHILDWINDOW ); + WinBits nTestStyle = (WB_MOVEABLE | WB_SIZEABLE | WB_ROLLABLE | WB_PINABLE | WB_CLOSEABLE | WB_STANDALONE | WB_DIALOGCONTROL | WB_NODIALOGCONTROL | WB_SYSTEMFLOATWIN | WB_INTROWIN | WB_DEFAULTWIN | WB_TOOLTIPWIN | WB_NOSHADOW | WB_OWNERDRAWDECORATION | WB_SYSTEMCHILDWINDOW | WB_NEEDSFOCUS); if ( nTypeStyle & BORDERWINDOW_STYLE_APP ) nTestStyle |= WB_APP; nStyle &= nTestStyle; diff --git a/vcl/source/window/dockmgr.cxx b/vcl/source/window/dockmgr.cxx index b5f1ada74a98..c587b7ad8441 100644 --- a/vcl/source/window/dockmgr.cxx +++ b/vcl/source/window/dockmgr.cxx @@ -1238,8 +1238,8 @@ void ImplDockingWindowWrapper::StartPopupMode( ToolBox *pParentToolBox ) ULONG nFlags = FLOATWIN_POPUPMODE_ALLOWTEAROFF | FLOATWIN_POPUPMODE_NOFOCUSCLOSE | FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE | - FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE | - FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE; + FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE; +// |FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE; // if the subtoolbar was opened via keyboard make sure that key events // will go into subtoolbar diff --git a/vcl/source/window/floatwin.cxx b/vcl/source/window/floatwin.cxx index 7bcb90bbb8fc..5f1578c4b9e2 100644 --- a/vcl/source/window/floatwin.cxx +++ b/vcl/source/window/floatwin.cxx @@ -243,6 +243,13 @@ FloatingWindow::~FloatingWindow() // ----------------------------------------------------------------------- +Point FloatingWindow::CalcFloatingPosition( Window* pWindow, const Rectangle& rRect, ULONG nFlags, USHORT& rArrangeIndex ) +{ + return ImplCalcPos( pWindow, rRect, nFlags, rArrangeIndex ); +} + +// ----------------------------------------------------------------------- + Point FloatingWindow::ImplCalcPos( Window* pWindow, const Rectangle& rRect, ULONG nFlags, USHORT& rArrangeIndex ) @@ -676,8 +683,6 @@ void FloatingWindow::StartPopupMode( const Rectangle& rRect, ULONG nFlags ) // avoid close on focus change for decorated floating windows only if( mpWindowImpl->mbFrame && (GetStyle() & WB_MOVEABLE) ) nFlags |= FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE; - else - nFlags &= ~FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE; // #102010# For debugging Accessibility static const char* pEnv = getenv("SAL_FLOATWIN_NOAPPFOCUSCLOSE" ); @@ -751,8 +756,9 @@ void FloatingWindow::StartPopupMode( ToolBox* pBox, ULONG nFlags ) // FLOATWIN_POPUPMODE_NOMOUSECLOSE | FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE | // FLOATWIN_POPUPMODE_NOMOUSERECTCLOSE | // #105968# floating toolboxes should close when clicked in (parent's) float rect - FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE | - FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE; + FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE; +// | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE; + /* * FLOATWIN_POPUPMODE_NOKEYCLOSE | * don't set since it disables closing floaters with escape diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx index ccf75dbd59b3..ebd4475a80fc 100644 --- a/vcl/source/window/menu.cxx +++ b/vcl/source/window/menu.cxx @@ -557,7 +557,7 @@ public: void DataChanged( const DataChangedEvent& rDCEvt ); - void SetImages( long nMaxHeight = 0 ); + void SetImages( long nMaxHeight = 0, bool bForce = false ); void calcMinSize(); Size getMinSize(); @@ -591,7 +591,7 @@ void DecoToolBox::DataChanged( const DataChangedEvent& rDCEvt ) { calcMinSize(); SetBackground(); - SetImages(); + SetImages( 0, true); } } @@ -625,7 +625,7 @@ Size DecoToolBox::getMinSize() return maMinSize; } -void DecoToolBox::SetImages( long nMaxHeight ) +void DecoToolBox::SetImages( long nMaxHeight, bool bForce ) { long border = getMinSize().Height() - maImage.GetSizePixel().Height(); @@ -635,13 +635,13 @@ void DecoToolBox::SetImages( long nMaxHeight ) if( nMaxHeight < getMinSize().Height() ) nMaxHeight = getMinSize().Height(); - if( lastSize != nMaxHeight - border ) + if( (lastSize != nMaxHeight - border) || bForce ) { lastSize = nMaxHeight - border; Color aEraseColor( 255, 255, 255, 255 ); BitmapEx aBmpExDst( maImage.GetBitmapEx() ); - BitmapEx aBmpExSrc( GetSettings().GetStyleSettings().GetMenuBarColor().IsDark() ? + BitmapEx aBmpExSrc( GetSettings().GetStyleSettings().GetHighContrastMode() ? maImageHC.GetBitmapEx() : aBmpExDst ); aEraseColor.SetTransparency( 255 ); @@ -2731,7 +2731,14 @@ void Menu::ImplPaint( Window* pWin, USHORT nBorder, long nStartY, MenuItemData* } if ( pThisItemOnly && bHighlighted ) - pWin->SetTextColor( rSettings.GetMenuTextColor() ); + { + // This restores the normal menu or menu bar text + // color for when it is no longer highlighted. + if ( bIsMenuBar ) + pWin->SetTextColor( rSettings.GetMenuBarTextColor() ); + else + pWin->SetTextColor( rSettings.GetMenuTextColor() ); + } } if( bLayout ) { @@ -3787,7 +3794,10 @@ static void ImplInitMenuWindow( Window* pWin, BOOL bFont, BOOL bMenuBar ) pWin->SetBackground( Wallpaper( rStyleSettings.GetMenuColor() ) ); } - pWin->SetTextColor( rStyleSettings.GetMenuTextColor() ); + if ( bMenuBar ) + pWin->SetTextColor( rStyleSettings.GetMenuBarTextColor() ); + else + pWin->SetTextColor( rStyleSettings.GetMenuTextColor() ); pWin->SetTextFillColor(); pWin->SetLineColor(); } @@ -5056,7 +5066,7 @@ MenuBarWindow::MenuBarWindow( Window* pParent ) : aCloser.SetParentClipMode( PARENTCLIPMODE_NOCLIP ); aCloser.InsertItem( IID_DOCUMENTCLOSE, - GetSettings().GetStyleSettings().GetMenuBarColor().IsDark() ? aCloser.maImageHC : aCloser.maImage, 0 ); + GetSettings().GetStyleSettings().GetHighContrastMode() ? aCloser.maImageHC : aCloser.maImage, 0 ); aCloser.SetSelectHdl( LINK( this, MenuBarWindow, CloserHdl ) ); aCloser.AddEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) ); aCloser.SetQuickHelpText( IID_DOCUMENTCLOSE, XubString( ResId( SV_HELPTEXT_CLOSEDOCUMENT, *pResMgr ) ) ); @@ -5697,7 +5707,7 @@ void MenuBarWindow::Paint( const Rectangle& ) // in high contrast mode draw a separating line on the lower edge if( ! IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) && - GetSettings().GetStyleSettings().GetFaceColor().IsDark() ) + GetSettings().GetStyleSettings().GetHighContrastMode() ) { Push( PUSH_LINECOLOR | PUSH_MAPMODE ); SetLineColor( Color( COL_WHITE ) ); diff --git a/vcl/source/window/msgbox.cxx b/vcl/source/window/msgbox.cxx index bd727092a836..3d3245af831f 100644 --- a/vcl/source/window/msgbox.cxx +++ b/vcl/source/window/msgbox.cxx @@ -500,7 +500,7 @@ void InfoBox::ImplInitInfoBoxData() if ( !GetText().Len() ) SetText( Application::GetDisplayName() ); - SetImage( GetSettings().GetStyleSettings().GetDialogColor().IsDark() ? + SetImage( GetSettings().GetStyleSettings().GetHighContrastMode() ? InfoBox::GetStandardImageHC() : InfoBox::GetStandardImage() ); mnSoundType = ((USHORT)SOUND_INFO)+1; } @@ -591,7 +591,7 @@ void ErrorBox::ImplInitErrorBoxData() if ( !GetText().Len() ) SetText( Application::GetDisplayName() ); - SetImage( GetSettings().GetStyleSettings().GetDialogColor().IsDark() ? + SetImage( GetSettings().GetStyleSettings().GetHighContrastMode() ? ErrorBox::GetStandardImageHC() : ErrorBox::GetStandardImage() ); mnSoundType = ((USHORT)SOUND_ERROR)+1; } @@ -637,7 +637,7 @@ void QueryBox::ImplInitQueryBoxData() if ( !GetText().Len() ) SetText( Application::GetDisplayName() ); - SetImage( GetSettings().GetStyleSettings().GetDialogColor().IsDark() ? + SetImage( GetSettings().GetStyleSettings().GetHighContrastMode() ? QueryBox::GetStandardImageHC() : QueryBox::GetStandardImage() ); mnSoundType = ((USHORT)SOUND_QUERY)+1; } diff --git a/vcl/source/window/toolbox.cxx b/vcl/source/window/toolbox.cxx index bb1f428c6626..8aa4926f5e1a 100644 --- a/vcl/source/window/toolbox.cxx +++ b/vcl/source/window/toolbox.cxx @@ -397,7 +397,7 @@ void ToolBox::ImplDrawGradientBackground( ToolBox* pThis, ImplDockingWindowWrapp Color startCol, endCol; startCol = pThis->GetSettings().GetStyleSettings().GetFaceGradientColor(); endCol = pThis->GetSettings().GetStyleSettings().GetFaceColor(); - if( endCol.IsDark() ) + if( pThis->GetSettings().GetStyleSettings().GetHighContrastMode() ) // no 'extreme' gradient when high contrast startCol = endCol; @@ -1901,37 +1901,78 @@ BOOL ToolBox::ImplCalcItem() nDefWidth = GetDefaultImageSize().Width(); nDefHeight = GetDefaultImageSize().Height(); + mnWinHeight = 0; // determine minimum size necessary in NWF - if( IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) ) { Rectangle aRect( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) ); - Region aArrowReg = aRect; + Region aReg = aRect; ImplControlValue aVal; Region aNativeBounds, aNativeContent; - if( GetNativeControlRegion( CTRL_TOOLBAR, PART_BUTTON, - aArrowReg, + if( IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) ) + { + if( GetNativeControlRegion( CTRL_TOOLBAR, PART_BUTTON, + aReg, + CTRL_STATE_ENABLED | CTRL_STATE_ROLLOVER, + aVal, OUString(), + aNativeBounds, aNativeContent ) ) + { + aRect = aNativeBounds.GetBoundRect(); + if( aRect.GetWidth() > nMinWidth ) + nMinWidth = aRect.GetWidth(); + if( aRect.GetHeight() > nMinHeight ) + nMinHeight = aRect.GetHeight(); + if( nDropDownArrowWidth < nMinWidth ) + nDropDownArrowWidth = nMinWidth; + if( nMinWidth > mpData->mnMenuButtonWidth ) + mpData->mnMenuButtonWidth = nMinWidth; + else if( nMinWidth < TB_MENUBUTTON_SIZE ) + mpData->mnMenuButtonWidth = TB_MENUBUTTON_SIZE; + } + } + + // also calculate the area for comboboxes, drop down list boxes and spinfields + // as these are often inserted into toolboxes; set mnWinHeight to the + // greater of those values to prevent toolbar flickering (#i103385#) + aRect = Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) ); + aReg = aRect; + if( GetNativeControlRegion( CTRL_COMBOBOX, PART_ENTIRE_CONTROL, + aReg, + CTRL_STATE_ENABLED | CTRL_STATE_ROLLOVER, + aVal, OUString(), + aNativeBounds, aNativeContent ) ) + { + aRect = aNativeBounds.GetBoundRect(); + if( aRect.GetHeight() > mnWinHeight ) + mnWinHeight = aRect.GetHeight(); + } + aRect = Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) ); + aReg = aRect; + if( GetNativeControlRegion( CTRL_LISTBOX, PART_ENTIRE_CONTROL, + aReg, CTRL_STATE_ENABLED | CTRL_STATE_ROLLOVER, aVal, OUString(), aNativeBounds, aNativeContent ) ) { aRect = aNativeBounds.GetBoundRect(); - if( aRect.GetWidth() > nMinWidth ) - nMinWidth = aRect.GetWidth(); - if( aRect.GetHeight() > nMinHeight ) - nMinHeight = aRect.GetHeight(); - if( nDropDownArrowWidth < nMinWidth ) - nDropDownArrowWidth = nMinWidth; - if( nMinWidth > mpData->mnMenuButtonWidth ) - mpData->mnMenuButtonWidth = nMinWidth; - else if( nMinWidth < TB_MENUBUTTON_SIZE ) - mpData->mnMenuButtonWidth = TB_MENUBUTTON_SIZE; + if( aRect.GetHeight() > mnWinHeight ) + mnWinHeight = aRect.GetHeight(); + } + aRect = Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) ); + aReg = aRect; + if( GetNativeControlRegion( CTRL_SPINBOX, PART_ENTIRE_CONTROL, + aReg, + CTRL_STATE_ENABLED | CTRL_STATE_ROLLOVER, + aVal, OUString(), + aNativeBounds, aNativeContent ) ) + { + aRect = aNativeBounds.GetBoundRect(); + if( aRect.GetHeight() > mnWinHeight ) + mnWinHeight = aRect.GetHeight(); } } if ( ! mpData->m_aItems.empty() ) { - mnWinHeight = 0; - std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin(); while ( it != mpData->m_aItems.end() ) { diff --git a/vcl/source/window/toolbox2.cxx b/vcl/source/window/toolbox2.cxx index 7fa8f76e1586..9ec86fab20de 100644 --- a/vcl/source/window/toolbox2.cxx +++ b/vcl/source/window/toolbox2.cxx @@ -2413,10 +2413,10 @@ void ToolBox::ImplUpdateImageList() { if (mpData->mpImageListProvider != NULL) { - BOOL bIsDark = GetSettings().GetStyleSettings().GetFaceColor().IsDark(); + BOOL bHC = GetSettings().GetStyleSettings().GetHighContrastMode(); try { - ImageListType eType = bIsDark ? vcl::HIGHCONTRAST_YES : vcl::HIGHCONTRAST_NO; + ImageListType eType = bHC ? vcl::HIGHCONTRAST_YES : vcl::HIGHCONTRAST_NO; if (eType != mpData->meImageListType) { diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index 5333d20d4306..6aff4779d8b2 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -292,6 +292,13 @@ bool Window::ImplCheckUIFont( const Font& rFont ) void Window::ImplUpdateGlobalSettings( AllSettings& rSettings, BOOL bCallHdl ) { + // reset high contrast to false, so the system can either update it + // or AutoDetectSystemHC can kick in (see below) + StyleSettings aTmpSt( rSettings.GetStyleSettings() ); + aTmpSt.SetHighContrastMode( FALSE ); + rSettings.SetStyleSettings( aTmpSt ); + ImplGetFrame()->UpdateSettings( rSettings ); + // Verify availability of the configured UI font, otherwise choose "Andale Sans UI" String aUserInterfaceFont; bool bUseSystemFont = rSettings.GetStyleSettings().GetUseSystemUIFonts(); @@ -472,7 +479,8 @@ void Window::ImplUpdateGlobalSettings( AllSettings& rSettings, BOOL bCallHdl ) rSettings.SetStyleSettings( aStyleSettings ); - // #104427# auto detect HC mode ? + // auto detect HC mode; if the system already set it to "yes" + // (see above) then accept that if( !rSettings.GetStyleSettings().GetHighContrastMode() ) { sal_Bool bTmp = sal_False, bAutoHCMode = sal_True; @@ -728,7 +736,7 @@ void Window::ImplInit( Window* pParent, WinBits nStyle, SystemParentData* pSyste nBorderTypeStyle |= BORDERWINDOW_STYLE_FRAME; nStyle |= WB_BORDER; } - ImplBorderWindow* pBorderWin = new ImplBorderWindow( pParent, nStyle & (WB_BORDER | WB_DIALOGCONTROL | WB_NODIALOGCONTROL), nBorderTypeStyle ); + ImplBorderWindow* pBorderWin = new ImplBorderWindow( pParent, nStyle & (WB_BORDER | WB_DIALOGCONTROL | WB_NODIALOGCONTROL | WB_NEEDSFOCUS), nBorderTypeStyle ); ((Window*)pBorderWin)->mpWindowImpl->mpClientWindow = this; pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder ); mpWindowImpl->mpBorderWindow = pBorderWin; @@ -783,6 +791,8 @@ void Window::ImplInit( Window* pParent, WinBits nStyle, SystemParentData* pSyste nFrameStyle = SAL_FRAME_STYLE_FLOAT; if( nStyle & WB_OWNERDRAWDECORATION ) nFrameStyle |= (SAL_FRAME_STYLE_OWNERDRAWDECORATION | SAL_FRAME_STYLE_NOSHADOW); + if( nStyle & WB_NEEDSFOCUS ) + nFrameStyle |= SAL_FRAME_STYLE_FLOAT_FOCUSABLE; } else if( mpWindowImpl->mbFloatWin ) nFrameStyle |= SAL_FRAME_STYLE_TOOLWINDOW; @@ -923,7 +933,7 @@ void Window::ImplInit( Window* pParent, WinBits nStyle, SystemParentData* pSyste ! (nStyle & (WB_INTROWIN|WB_DEFAULTWIN)) ) { - mpWindowImpl->mpFrame->UpdateSettings( *pSVData->maAppData.mpSettings ); + // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings ImplUpdateGlobalSettings( *pSVData->maAppData.mpSettings ); OutputDevice::SetSettings( *pSVData->maAppData.mpSettings ); pSVData->maAppData.mbSettingsInit = TRUE; diff --git a/vcl/unx/gtk/a11y/atktext.cxx b/vcl/unx/gtk/a11y/atktext.cxx index 8bdfe1706962..8d83ca008e4a 100644 --- a/vcl/unx/gtk/a11y/atktext.cxx +++ b/vcl/unx/gtk/a11y/atktext.cxx @@ -33,12 +33,15 @@ #include "atkwrapper.hxx" #include "atktextattributes.hxx" +#include <algorithm> #include <com/sun/star/accessibility/AccessibleTextType.hpp> #include <com/sun/star/accessibility/TextSegment.hpp> #include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp> #include <com/sun/star/accessibility/XAccessibleText.hpp> #include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp> +#include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp> +#include <com/sun/star/text/TextMarkupType.hpp> // #define ENABLE_TRACING @@ -175,6 +178,27 @@ static accessibility::XAccessibleText* /*****************************************************************************/ +static accessibility::XAccessibleTextMarkup* + getTextMarkup( AtkText *pText ) throw (uno::RuntimeException) +{ + AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText ); + if( pWrap ) + { + if( !pWrap->mpTextMarkup && pWrap->mpContext ) + { + uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTextMarkup::static_type(NULL) ); + pWrap->mpTextMarkup = reinterpret_cast< accessibility::XAccessibleTextMarkup * > (any.pReserved); + pWrap->mpTextMarkup->acquire(); + } + + return pWrap->mpTextMarkup; + } + + return NULL; +} + +/*****************************************************************************/ + static accessibility::XAccessibleTextAttributes* getTextAttributes( AtkText *pText ) throw (uno::RuntimeException) { @@ -434,6 +458,8 @@ text_wrapper_get_run_attributes( AtkText *text, AtkAttributeSet *pSet = NULL; try { + bool bOffsetsAreValid = false; + accessibility::XAccessibleText* pText = getText( text ); accessibility::XAccessibleTextAttributes* pTextAttributes = getTextAttributes( text ); if( pText && pTextAttributes ) @@ -456,10 +482,47 @@ text_wrapper_get_run_attributes( AtkText *text, // *end_offset = aTextSegment.SegmentEnd + 1; // FIXME: TESTME *end_offset = aTextSegment.SegmentEnd; // <-- + bOffsetsAreValid = true; + } + } + + // Special handling for missspelled + accessibility::XAccessibleTextMarkup* pTextMarkup = getTextMarkup( text ); + if( pTextMarkup ) + { + uno::Sequence< accessibility::TextSegment > aTextSegmentSeq = + pTextMarkup->getTextMarkupAtIndex( offset, com::sun::star::text::TextMarkupType::SPELLCHECK ); + if( aTextSegmentSeq.getLength() > 0 ) + { + accessibility::TextSegment aTextSegment = aTextSegmentSeq[0]; + gint nStartOffsetMisspelled = aTextSegment.SegmentStart; + gint nEndOffsetMisspelled = aTextSegment.SegmentEnd; + + // Get attribute run here if it hasn't been done before + if( !bOffsetsAreValid ) + { + accessibility::TextSegment aAttributeTextSegment = + pText->getTextAtIndex(offset, accessibility::AccessibleTextType::ATTRIBUTE_RUN); + *start_offset = aAttributeTextSegment.SegmentStart; + *end_offset = aAttributeTextSegment.SegmentEnd; + } + + if( nEndOffsetMisspelled <= offset ) + *start_offset = ::std::max( *start_offset, nEndOffsetMisspelled ); + else if( nStartOffsetMisspelled <= offset ) + *start_offset = ::std::max( *start_offset, nStartOffsetMisspelled ); + + if( nStartOffsetMisspelled > offset ) + *end_offset = ::std::min( *end_offset, nStartOffsetMisspelled ); + else if( nEndOffsetMisspelled > offset ) + *end_offset = ::std::min( *end_offset, nEndOffsetMisspelled ); + + if( nStartOffsetMisspelled <= offset && nEndOffsetMisspelled > offset ) + pSet = attribute_set_prepend_misspelled( pSet ); } } } - catch(const uno::Exception& e) { + catch(const uno::Exception& e){ g_warning( "Exception in get_run_attributes()" ); diff --git a/vcl/unx/gtk/a11y/atktextattributes.cxx b/vcl/unx/gtk/a11y/atktextattributes.cxx index f6b1eccc882a..58dd5f200bbd 100644 --- a/vcl/unx/gtk/a11y/atktextattributes.cxx +++ b/vcl/unx/gtk/a11y/atktextattributes.cxx @@ -76,6 +76,7 @@ static AtkTextAttribute atk_text_attribute_tab_interval = ATK_TEXT_ATTR_INVALID; static AtkTextAttribute atk_text_attribute_tab_stops = ATK_TEXT_ATTR_INVALID; static AtkTextAttribute atk_text_attribute_writing_mode = ATK_TEXT_ATTR_INVALID; static AtkTextAttribute atk_text_attribute_vertical_align = ATK_TEXT_ATTR_INVALID; +static AtkTextAttribute atk_text_attribute_misspelled = ATK_TEXT_ATTR_INVALID; /*****************************************************************************/ @@ -1299,6 +1300,18 @@ attribute_set_new_from_property_values( } +AtkAttributeSet* attribute_set_prepend_misspelled( AtkAttributeSet* attribute_set ) +{ + if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_misspelled ) + atk_text_attribute_misspelled = atk_text_attribute_register( "text-spelling" ); + + attribute_set = attribute_set_prepend( attribute_set, atk_text_attribute_misspelled, + g_strdup_printf( "misspelled" ) ); + + return attribute_set; +} + + /*****************************************************************************/ struct AtkTextAttrMapping diff --git a/vcl/unx/gtk/a11y/atktextattributes.hxx b/vcl/unx/gtk/a11y/atktextattributes.hxx index 909f09eb1522..ca67fd946a20 100644 --- a/vcl/unx/gtk/a11y/atktextattributes.hxx +++ b/vcl/unx/gtk/a11y/atktextattributes.hxx @@ -47,5 +47,6 @@ attribute_set_map_to_property_values( AtkAttributeSet* attribute_set, com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& rValueList ); +AtkAttributeSet* attribute_set_prepend_misspelled( AtkAttributeSet* attribute_set ); #endif diff --git a/vcl/unx/gtk/a11y/atkwrapper.cxx b/vcl/unx/gtk/a11y/atkwrapper.cxx index 927b8548a77a..8854083e1509 100644 --- a/vcl/unx/gtk/a11y/atkwrapper.cxx +++ b/vcl/unx/gtk/a11y/atkwrapper.cxx @@ -40,6 +40,7 @@ #include <com/sun/star/accessibility/AccessibleStateType.hpp> #include <com/sun/star/accessibility/XAccessible.hpp> #include <com/sun/star/accessibility/XAccessibleText.hpp> +#include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp> #include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp> #include <com/sun/star/accessibility/XAccessibleValue.hpp> #include <com/sun/star/accessibility/XAccessibleAction.hpp> @@ -893,6 +894,7 @@ void atk_object_wrapper_dispose(AtkObjectWrapper* wrapper) RELEASE( wrapper->mpMultiLineText ) RELEASE( wrapper->mpTable ) RELEASE( wrapper->mpText ) + RELEASE( wrapper->mpTextMarkup ) RELEASE( wrapper->mpTextAttributes ) RELEASE( wrapper->mpValue ) } diff --git a/vcl/unx/gtk/a11y/atkwrapper.hxx b/vcl/unx/gtk/a11y/atkwrapper.hxx index 1003d0d25cc7..95cf30096e7b 100644 --- a/vcl/unx/gtk/a11y/atkwrapper.hxx +++ b/vcl/unx/gtk/a11y/atkwrapper.hxx @@ -49,6 +49,7 @@ namespace com { namespace sun { namespace star { namespace accessibility { class XAccessibleSelection; class XAccessibleTable; class XAccessibleText; + class XAccessibleTextMarkup; class XAccessibleTextAttributes; class XAccessibleValue; } } } } @@ -69,6 +70,7 @@ struct _AtkObjectWrapper ::com::sun::star::accessibility::XAccessibleSelection *mpSelection; ::com::sun::star::accessibility::XAccessibleTable *mpTable; ::com::sun::star::accessibility::XAccessibleText *mpText; + ::com::sun::star::accessibility::XAccessibleTextMarkup *mpTextMarkup; ::com::sun::star::accessibility::XAccessibleTextAttributes *mpTextAttributes; ::com::sun::star::accessibility::XAccessibleValue *mpValue; diff --git a/vcl/unx/gtk/app/gtkinst.cxx b/vcl/unx/gtk/app/gtkinst.cxx index 73b4432342bf..8bed40fa539f 100644 --- a/vcl/unx/gtk/app/gtkinst.cxx +++ b/vcl/unx/gtk/app/gtkinst.cxx @@ -134,6 +134,16 @@ extern "C" VCL_DLLPUBLIC SalInstance* create_SalInstance( oslModule pModule ) { + /* #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(); + #if OSL_DEBUG_LEVEL > 1 int nFd = open( "/home/pl93762/log.txt", O_CREAT | O_TRUNC | O_WRONLY, 0755 ); dup2( nFd, STDERR_FILENO ); diff --git a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx index fdaa102c614b..f922552ce923 100644 --- a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx +++ b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx @@ -3291,12 +3291,38 @@ void GtkSalGraphics::updateSettings( AllSettings& rSettings ) aBackColor = getColor( pMenubarStyle->bg[GTK_STATE_NORMAL] ); aStyleSet.SetMenuBarColor( aBackColor ); aBackColor = getColor( pMenuStyle->bg[GTK_STATE_NORMAL] ); - aTextColor = getColor( pMenuTextStyle->fg[GTK_STATE_NORMAL] ); - if( aBackColor == aTextColor ) - aTextColor = (aBackColor.GetLuminance() < 128) ? Color( COL_WHITE ) : Color( COL_BLACK ); + aTextColor = getColor( pMenuTextStyle->text[GTK_STATE_NORMAL] ); aStyleSet.SetMenuColor( aBackColor ); aStyleSet.SetMenuTextColor( aTextColor ); + aTextColor = getColor( pMenubarStyle->text[GTK_STATE_NORMAL] ); + aStyleSet.SetMenuBarTextColor( aTextColor ); + +#if OSL_DEBUG_LEVEL > 1 + std::fprintf( stderr, "==\n" ); + std::fprintf( stderr, "MenuColor = %x (%d)\n", (int)aStyleSet.GetMenuColor().GetColor(), aStyleSet.GetMenuColor().GetLuminance() ); + std::fprintf( stderr, "MenuTextColor = %x (%d)\n", (int)aStyleSet.GetMenuTextColor().GetColor(), aStyleSet.GetMenuTextColor().GetLuminance() ); + std::fprintf( stderr, "MenuBarColor = %x (%d)\n", (int)aStyleSet.GetMenuBarColor().GetColor(), aStyleSet.GetMenuBarColor().GetLuminance() ); + std::fprintf( stderr, "MenuBarTextColor = %x (%d)\n", (int)aStyleSet.GetMenuBarTextColor().GetColor(), aStyleSet.GetMenuBarTextColor().GetLuminance() ); + std::fprintf( stderr, "LightColor = %x (%d)\n", (int)aStyleSet.GetLightColor().GetColor(), aStyleSet.GetLightColor().GetLuminance() ); + std::fprintf( stderr, "ShadowColor = %x (%d)\n", (int)aStyleSet.GetShadowColor().GetColor(), aStyleSet.GetShadowColor().GetLuminance() ); +#endif + + // Awful hack for menu separators in the Sonar and similar themes. + // If the menu color is not too dark, and the menu text color is lighter, + // make the "light" color lighter than the menu color and the "shadow" + // color darker than it. + if ( aStyleSet.GetMenuColor().GetLuminance() >= 32 && + aStyleSet.GetMenuColor().GetLuminance() <= aStyleSet.GetMenuTextColor().GetLuminance() ) + { + Color temp = aStyleSet.GetMenuColor(); + temp.IncreaseLuminance( 8 ); + aStyleSet.SetLightColor( temp ); + temp = aStyleSet.GetMenuColor(); + temp.DecreaseLuminance( 16 ); + aStyleSet.SetShadowColor( temp ); + } + aHighlightColor = getColor( pMenuItemStyle->bg[ GTK_STATE_SELECTED ] ); aHighlightTextColor = getColor( pMenuTextStyle->fg[ GTK_STATE_PRELIGHT ] ); if( aHighlightColor == aHighlightTextColor ) @@ -3439,13 +3465,6 @@ void GtkSalGraphics::updateSettings( AllSettings& rSettings ) // FIXME: need some way of fetching toolbar icon size. // aStyleSet.SetToolbarIconSize( STYLE_TOOLBAR_ICONSIZE_SMALL ); - /* #i35482# do not override HC mode per force - // #i59364# high contrast mode - bool bHC = ( aStyleSet.GetFaceColor().IsDark() || - aStyleSet.GetWindowColor().IsDark() ); - aStyleSet.SetHighContrastMode( bHC ); - */ - // finally update the collected settings rSettings.SetStyleSettings( aStyleSet ); diff --git a/vcl/unx/gtk/window/gtkframe.cxx b/vcl/unx/gtk/window/gtkframe.cxx index b6770ca1a77e..8963ac2e3643 100644 --- a/vcl/unx/gtk/window/gtkframe.cxx +++ b/vcl/unx/gtk/window/gtkframe.cxx @@ -1123,7 +1123,7 @@ void GtkSalFrame::SetIcon( USHORT nIcon ) USHORT nIndex; // Use high contrast icons where appropriate - if( Application::GetSettings().GetStyleSettings().GetFaceColor().IsDark() ) + if( Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) { nOffsets[0] = SV_ICON_LARGE_HC_START; nOffsets[1] = SV_ICON_SMALL_HC_START; @@ -1506,7 +1506,7 @@ void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, USHOR if( isChild( false, true ) ) gtk_widget_set_size_request( m_pWindow, nWidth, nHeight ); - else + else if( ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) ) gtk_window_resize( GTK_WINDOW(m_pWindow), nWidth, nHeight ); setMinMaxSize(); } @@ -1608,6 +1608,7 @@ void GtkSalFrame::SetWindowState( const SalFrameState* pState ) SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT; if( (pState->mnMask & SAL_FRAMESTATE_MASK_STATE) && + ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) && (pState->mnState & SAL_FRAMESTATE_MAXIMIZED) && (pState->mnMask & nMaxGeometryMask) == nMaxGeometryMask ) { diff --git a/vcl/unx/inc/salinst.h b/vcl/unx/inc/salinst.h index c0614a78af9b..bef5cfd5e9b4 100644 --- a/vcl/unx/inc/salinst.h +++ b/vcl/unx/inc/salinst.h @@ -116,6 +116,11 @@ public: virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ); void FillFontPathList( std::list< rtl::OString >& o_rFontPaths ); + // dtrans implementation + virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > + CreateClipboard( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& i_rArguments ); + virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDragSource(); + virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDropTarget(); bool isPrinterInit() const { diff --git a/vcl/unx/kde/kdedata.cxx b/vcl/unx/kde/kdedata.cxx index 15a5ba087ab2..1b5a2f86dcee 100644 --- a/vcl/unx/kde/kdedata.cxx +++ b/vcl/unx/kde/kdedata.cxx @@ -232,6 +232,16 @@ void KDEData::Init() extern "C" { VCL_DLLPUBLIC SalInstance* create_SalInstance( oslModule ) { + /* #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(); + rtl::OString aVersion( qVersion() ); #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "qt version string is \"%s\"\n", aVersion.getStr() ); diff --git a/vcl/unx/kde/salnativewidgets-kde.cxx b/vcl/unx/kde/salnativewidgets-kde.cxx index 24358022d6a1..8046d22d75d3 100644 --- a/vcl/unx/kde/salnativewidgets-kde.cxx +++ b/vcl/unx/kde/salnativewidgets-kde.cxx @@ -1996,6 +1996,7 @@ void KDESalFrame::UpdateSettings( AllSettings& rSettings ) } aStyleSettings.SetMenuTextColor( aMenuFore ); + aStyleSettings.SetMenuBarTextColor( aMenuFore ); aStyleSettings.SetMenuColor( aMenuBack ); aStyleSettings.SetMenuBarColor( aMenuBack ); @@ -2035,13 +2036,6 @@ void KDESalFrame::UpdateSettings( AllSettings& rSettings ) // Scroll bar size aStyleSettings.SetScrollBarSize( kapp->style().pixelMetric( QStyle::PM_ScrollBarExtent ) ); - /* #i35482# do not override HC mode - // #i59364# high contrast mode - bool bHC = ( aStyleSettings.GetFaceColor().IsDark() || - aStyleSettings.GetWindowColor().IsDark() ); - aStyleSettings.SetHighContrastMode( bHC ); - */ - rSettings.SetStyleSettings( aStyleSettings ); } diff --git a/vcl/unx/kde4/KDEData.cxx b/vcl/unx/kde4/KDEData.cxx index 07a10c60d933..91e3a758da3c 100644 --- a/vcl/unx/kde4/KDEData.cxx +++ b/vcl/unx/kde4/KDEData.cxx @@ -45,6 +45,8 @@ void KDEData::initNWF() // draw toolbars on separate lines pSVData->maNWFData.mbDockingAreaSeparateTB = true; + // no borders for menu, theming does that + pSVData->maNWFData.mbFlatMenu = true; } void KDEData::deInitNWF() diff --git a/vcl/unx/kde4/KDESalFrame.cxx b/vcl/unx/kde4/KDESalFrame.cxx index ad8f467ee960..796350a63d50 100644 --- a/vcl/unx/kde4/KDESalFrame.cxx +++ b/vcl/unx/kde4/KDESalFrame.cxx @@ -318,6 +318,7 @@ void KDESalFrame::UpdateSettings( AllSettings& rSettings ) aMenuBack = toColor( qMenuCG.color( QPalette::Button ) ); style.SetMenuTextColor( aMenuFore ); + style.SetMenuBarTextColor( aMenuFore ); style.SetMenuColor( aMenuBack ); style.SetMenuBarColor( aMenuBack ); diff --git a/vcl/unx/kde4/KDESalGraphics.cxx b/vcl/unx/kde4/KDESalGraphics.cxx index ae917f252b11..2e8f0dcad96b 100644 --- a/vcl/unx/kde4/KDESalGraphics.cxx +++ b/vcl/unx/kde4/KDESalGraphics.cxx @@ -35,6 +35,8 @@ #include <QStyle> #include <QStyleOption> #include <QPainter> +#include <QFrame> +#include <QLabel> #include <kapplication.h> @@ -42,10 +44,9 @@ #include "KDESalGraphics.hxx" -#include <vcl/settings.hxx> -#include <rtl/ustrbuf.hxx> - -#include <stdio.h> +#include "vcl/settings.hxx" +#include "vcl/decoview.hxx" +#include "rtl/ustrbuf.hxx" using namespace ::rtl; @@ -150,6 +151,30 @@ BOOL KDESalGraphics::hitTestNativeControl( ControlType, ControlPart, return FALSE; } +void lcl_drawFrame( QRect& i_rRect, QPainter& i_rPainter, QStyle::PrimitiveElement i_nElement, + ControlState i_nState, const ImplControlValue& i_rValue ) +{ + #if ( QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 ) ) + QStyleOptionFrameV3 styleOption; + styleOption.frameShape = QFrame::StyledPanel; + #else + QStyleOptionFrame styleOption; + QFrame aFrame( NULL ); + aFrame.setFrameRect( QRect(0, 0, i_rRect.width(), i_rRect.height()) ); + aFrame.setFrameStyle( QFrame::StyledPanel | QFrame::Sunken ); + aFrame.ensurePolished(); + styleOption.initFrom( &aFrame ); + styleOption.lineWidth = aFrame.lineWidth(); + styleOption.midLineWidth = aFrame.midLineWidth(); + #endif + styleOption.rect = QRect(0, 0, i_rRect.width(), i_rRect.height()); + styleOption.state = vclStateValue2StateFlag( i_nState, i_rValue ); + #if ( QT_VERSION < QT_VERSION_CHECK( 4, 5, 0 ) ) + styleOption.state |= QStyle::State_Sunken; + #endif + kapp->style()->drawPrimitive(i_nElement, &styleOption, &i_rPainter); +} + BOOL KDESalGraphics::drawNativeControl( ControlType type, ControlPart part, const Region& rControlRegion, ControlState nControlState, const ImplControlValue& value, SalControlHandle&, @@ -352,18 +377,25 @@ BOOL KDESalGraphics::drawNativeControl( ControlType type, ControlPart part, } else if (type == CTRL_LISTBOX) { - QStyleOptionComboBox styleOption; - - styleOption.rect = QRect(0, 0, widgetRect.width(), widgetRect.height()); - styleOption.state = vclStateValue2StateFlag( nControlState, value ); - - if (part == PART_SUB_EDIT) + if( part == PART_WINDOW ) { - kapp->style()->drawControl(QStyle::CE_ComboBoxLabel, &styleOption, &painter); + lcl_drawFrame( widgetRect, painter, QStyle::PE_Frame, nControlState, value ); } else { - kapp->style()->drawComplexControl(QStyle::CC_ComboBox, &styleOption, &painter); + QStyleOptionComboBox styleOption; + + styleOption.rect = QRect(0, 0, widgetRect.width(), widgetRect.height()); + styleOption.state = vclStateValue2StateFlag( nControlState, value ); + + if (part == PART_SUB_EDIT) + { + kapp->style()->drawControl(QStyle::CE_ComboBoxLabel, &styleOption, &painter); + } + else + { + kapp->style()->drawComplexControl(QStyle::CC_ComboBox, &styleOption, &painter); + } } } else if (type == CTRL_LISTNODE) @@ -481,33 +513,11 @@ BOOL KDESalGraphics::drawNativeControl( ControlType type, ControlPart part, } else if (type == CTRL_FRAME) { - #if ( QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 ) ) - QStyleOptionFrameV3 styleOption; - #else - QStyleOptionFrameV2 styleOption; - #endif - styleOption.rect = QRect(0, 0, widgetRect.width(), widgetRect.height()); - styleOption.state = vclStateValue2StateFlag( nControlState, value ); - #if ( QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 ) ) - styleOption.frameShape = QFrame::StyledPanel; - #endif - - kapp->style()->drawPrimitive(QStyle::PE_FrameWindow, &styleOption, &painter); + lcl_drawFrame( widgetRect, painter, QStyle::PE_Frame, nControlState, value ); } else if (type == CTRL_FIXEDBORDER) { - #if ( QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 ) ) - QStyleOptionFrameV3 styleOption; - #else - QStyleOptionFrameV2 styleOption; - #endif - styleOption.rect = QRect(0, 0, widgetRect.width(), widgetRect.height()); - styleOption.state = vclStateValue2StateFlag( nControlState, value ); - #if ( QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 ) ) - styleOption.frameShape = QFrame::StyledPanel; - #endif - - kapp->style()->drawPrimitive(QStyle::PE_FrameWindow, &styleOption, &painter); + lcl_drawFrame( widgetRect, painter, QStyle::PE_FrameWindow, nControlState, value ); } else if (type == CTRL_WINDOW_BACKGROUND) { @@ -573,14 +583,21 @@ BOOL KDESalGraphics::getNativeControlRegion( ControlType type, ControlPart part, break; case CTRL_EDITBOX: { - styleOption.rect = QRect(0, 0, contentRect.width(), contentRect.height()); - styleOption.state = vclStateValue2StateFlag(controlState, val); - - int size = kapp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin) - 1; - - contentRect.adjust( -size, -size, size, size); - boundingRect = contentRect; - + int nFontHeight = kapp->fontMetrics().height(); + //int nFrameSize = kapp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + int nLayoutTop = kapp->style()->pixelMetric(QStyle::PM_LayoutTopMargin); + int nLayoutBottom = kapp->style()->pixelMetric(QStyle::PM_LayoutBottomMargin); + int nLayoutLeft = kapp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin); + int nLayoutRight = kapp->style()->pixelMetric(QStyle::PM_LayoutRightMargin); + + int nMinHeight = (nFontHeight + nLayoutTop + nLayoutBottom); + if( boundingRect.height() < nMinHeight ) + { + int delta = nMinHeight - boundingRect.height(); + boundingRect.adjust( 0, 0, 0, delta ); + } + contentRect = boundingRect; + contentRect.adjust( -nLayoutLeft+1, -nLayoutTop+1, nLayoutRight-1, nLayoutBottom-1 ); retVal = true; break; @@ -621,7 +638,6 @@ BOOL KDESalGraphics::getNativeControlRegion( ControlType type, ControlPart part, case PART_ENTIRE_CONTROL: { int size = kapp->style()->pixelMetric(QStyle::PM_ComboBoxFrameWidth) - 2; - contentRect.adjust(-size,-size,size,size); // find out the minimum size that should be used // assume contents is a text ling @@ -632,6 +648,11 @@ BOOL KDESalGraphics::getNativeControlRegion( ControlType type, ControlPart part, if( aMinSize.height() > contentRect.height() ) contentRect.adjust( 0, 0, 0, aMinSize.height() - contentRect.height() ); boundingRect = contentRect; + // FIXME: why this difference between comboboxes and listboxes ? + // because a combobox has a sub edit and that is positioned + // inside the outer bordered control ? + if( type == CTRL_COMBOBOX ) + contentRect.adjust(-size,-size,size,size); retVal = true; break; } @@ -647,6 +668,9 @@ BOOL KDESalGraphics::getNativeControlRegion( ControlType type, ControlPart part, retVal = true; break; + case PART_WINDOW: + retVal = true; + break; } break; } @@ -703,14 +727,19 @@ BOOL KDESalGraphics::getNativeControlRegion( ControlType type, ControlPart part, break; case CTRL_FRAME: { - if (part == PART_BORDER) + if( part == PART_BORDER ) { - int size = kapp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); - //contentRect.adjust(size, size, size, size); - boundingRect.adjust(-size, -size, size, size); + int size = kapp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin); + USHORT nStyle = val.getNumericVal(); + if( nStyle & FRAME_DRAW_NODRAW ) + { + // in this case the question is: how thick would a frame be + // see brdwin.cxx, decoview.cxx + // most probably the behavior in decoview.cxx is wrong. + contentRect.adjust(size, size, -size, -size); + } retVal = true; } - break; } case CTRL_RADIOBUTTON: diff --git a/vcl/unx/kde4/main.cxx b/vcl/unx/kde4/main.cxx index 2a48624d9d14..798990c06466 100644 --- a/vcl/unx/kde4/main.cxx +++ b/vcl/unx/kde4/main.cxx @@ -45,6 +45,16 @@ extern "C" { VCL_DLLPUBLIC SalInstance* create_SalInstance( oslModule ) { + /* #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(); + #if QT_VERSION < 0x050000 // Qt 4.x support needs >= 4.1.0 rtl::OString aVersion( qVersion() ); diff --git a/vcl/unx/source/app/salinst.cxx b/vcl/unx/source/app/salinst.cxx index c160ea4c2fa5..d84b7fa5df6d 100644 --- a/vcl/unx/source/app/salinst.cxx +++ b/vcl/unx/source/app/salinst.cxx @@ -103,6 +103,16 @@ extern "C" { VCL_DLLPUBLIC SalInstance* create_SalInstance() { + /* #i92121# workaround deadlocks in the X11 implementation + */ + static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" ); + /* #i90094# + from now on we know that an X connection will be + established, so protect X against itself + */ + if( ! ( pNoXInitThreads && *pNoXInitThreads ) ) + XInitThreads(); + X11SalInstance* pInstance = new X11SalInstance( new SalYieldMutex() ); // initialize SalData diff --git a/vcl/unx/source/app/sm.cxx b/vcl/unx/source/app/sm.cxx index 7e4e16579623..ff981b04259b 100644 --- a/vcl/unx/source/app/sm.cxx +++ b/vcl/unx/source/app/sm.cxx @@ -48,6 +48,7 @@ #include <saldisp.hxx> #include <salframe.h> #include <vcl/svapp.hxx> +#include <vcl/window.hxx> #include <salinst.h> #include <osl/conditn.h> @@ -187,6 +188,7 @@ bool SessionManagerClient::bDocSaveDone = false; static SmProp* pSmProps = NULL; static SmProp** ppSmProps = NULL; static int nSmProps = 0; +static unsigned char *pSmRestartHint = NULL; static void BuildSmPropertyList() @@ -195,7 +197,7 @@ static void BuildSmPropertyList() { ByteString aExec( SessionManagerClient::getExecName(), osl_getThreadTextEncoding() ); - nSmProps = 4; + nSmProps = 5; pSmProps = new SmProp[ nSmProps ]; pSmProps[ 0 ].name = const_cast<char*>(SmCloneCommand); @@ -243,6 +245,15 @@ static void BuildSmPropertyList() 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]; @@ -257,6 +268,31 @@ bool SessionManagerClient::checkDocumentsSaved() 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 ); @@ -385,7 +421,7 @@ void SessionManagerClient::saveDone() ICEConnectionObserver::lock(); SmcSetProperties( aSmcConnection, nSmProps, ppSmProps ); SmcSaveYourselfDone( aSmcConnection, True ); - SMprintf( "sent SaveYourselfDone\n" ); + SMprintf( "sent SaveYourselfDone SmRestartHint of %d\n", *pSmRestartHint ); bDocSaveDone = true; ICEConnectionObserver::unlock(); } diff --git a/vcl/unx/source/desktopdetect/desktopdetector.cxx b/vcl/unx/source/desktopdetect/desktopdetector.cxx new file mode 100644 index 000000000000..07fb18fa8344 --- /dev/null +++ b/vcl/unx/source/desktopdetect/desktopdetector.cxx @@ -0,0 +1,346 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salplug.cxx,v $ + * $Revision: 1.30 $ + * + * 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 <svunx.h> +#include <tools/prex.h> +#include <X11/Xatom.h> +#include <tools/postx.h> + +#include "vcl/dllapi.h" + +#include "rtl/ustrbuf.hxx" +#include "osl/module.h" +#include "osl/process.h" +#include "osl/thread.h" + +#include <unistd.h> + +using namespace rtl; + +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" +{ + +VCL_DLLPUBLIC 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" ); + int nParams = osl_getCommandArgCount(); + OUString aParam; + OString aBParm; + for( int i = 0; i < nParams; i++ ) + { + osl_getCommandArg( i, &aParam.pData ); + if( aParam.equalsAscii( "-headless" ) ) + { + pDisplayStr = NULL; + break; + } + if( i < nParams-1 && (aParam.equalsAscii( "-display" ) || aParam.equalsAscii( "--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(); +} + +} diff --git a/vcl/unx/source/desktopdetect/makefile.mk b/vcl/unx/source/desktopdetect/makefile.mk new file mode 100644 index 000000000000..cc845ee34887 --- /dev/null +++ b/vcl/unx/source/desktopdetect/makefile.mk @@ -0,0 +1,61 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.8 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=vcl +TARGET=dtdetect + +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile2.pmk + +# --- Files -------------------------------------------------------- + +.IF "$(GUIBASE)"!="unx" + +dummy: + @echo "Nothing to build for GUIBASE $(GUIBASE)" + +.ELSE # "$(GUIBASE)"!="unx" + +SLOFILES=$(SLO)$/desktopdetector.obj + +.ENDIF # "$(GUIBASE)"!="unx" + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + +.INCLUDE : $(PRJ)$/util$/target.pmk diff --git a/vcl/unx/source/dtrans/X11_clipboard.cxx b/vcl/unx/source/dtrans/X11_clipboard.cxx new file mode 100644 index 000000000000..0a47076f0d09 --- /dev/null +++ b/vcl/unx/source/dtrans/X11_clipboard.cxx @@ -0,0 +1,296 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: X11_clipboard.cxx,v $ + * $Revision: 1.17 $ + * + * 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 rtl; +using namespace x11; + +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::createFromAscii( "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::createFromAscii( "CLIPBOARD" ) ) ); + } +} + + +// ------------------------------------------------------------------------ + +void X11Clipboard::fireChangedContentsEvent() +{ + ClearableMutexGuard aGuard( m_rSelectionManager.getMutex() ); +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "X11Clipboard::fireChangedContentsEvent for %s (%d 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::createFromAscii( "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::createFromAscii(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(); +} + diff --git a/vcl/unx/source/dtrans/X11_clipboard.hxx b/vcl/unx/source/dtrans/X11_clipboard.hxx new file mode 100644 index 000000000000..a12064df6cbd --- /dev/null +++ b/vcl/unx/source/dtrans/X11_clipboard.hxx @@ -0,0 +1,154 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: X11_clipboard.hxx,v $ + * $Revision: 1.9 $ + * + * 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> + +#ifndef _COM_SUN_STAR_DATATRANSFER_CLIPBAORD_XCLIPBOARDEX_HPP_ +#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp> +#endif + +#ifndef _COM_SUN_STAR_DATATRANSFER_CLIPBAORD_XCLIPBOARDNOTIFIER_HPP_ +#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp> +#endif +#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 + { + Reference< ::com::sun::star::datatransfer::XTransferable > m_aContents; + Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner > m_aOwner; + + SelectionManager& m_rSelectionManager; + Reference< ::com::sun::star::lang::XInitialization > m_xSelectionManager; + ::std::list< 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 Reference< ::com::sun::star::datatransfer::XTransferable > SAL_CALL getContents() + throw(RuntimeException); + + virtual void SAL_CALL setContents( + const Reference< ::com::sun::star::datatransfer::XTransferable >& xTrans, + const 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 Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener ) + throw(RuntimeException); + + virtual void SAL_CALL removeClipboardListener( + const Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener ) + throw(RuntimeException); + + /* + * SelectionAdaptor + */ + virtual Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable(); + virtual void clearTransferable(); + virtual void fireContentsChanged(); + virtual Reference< XInterface > getReference() throw(); + }; + +// ------------------------------------------------------------------------ + + Sequence< ::rtl::OUString > SAL_CALL X11Clipboard_getSupportedServiceNames(); + Reference< XInterface > SAL_CALL X11Clipboard_createInstance( + const Reference< ::com::sun::star::lang::XMultiServiceFactory > & xMultiServiceFactory); + +// ------------------------------------------------------------------------ + +} // namepspace + +#endif diff --git a/vcl/unx/source/dtrans/X11_dndcontext.cxx b/vcl/unx/source/dtrans/X11_dndcontext.cxx new file mode 100644 index 000000000000..59832c27c2a7 --- /dev/null +++ b/vcl/unx/source/dtrans/X11_dndcontext.cxx @@ -0,0 +1,141 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: X11_dndcontext.cxx,v $ + * $Revision: 1.5 $ + * + * 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( + Window aDropWindow, + 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( + Window aDropWindow, + 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( + Window aDropWindow, + 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(); +} diff --git a/vcl/unx/source/dtrans/X11_dndcontext.hxx b/vcl/unx/source/dtrans/X11_dndcontext.hxx new file mode 100644 index 000000000000..f2ecb7b0841b --- /dev/null +++ b/vcl/unx/source/dtrans/X11_dndcontext.hxx @@ -0,0 +1,105 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: X11_dndcontext.hxx,v $ + * $Revision: 1.4 $ + * + * 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 <X11/Xlib.h> + +using namespace com::sun::star::uno; + +namespace x11 { + + class SelectionManager; + + class DropTargetDropContext : + public ::cppu::WeakImplHelper1< + ::com::sun::star::datatransfer::dnd::XDropTargetDropContext + > + { + Window m_aDropWindow; + Time m_nTimestamp; + SelectionManager& m_rManager; + Reference< XInterface > m_xManagerRef; + public: + DropTargetDropContext( Window, 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 + > + { + Window m_aDropWindow; + Time m_nTimestamp; + SelectionManager& m_rManager; + Reference< XInterface > m_xManagerRef; + public: + DropTargetDragContext( Window, 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 + > + { + Window m_aDropWindow; + Time m_nTimestamp; + SelectionManager& m_rManager; + Reference< XInterface > m_xManagerRef; + public: + DragSourceContext( Window, 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 diff --git a/vcl/unx/source/dtrans/X11_droptarget.cxx b/vcl/unx/source/dtrans/X11_droptarget.cxx new file mode 100644 index 000000000000..153514c668a0 --- /dev/null +++ b/vcl/unx/source/dtrans/X11_droptarget.cxx @@ -0,0 +1,231 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: X11_droptarget.cxx,v $ + * $Revision: 1.14 $ + * + * 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 rtl; +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; + +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::createFromAscii(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(); +} + + diff --git a/vcl/unx/source/dtrans/X11_selection.cxx b/vcl/unx/source/dtrans/X11_selection.cxx new file mode 100644 index 000000000000..3f7dfc2df709 --- /dev/null +++ b/vcl/unx/source/dtrans/X11_selection.cxx @@ -0,0 +1,4024 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: X11_selection.cxx,v $ + * $Revision: 1.85 $ + * + * 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 <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> +#include <X11/Xlib.h> +#include <X11/X.h> +#include <X11/Xutil.h> +#if defined(LINUX) || defined(NETBSD) || defined (FREEBSD) +#include <sys/poll.h> +#else +#include <poll.h> +#endif +#include <sal/alloca.h> + +#include <X11_selection.hxx> +#include <X11_clipboard.hxx> +#include <X11_transferable.hxx> +#include <X11_dndcontext.hxx> +#include <bmp.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> +#ifndef OSL_PROCESS_H +#include <osl/process.h> +#endif + +#define DRAG_EVENT_MASK ButtonPressMask |\ + ButtonReleaseMask |\ + PointerMotionMask |\ + EnterWindowMask |\ + LeaveWindowMask + +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 cppu; +using namespace osl; +using namespace rtl; + +using namespace x11; + +// 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; +} + +// ------------------------------------------------------------------------ + +::std::hash_map< OUString, SelectionManager*, OUStringHash >& SelectionManager::getInstances() +{ + static ::std::hash_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_aCurrentDropWindow( None ), + m_bDropWaitingForCompletion( false ), + m_aDropWindow( None ), + m_aDropProxy( None ), + m_aDragSourceWindow( None ), + m_nNoPosX( 0 ), + m_nNoPosY( 0 ), + m_nNoPosWidth( 0 ), + m_nNoPosHeight( 0 ), + m_bLastDropAccepted( false ), + m_bDropSuccess( false ), + m_bDropSent( false ), + m_bWaitingForPrimaryConversion( false ), + m_aMoveCursor( None ), + m_aCopyCursor( None ), + m_aLinkCursor( None ), + m_aNoneCursor( None ), + m_aCurrentCursor( None ), + m_nCurrentProtocolVersion( nXdndProtocolRevision ) +{ + m_aDropEnterEvent.data.l[0] = None; + m_bDropEnterSent = true; + m_aDragRunning.reset(); +} + +Cursor SelectionManager::createCursor( const char* pPointerData, const 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, + pPointerData, + width, + height ); + aMask + = XCreateBitmapFromData( m_pDisplay, + m_aWindow, + pMaskData, + width, + height ); + 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) +{ + 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() ) + { +#if 0 + // for the time being try to live without XDisplayConnection + // for the sake of clipboard service + // clipboard service should be initialized with a XDisplayConnection + // in the future + Exception aExc; + aExc.Message = OUString::createFromAscii( "initialize me with a valid XDisplayConnection" ); + aExc.Context = static_cast< OWeakObject* >(this); + throw aExc; +#endif + } + 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::createFromAscii( "CLIPBOARD" ) ); + + // special targets + m_nTARGETSAtom = getAtom( OUString::createFromAscii( "TARGETS" ) ); + m_nTIMESTAMPAtom = getAtom( OUString::createFromAscii( "TIMESTAMP" ) ); + m_nTEXTAtom = getAtom( OUString::createFromAscii( "TEXT" ) ); + m_nINCRAtom = getAtom( OUString::createFromAscii( "INCR" ) ); + m_nCOMPOUNDAtom = getAtom( OUString::createFromAscii( "COMPOUND_TEXT" ) ); + m_nMULTIPLEAtom = getAtom( OUString::createFromAscii( "MULTIPLE" ) ); + m_nUTF16Atom = getAtom( OUString::createFromAscii( "ISO10646-1" ) ); +// m_nUTF16Atom = getAtom( OUString::createFromAscii( "text/plain;charset=ISO-10646-UCS-2" ) ); + m_nImageBmpAtom = getAtom( OUString::createFromAscii( "image/bmp" ) ); + + // Atoms for Xdnd protocol + m_nXdndAware = getAtom( OUString::createFromAscii( "XdndAware" ) ); + m_nXdndEnter = getAtom( OUString::createFromAscii( "XdndEnter" ) ); + m_nXdndLeave = getAtom( OUString::createFromAscii( "XdndLeave" ) ); + m_nXdndPosition = getAtom( OUString::createFromAscii( "XdndPosition" ) ); + m_nXdndStatus = getAtom( OUString::createFromAscii( "XdndStatus" ) ); + m_nXdndDrop = getAtom( OUString::createFromAscii( "XdndDrop" ) ); + m_nXdndFinished = getAtom( OUString::createFromAscii( "XdndFinished" ) ); + m_nXdndSelection = getAtom( OUString::createFromAscii( "XdndSelection" ) ); + m_nXdndTypeList = getAtom( OUString::createFromAscii( "XdndTypeList" ) ); + m_nXdndProxy = getAtom( OUString::createFromAscii( "XdndProxy" ) ); + m_nXdndActionCopy = getAtom( OUString::createFromAscii( "XdndActionCopy" ) ); + m_nXdndActionMove = getAtom( OUString::createFromAscii( "XdndActionMove" ) ); + m_nXdndActionLink = getAtom( OUString::createFromAscii( "XdndActionLink" ) ); + m_nXdndActionAsk = getAtom( OUString::createFromAscii( "XdndActionAsk" ) ); + m_nXdndActionPrivate= getAtom( OUString::createFromAscii( "XdndActionPrivate" ) ); + + // initialize map with member none + m_aAtomToString[ 0 ]= OUString::createFromAscii( "None" ); + m_aAtomToString[ XA_PRIMARY ] = OUString::createFromAscii( "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 + { + MutexGuard aGuard( *Mutex::getGlobalMutex() ); + + ::std::hash_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() + } + + 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 ) +{ + ::std::hash_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 ) +{ + 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 ) +{ + 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 + /* #97070# + * 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 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::createFromAscii( "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 ) +{ + MutexGuard aGuard( *Mutex::getGlobalMutex() ); + + OUString aDisplayName( rDisplayName ); + if( ! aDisplayName.getLength() ) + aDisplayName = OStringToOUString( getenv( "DISPLAY" ), RTL_TEXTENCODING_ISO_8859_1 ); + SelectionManager* pInstance = NULL; + + ::std::hash_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 ) +{ + MutexGuard aGuard(m_aMutex); + + ::std::hash_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 ) +{ + MutexGuard aGuard(m_aMutex); + + ::std::hash_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 ) + { + 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 + ? sizeof(aXdndConversionTab)/sizeof(aXdndConversionTab[0]) : + sizeof(aNativeConversionTab)/sizeof(aNativeConversionTab[0]); + + 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::createFromAscii( "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 + ? sizeof(aXdndConversionTab)/sizeof(aXdndConversionTab[0]) : + sizeof(aNativeConversionTab)/sizeof(aNativeConversionTab[0]); + + 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 ) +{ + ResettableMutexGuard aGuard(m_aMutex); + ::std::hash_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; + + 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 ) +{ + int nFormat; + bool bSuccess = false; + + ::std::hash_map< Atom, Selection* >::iterator it; + { + 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 }; + { + 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 ) + { + 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 ) + { + 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 ) + { + ::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 %ld\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 ) +{ + ::std::hash_map< Atom, Selection* >::iterator it; + { + 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 + 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::createFromAscii( "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; + } + } + + { + 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 +// if( selection != m_nCLIPBOARDAtom ) + { + 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 ) +{ + std::hash_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, + Window requestor, + Atom target, + Atom property, + Atom selection ) +{ + 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 + 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::createFromAscii( "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" ); + std::hash_map< Window, std::hash_map< Atom, IncrementalTransfer > >::const_iterator win_it = m_aIncrementals.find( requestor ); + if( win_it != m_aIncrementals.end() ) + { + std::hash_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 ) +{ + 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 ) + { + 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; + } + 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 ) +{ + 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; + + ::std::hash_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 ) +{ + 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 ) + { + std::hash_map< Window, std::hash_map< Atom, IncrementalTransfer > >::iterator it; + it = m_aIncrementals.find( rNotify.window ); + if( it != m_aIncrementals.end() ) + { + bHandled = true; + int nCurrentTime = time( NULL ); + std::hash_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 ) +{ + 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( OUString::createFromAscii( "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 + ::std::hash_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 ) +{ + ResettableMutexGuard aGuard(m_aMutex); + + // handle drop related events + Window aSource = rMessage.data.l[0]; + Window aTarget = rMessage.window; + + bool bHandled = false; + + ::std::hash_map< 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 && (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_ENSURE( 0, "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 || 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 == 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; + + 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 == 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 == 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, Window aDropWindow, Time ) +{ + 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; + 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_ASSERT( "dropComplete from invalid DropTargetDropContext" ); +} + +/* + * methods for XDropTargetDragContext + */ + +// ------------------------------------------------------------------------ + +void SelectionManager::sendDragStatus( Atom nDropAction ) +{ + 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(); + + 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, Time eventTime ) +{ + ClearableMutexGuard aGuard(m_aMutex); + + if( m_bDropSent ) + return; + + ::std::hash_map< 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; + 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; + + ResettableMutexGuard aGuard(m_aMutex); + + bool bHandled = false; + + // for shortcut + ::std::hash_map< 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: +// fprintf( stderr, "handleDragEvent: MotionNotify\n" ); + 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 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; + 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; + 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 == 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; + 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 == 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; + 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; + + 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, 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; + Reference< XDragSourceListener > xListener( m_xDragSourceListener ); + m_xDragSourceListener.clear(); + aGuard.clear(); + xListener->dragDropEnd( dsde ); + bHandled = true; + } + } + return bHandled; +} + +// ------------------------------------------------------------------------ + +void SelectionManager::accept( sal_Int8 dragOperation, Window aDropWindow, 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( Window aDropWindow, 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() +{ + 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( Window aWindow, 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 = *(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 && *(Window*)pBytes != rProxy ) + rProxy = None; + XFree( pBytes ); + pBytes = NULL; + } + else + rProxy = None; + } + } + break; + } + } + 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, Window aRoot ) +{ + ResettableMutexGuard aGuard( m_aMutex ); + + Reference< XDragSourceListener > xListener( m_xDragSourceListener ); + + m_nLastDragX = nX; + m_nLastDragY = nY; + + Window aParent = aRoot; + Window aChild; + 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; + + ::std::hash_map< 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 Reference< XTransferable >& transferable, + const 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; + } + + { + 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 + Window aRoot, aParent, aChild; + int root_x, root_y, win_x, win_y; + unsigned int mask; + + ::std::hash_map< 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 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 ); + 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 + if( trigger.Event.getValueTypeName().equalsAsciiL( "com.sun.star.awt.MouseEvent", 27 ) ) + { + MouseEvent aEvent; + 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 ); + + 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 + { + ClearableMutexGuard aGuard(m_aMutex); + + Reference< XDragSourceListener > xListener( m_xDragSourceListener ); + 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, Window aDropWindow, Time ) +{ + MutexGuard aGuard( m_aMutex ); + if( aDropWindow == m_aDropWindow && 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, Window, Time ) +{ +} + +// ------------------------------------------------------------------------ + +void SelectionManager::transferablesFlavorsChanged() +{ + 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 + * + * #95201# 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: + { + 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 ); + std::hash_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 KeyPress: + case KeyRelease: + bHandled = handleDragEvent( rEvent ); + break; + default: + ; + } + return bHandled; +} + +// ------------------------------------------------------------------------ + +void SelectionManager::dispatchEvent( int millisec ) +{ + pollfd aPollFD; + XEvent event; + + // query socket handle to poll on + aPollFD.fd = ConnectionNumber( m_pDisplay ); + aPollFD.events = POLLIN; + aPollFD.revents = 0; + + // wait for activity (outside the xlib) + if( poll( &aPollFD, 1, millisec ) > 0 ) + { + // now acquire the mutex to prevent other threads + // from using the same X connection + ResettableMutexGuard aGuard(m_aMutex); + + // prevent that another thread already ate the input + // this can happen if e.g. another thread does + // an X request getting a response. the response + // would be removed from the queue and we would end up + // with an empty socket here + if( poll( &aPollFD, 1, 0 ) > 0 ) + { + int nPending = 1; + while( nPending ) + { + nPending = XPending( m_pDisplay ); + if( nPending ) + { + 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 ); + + while( osl_scheduleThread(This->m_aThread) ) + { + This->dispatchEvent( 1000 ); + + timeval aNow; + gettimeofday( &aNow, 0 ); + + if( (aNow.tv_sec - aLast.tv_sec) > 0 ) + { + ClearableMutexGuard aGuard(This->m_aMutex); + std::list< std::pair< SelectionAdaptor*, Reference< XInterface > > > aChangeList; + + for( std::hash_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 ) + { + Window aOwner = XGetSelectionOwner( This->m_pDisplay, it->first ); + if( aOwner != it->second->m_aLastOwner ) + { + it->second->m_aLastOwner = aOwner; + std::pair< SelectionAdaptor*, 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 +} + +// ------------------------------------------------------------------------ + +sal_Bool SelectionManager::handleEvent( const Any& event ) throw() +{ + Sequence< sal_Int8 > aSeq; + if( (event >>= aSeq) ) + { + XEvent* pEvent = (XEvent*)aSeq.getArray(); + Time nTimestamp = CurrentTime; + if( pEvent->type == ButtonPress || pEvent->type == ButtonRelease ) + nTimestamp = pEvent->xbutton.time; + else if( pEvent->type == 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 ) + { + 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 + MutexGuard aGuard(m_aMutex); + // stop dispatching + if( m_aThread ) + osl_terminateThread( m_aThread ); + m_xDisplayConnection->removeEventHandler( Any(), this ); + m_xDisplayConnection.clear(); + } + return sal_True; +} + +// ------------------------------------------------------------------------ + +void SelectionManager::registerHandler( Atom selection, SelectionAdaptor& rAdaptor ) +{ + 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 ) +{ + MutexGuard aGuard(m_aMutex); + + ::std::hash_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 ); + } +} + +// ------------------------------------------------------------------------ + +void SelectionManager::registerDropTarget( Window aWindow, DropTarget* pTarget ) +{ + MutexGuard aGuard(m_aMutex); + + // sanity check + ::std::hash_map< Window, DropTargetEntry >::const_iterator it = + m_aDropTargets.find( aWindow ); + if( it != m_aDropTargets.end() ) + OSL_ASSERT( "attempt to register window as drop target twice" ); + else if( aWindow && m_pDisplay ) + { + XSelectInput( m_pDisplay, aWindow, PropertyChangeMask ); + + // set XdndAware + XChangeProperty( m_pDisplay, aWindow, m_nXdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*)&nXdndProtocolRevision, 1 ); + + DropTargetEntry aEntry( pTarget ); + // 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 ); + m_aDropTargets[ aWindow ] = aEntry; + } + else + OSL_ASSERT( "attempt to register None as drop target" ); +} + +// ------------------------------------------------------------------------ + +void SelectionManager::deregisterDropTarget( Window aWindow ) +{ + ClearableMutexGuard aGuard(m_aMutex); + + m_aDropTargets.erase( aWindow ); + if( aWindow == m_aDragSourceWindow && m_aDragRunning.check() ) + { + // abort drag + std::hash_map< 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; + Reference< XDragSourceListener > xListener( m_xDragSourceListener ); + m_xDragSourceListener.clear(); + aGuard.clear(); + xListener->dragDropEnd( dsde ); + } +} + +/* + * SelectionAdaptor + */ + +Reference< XTransferable > SelectionManager::getTransferable() throw() +{ + return m_xDragSourceTransferable; +} + +// ------------------------------------------------------------------------ + +void SelectionManager::clearTransferable() throw() +{ + m_xDragSourceTransferable.clear(); +} + +// ------------------------------------------------------------------------ + +void SelectionManager::fireContentsChanged() throw() +{ +} + +// ------------------------------------------------------------------------ + +Reference< XInterface > SelectionManager::getReference() throw() +{ + return 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 ) + { + 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 Reference< ::com::sun::star::datatransfer::XTransferable >& transferable, + const 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::createFromAscii(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(); +} + + +// ------------------------------------------------------------------------ + diff --git a/vcl/unx/source/dtrans/X11_selection.hxx b/vcl/unx/source/dtrans/X11_selection.hxx new file mode 100644 index 000000000000..dc6c41247bbd --- /dev/null +++ b/vcl/unx/source/dtrans/X11_selection.hxx @@ -0,0 +1,518 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: X11_selection.hxx,v $ + * $Revision: 1.37 $ + * + * 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 <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 <osl/thread.h> + +#ifndef _OSL_CONDITION_HXX_ +#include <osl/conditn.hxx> +#endif + +#include <hash_map> +#include <list> + +#include <X11/Xlib.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 Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable() = 0; + virtual void clearTransferable() = 0; + virtual void fireContentsChanged() = 0; + virtual 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; + Window m_aTargetWindow; + class SelectionManager* m_pSelectionManager; + Reference< ::com::sun::star::datatransfer::dnd::XDragSource > + m_xSelectionManager; + ::std::list< 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 Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw(); + virtual void SAL_CALL removeDropTargetListener( const 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; + 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 Reference< ::com::sun::star::datatransfer::XTransferable >& transferable, + const Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener + ) throw(); + + }; + + + class SelectionManager : + public ::cppu::WeakImplHelper3< + ::com::sun::star::datatransfer::dnd::XDragSource, + ::com::sun::star::lang::XInitialization, + ::com::sun::star::awt::XEventHandler + >, + public SelectionAdaptor + { + static ::std::hash_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; + 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; + Window m_aLastOwner; + PixmapHolder* m_pPixmap; + // m_nOrigTimestamp contains the timestamp at which the seclection + // was acquired; needed for TIMESTAMP target + 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; + 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; + Window m_aWindow; + Reference< ::com::sun::star::awt::XDisplayConnection > + m_xDisplayConnection; + Reference< com::sun::star::script::XInvocation > + m_xBitmapConverter; + sal_Int32 m_nSelectionTimeout; + 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 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; + Window m_aCurrentDropWindow; + // time code of XdndDrop + Time m_nDropTime; + sal_Int8 m_nLastDropAction; + // XTransferable for Xdnd with foreign drag source + Reference< ::com::sun::star::datatransfer::XTransferable > + m_xDropTransferable; + int m_nLastX, m_nLastY; + 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 + Window m_aDropWindow; + // either m_aDropWindow or its XdndProxy + Window m_aDropProxy; + Window m_aDragSourceWindow; + // XTransferable for Xdnd when we are drag source + Reference< ::com::sun::star::datatransfer::XTransferable > + m_xDragSourceTransferable; + 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; + Time m_nDragTimestamp; + + // drag cursors + Cursor m_aMoveCursor; + Cursor m_aCopyCursor; + Cursor m_aLinkCursor; + Cursor m_aNoneCursor; + Cursor m_aCurrentCursor; + + + // drag and drop + + int m_nCurrentProtocolVersion; + ::std::hash_map< 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 + ::std::hash_map< Atom, ::rtl::OUString > + m_aAtomToString; + ::std::hash_map< ::rtl::OUString, Atom, ::rtl::OUStringHash > + m_aStringToAtom; + + // the registered selections + ::std::hash_map< Atom, Selection* > + m_aSelections; + // IncrementalTransfers in progress + std::hash_map< Window, std::hash_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; + + 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, Time eventTime ); + bool updateDragAction( int modifierState ); + int getXdndVersion( Window aWindow, Window& rProxy ); + Cursor createCursor( const char* pPointerData, const char* pMaskData, int width, int height, int hotX, int hotY ); + // coordinates on root window + void updateDragWindow( int nX, int nY, Window aRoot ); + + bool getPasteData( Atom selection, Atom type, Sequence< sal_Int8 >& rData ); + // returns true if conversion was successful + bool convertData( const Reference< ::com::sun::star::datatransfer::XTransferable >& xTransferable, + Atom nType, + Atom nSelection, + int & rFormat, + Sequence< sal_Int8 >& rData ); + bool sendData( SelectionAdaptor* pAdaptor, 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; }; + 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( Window aWindow, DropTarget* pTarget ); + void deregisterDropTarget( Window aWindow ); + + // for XDropTarget{Drag|Drop}Context + void accept( sal_Int8 dragOperation, Window aDropWindow, Time aTimestamp ); + void reject( Window aDropWindow, Time aTimestamp ); + void dropComplete( sal_Bool success, Window aDropWindow, Time aTimestamp ); + + // for XDragSourceContext + sal_Int32 getCurrentCursor(); + void setCursor( sal_Int32 cursor, Window aDropWindow, Time aTimestamp ); + void setImage( sal_Int32 image, Window aDropWindow, Time aTimestamp ); + void transferablesFlavorsChanged(); + + // 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 Reference< ::com::sun::star::datatransfer::XTransferable >& transferable, + const Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener + ) throw(); + + // SelectionAdaptor for XdndSelection Drag (we are drag source) + virtual Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable() throw(); + virtual void clearTransferable() throw(); + virtual void fireContentsChanged() throw(); + virtual Reference< XInterface > getReference() throw(); + }; + +// ------------------------------------------------------------------------ + + ::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 diff --git a/vcl/unx/source/dtrans/X11_service.cxx b/vcl/unx/source/dtrans/X11_service.cxx new file mode 100644 index 000000000000..cf971a2f8eb6 --- /dev/null +++ b/vcl/unx/source/dtrans/X11_service.cxx @@ -0,0 +1,138 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: X11_service.cxx,v $ + * $Revision: 1.11 $ + * + * 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 "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> + +using namespace rtl; +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; + +Sequence< OUString > SAL_CALL x11::X11Clipboard_getSupportedServiceNames() +{ + Sequence< OUString > aRet(1); + aRet[0] = OUString::createFromAscii("com.sun.star.datatransfer.clipboard.SystemClipboard"); + return aRet; +} + +Sequence< OUString > SAL_CALL x11::Xdnd_getSupportedServiceNames() +{ + Sequence< OUString > aRet(1); + aRet[0] = OUString::createFromAscii("com.sun.star.datatransfer.dnd.X11DragSource"); + return aRet; +} + +Sequence< OUString > SAL_CALL x11::Xdnd_dropTarget_getSupportedServiceNames() +{ + Sequence< OUString > aRet(1); + aRet[0] = OUString::createFromAscii("com.sun.star.datatransfer.dnd.X11DropTarget"); + return aRet; +} + +// ------------------------------------------------------------------------ + +Reference< XInterface > X11SalInstance::CreateClipboard( const Sequence< Any >& arguments ) +{ + static std::hash_map< OUString, ::std::hash_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 ) + { + 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::createFromAscii( "CLIPBOARD" ) ); + } + + ::std::hash_map< Atom, Reference< XClipboard > >& rMap( m_aInstances[ aDisplayName ] ); + ::std::hash_map< Atom, 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); +} + +// ------------------------------------------------------------------------ + +Reference< XInterface > X11SalInstance::CreateDragSource() +{ + return Reference < XInterface >( ( OWeakObject * ) new SelectionManagerHolder() ); +} + +// ------------------------------------------------------------------------ + +Reference< XInterface > X11SalInstance::CreateDropTarget() +{ + return Reference < XInterface >( ( OWeakObject * ) new DropTarget() ); +} + + diff --git a/vcl/unx/source/dtrans/X11_transferable.cxx b/vcl/unx/source/dtrans/X11_transferable.cxx new file mode 100644 index 000000000000..a95b87fe1c15 --- /dev/null +++ b/vcl/unx/source/dtrans/X11_transferable.cxx @@ -0,0 +1,137 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: X11_transferable.cxx,v $ + * $Revision: 1.9 $ + * + * 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 rtl; + + +using namespace x11; + + +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::createFromAscii( "CLIPBOARD" ) ), rFlavor.MimeType, aData ); + + if( ! bSuccess ) + { + throw UnsupportedFlavorException( rFlavor.MimeType, static_cast < XTransferable * > ( this ) ); + } + if( rFlavor.MimeType.equalsIgnoreAsciiCase( OUString::createFromAscii( "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::createFromAscii( "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::createFromAscii( "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; +} + diff --git a/vcl/unx/source/dtrans/X11_transferable.hxx b/vcl/unx/source/dtrans/X11_transferable.hxx new file mode 100644 index 000000000000..8e8367f666e2 --- /dev/null +++ b/vcl/unx/source/dtrans/X11_transferable.hxx @@ -0,0 +1,75 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: X11_transferable.hxx,v $ + * $Revision: 1.5 $ + * + * 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> + +#ifndef _COM_SUN_STAR_LANG_XEVENTLISTENER_HDL_ +#include <com/sun/star/lang/XEventListener.hpp> +#endif +#include <cppuhelper/implbase1.hxx> + +namespace x11 { + + class X11Transferable : public ::cppu::WeakImplHelper1 < + ::com::sun::star::datatransfer::XTransferable > + { + ::osl::Mutex m_aMutex; + + SelectionManager& m_rManager; + Reference< XInterface > m_xCreator; + Atom m_aSelection; + public: + X11Transferable( SelectionManager& rManager, const 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 diff --git a/vcl/unx/source/dtrans/bmp.cxx b/vcl/unx/source/dtrans/bmp.cxx new file mode 100644 index 000000000000..49219bfb0e2a --- /dev/null +++ b/vcl/unx/source/dtrans/bmp.cxx @@ -0,0 +1,742 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: bmp.cxx,v $ + * $Revision: 1.8 $ + * + * 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> + +using namespace x11; +using namespace com::sun::star::uno; +using namespace com::sun::star::script; +using namespace com::sun::star::awt; +using namespace rtl; + +/* + * 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 + 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) < sizeof(pClasses)/sizeof(pClasses[0])) ? 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; +} diff --git a/vcl/unx/source/dtrans/bmp.hxx b/vcl/unx/source/dtrans/bmp.hxx new file mode 100644 index 000000000000..baf04ac31d90 --- /dev/null +++ b/vcl/unx/source/dtrans/bmp.hxx @@ -0,0 +1,106 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: bmp.hxx,v $ + * $Revision: 1.4 $ + * + * 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 <X11/Xatom.h> +#include <X11/keysym.h> +#include <X11/Xlib.h> +#include <X11/Xutil.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 diff --git a/vcl/unx/source/dtrans/config.cxx b/vcl/unx/source/dtrans/config.cxx new file mode 100644 index 000000000000..2402fb4452c3 --- /dev/null +++ b/vcl/unx/source/dtrans/config.cxx @@ -0,0 +1,151 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: config.cxx,v $ + * $Revision: 1.6 $ + * + * 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 rtl; +using namespace x11; + +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 %ld 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 %ld 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*/ ) +{ +} + + diff --git a/vcl/unx/source/dtrans/copydata_curs.h b/vcl/unx/source/dtrans/copydata_curs.h new file mode 100644 index 000000000000..21a095521939 --- /dev/null +++ b/vcl/unx/source/dtrans/copydata_curs.h @@ -0,0 +1,45 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: copydata_curs.h,v $ + * $Revision: 1.3 $ + * + * 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 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}; diff --git a/vcl/unx/source/dtrans/copydata_mask.h b/vcl/unx/source/dtrans/copydata_mask.h new file mode 100644 index 000000000000..25db64d9bfee --- /dev/null +++ b/vcl/unx/source/dtrans/copydata_mask.h @@ -0,0 +1,45 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: copydata_mask.h,v $ + * $Revision: 1.3 $ + * + * 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 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}; diff --git a/vcl/unx/source/dtrans/linkdata_curs.h b/vcl/unx/source/dtrans/linkdata_curs.h new file mode 100644 index 000000000000..01ea8678acd2 --- /dev/null +++ b/vcl/unx/source/dtrans/linkdata_curs.h @@ -0,0 +1,45 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: linkdata_curs.h,v $ + * $Revision: 1.3 $ + * + * 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 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}; diff --git a/vcl/unx/source/dtrans/linkdata_mask.h b/vcl/unx/source/dtrans/linkdata_mask.h new file mode 100644 index 000000000000..b4207ad40dcf --- /dev/null +++ b/vcl/unx/source/dtrans/linkdata_mask.h @@ -0,0 +1,45 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: linkdata_mask.h,v $ + * $Revision: 1.3 $ + * + * 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 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}; diff --git a/vcl/unx/source/dtrans/makefile.mk b/vcl/unx/source/dtrans/makefile.mk new file mode 100644 index 000000000000..6af3a7c75048 --- /dev/null +++ b/vcl/unx/source/dtrans/makefile.mk @@ -0,0 +1,72 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.14 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=vcl +TARGET=dtransX11 +TARGETTYPE=GUI + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# ------------------------------------------------------------------ + +.IF "$(GUIBASE)"=="aqua" + +dummy: + @echo "Nothing to build for Mac OS X" + +.ELSE # "$(GUIBASE)"=="aqua" + +.IF "$(COM)$(CPU)" == "C50I" || "$(COM)$(CPU)" == "C52I" +NOOPTFILES=\ + $(SLO)$/X11_selection.obj +.ENDIF + +SLOFILES=\ + $(SLO)$/X11_dndcontext.obj \ + $(SLO)$/X11_transferable.obj \ + $(SLO)$/X11_clipboard.obj \ + $(SLO)$/X11_selection.obj \ + $(SLO)$/X11_droptarget.obj \ + $(SLO)$/X11_service.obj \ + $(SLO)$/bmp.obj \ + $(SLO)$/config.obj + +.ENDIF # "$(OS)"=="MACOSX" + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/vcl/unx/source/dtrans/movedata_curs.h b/vcl/unx/source/dtrans/movedata_curs.h new file mode 100644 index 000000000000..36845d5e9d1e --- /dev/null +++ b/vcl/unx/source/dtrans/movedata_curs.h @@ -0,0 +1,45 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: movedata_curs.h,v $ + * $Revision: 1.3 $ + * + * 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 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}; diff --git a/vcl/unx/source/dtrans/movedata_mask.h b/vcl/unx/source/dtrans/movedata_mask.h new file mode 100644 index 000000000000..facca718b8bf --- /dev/null +++ b/vcl/unx/source/dtrans/movedata_mask.h @@ -0,0 +1,45 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: movedata_mask.h,v $ + * $Revision: 1.3 $ + * + * 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 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}; diff --git a/vcl/unx/source/dtrans/nodrop_curs.h b/vcl/unx/source/dtrans/nodrop_curs.h new file mode 100644 index 000000000000..725b0fccf91b --- /dev/null +++ b/vcl/unx/source/dtrans/nodrop_curs.h @@ -0,0 +1,45 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: nodrop_curs.h,v $ + * $Revision: 1.3 $ + * + * 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 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}; diff --git a/vcl/unx/source/dtrans/nodrop_mask.h b/vcl/unx/source/dtrans/nodrop_mask.h new file mode 100644 index 000000000000..ef67a2bc2642 --- /dev/null +++ b/vcl/unx/source/dtrans/nodrop_mask.h @@ -0,0 +1,45 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: nodrop_mask.h,v $ + * $Revision: 1.3 $ + * + * 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 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}; diff --git a/vcl/unx/source/gdi/cdeint.cxx b/vcl/unx/source/gdi/cdeint.cxx index 4d2a6dba78ca..3794737b293e 100644 --- a/vcl/unx/source/gdi/cdeint.cxx +++ b/vcl/unx/source/gdi/cdeint.cxx @@ -216,6 +216,7 @@ void CDEIntegrator::GetSystemLook( AllSettings& rSettings ) aStyleSettings.SetDialogTextColor( aDeactive ); aStyleSettings.SetMenuTextColor( aDeactive ); + aStyleSettings.SetMenuBarTextColor( aDeactive ); aStyleSettings.SetButtonTextColor( aDeactive ); aStyleSettings.SetRadioCheckTextColor( aDeactive ); aStyleSettings.SetGroupTextColor( aDeactive ); diff --git a/vcl/unx/source/gdi/salgdi.cxx b/vcl/unx/source/gdi/salgdi.cxx index 4d3e40840a7b..34f2dfd4b935 100644 --- a/vcl/unx/source/gdi/salgdi.cxx +++ b/vcl/unx/source/gdi/salgdi.cxx @@ -1176,11 +1176,11 @@ typedef std::multiset< int, TrapezoidYCompare > VerticalTrapSet; } // end of anonymous namespace // draw a poly-polygon -bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly, double fTransparency) +bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency) { // nothing to do for empty polypolygons - const int nPolygonCount = rPolyPoly.count(); - if( nPolygonCount <= 0 ) + const int nOrigPolyCount = rOrigPolyPoly.count(); + if( nOrigPolyCount <= 0 ) return TRUE; // nothing to do if everything is transparent @@ -1209,28 +1209,22 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly // don't bother with polygons outside of visible area const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() ); - const basegfx::B2DRange aPolyRange = basegfx::tools::getRange( rPolyPoly ); + const basegfx::B2DRange aPolyRange = basegfx::tools::getRange( rOrigPolyPoly ); const bool bNeedViewClip = !aPolyRange.isInside( aViewRange ); if( !aPolyRange.overlaps( aViewRange ) ) return true; // convert the polypolygon to trapezoids - // first convert the B2DPolyPolygon to HalfTrapezoids - // #i100922# try to prevent priority-queue reallocations by reservering enough + // prepare the polypolygon for the algorithm below: + // - clip it against the view range + // - make sure it contains no self-intersections + // while we are at it guess the number of involved polygon points int nHTQueueReserve = 0; - for( int nOuterPolyIdx = 0; nOuterPolyIdx < nPolygonCount; ++nOuterPolyIdx ) - { - const ::basegfx::B2DPolygon aOuterPolygon = rPolyPoly.getB2DPolygon( nOuterPolyIdx ); - const int nPointCount = aOuterPolygon.count(); - nHTQueueReserve += aOuterPolygon.areControlPointsUsed() ? 8 * nPointCount : nPointCount; - } - nHTQueueReserve = ((4*nHTQueueReserve) | 0x1FFF) + 1; - HTQueue aHTQueue; - aHTQueue.reserve( nHTQueueReserve ); - for( int nOuterPolyIdx = 0; nOuterPolyIdx < nPolygonCount; ++nOuterPolyIdx ) + basegfx::B2DPolyPolygon aGoodPolyPoly; + for( int nOrigPolyIdx = 0; nOrigPolyIdx < nOrigPolyCount; ++nOrigPolyIdx ) { - const ::basegfx::B2DPolygon aOuterPolygon = rPolyPoly.getB2DPolygon( nOuterPolyIdx ); + const ::basegfx::B2DPolygon aOuterPolygon = rOrigPolyPoly.getB2DPolygon( nOrigPolyIdx ); // render-trapezoids should be inside the view => clip polygon against view range basegfx::B2DPolyPolygon aClippedPolygon( aOuterPolygon ); @@ -1238,33 +1232,55 @@ bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly { aClippedPolygon = basegfx::tools::clipPolygonOnRange( aOuterPolygon, aViewRange, true, false ); DBG_ASSERT( aClippedPolygon.count(), "polygon confirmed to overlap with view should not get here" ); - if( !aClippedPolygon.count() ) - continue; } + const int nClippedPolyCount = aClippedPolygon.count(); + if( !nClippedPolyCount ) + continue; - // render-trapezoids have linear edges => get rid of bezier segments - if( aClippedPolygon.areControlPointsUsed() ) - aClippedPolygon = ::basegfx::tools::adaptiveSubdivideByDistance( aClippedPolygon, 0.125 ); - - // test and remove self intersections - // TODO: make code intersection save, then remove this test - basegfx::B2DPolyPolygon aInnerPolyPoly(basegfx::tools::solveCrossovers( aClippedPolygon)); - const int nInnerPolyCount = aInnerPolyPoly.count(); - for( int nInnerPolyIdx = 0; nInnerPolyIdx < nInnerPolyCount; ++nInnerPolyIdx ) + // #i103259# polypoly.solveCrossover() fails to remove self-intersections + // but polygon.solveCrossover() works. Use it to build the intersection-free polypolygon + // TODO: if the self-intersection prevention is too expensive make the trap-algorithm tolerate intersections + for( int nClippedPolyIdx = 0; nClippedPolyIdx < nClippedPolyCount; ++nClippedPolyIdx ) { - ::basegfx::B2DPolygon aInnerPolygon = aInnerPolyPoly.getB2DPolygon( nInnerPolyIdx ); - const int nPointCount = aInnerPolygon.count(); - if( !nPointCount ) - continue; + ::basegfx::B2DPolygon aUnsolvedPolygon = aClippedPolygon.getB2DPolygon( nClippedPolyIdx ); + basegfx::B2DPolyPolygon aSolvedPolyPoly( basegfx::tools::solveCrossovers( aUnsolvedPolygon) ); + const int nSolvedPolyCount = aSolvedPolyPoly.count(); + for( int nSolvedPolyIdx = 0; nSolvedPolyIdx < nSolvedPolyCount; ++nSolvedPolyIdx ) + { + // build the intersection-free polypolygon one by one + const ::basegfx::B2DPolygon aSolvedPolygon = aSolvedPolyPoly.getB2DPolygon( nSolvedPolyIdx ); + aGoodPolyPoly.append( aSolvedPolygon ); + // and while we are at it use the conviently available point count to guess the number of needed half-traps + const int nPointCount = aSolvedPolygon.count(); + nHTQueueReserve += aSolvedPolygon.areControlPointsUsed() ? 8 * nPointCount : nPointCount; + } + } + } + // #i100922# try to prevent priority-queue reallocations by reservering enough + nHTQueueReserve = ((4*nHTQueueReserve) | 0x1FFF) + 1; + HTQueue aHTQueue; + aHTQueue.reserve( nHTQueueReserve ); - aHTQueue.reserve( aHTQueue.size() + 8 * nPointCount ); + // first convert the B2DPolyPolygon to HalfTrapezoids + const int nGoodPolyCount = aGoodPolyPoly.count(); + for( int nGoodPolyIdx = 0; nGoodPolyIdx < nGoodPolyCount; ++nGoodPolyIdx ) + { + ::basegfx::B2DPolygon aInnerPolygon = aGoodPolyPoly.getB2DPolygon( nGoodPolyIdx ); + + // render-trapezoids have linear edges => get rid of bezier segments + if( aInnerPolygon.areControlPointsUsed() ) + aInnerPolygon = ::basegfx::tools::adaptiveSubdivideByDistance( aInnerPolygon, 0.125 ); + const int nPointCount = aInnerPolygon.count(); + if( nPointCount >= 3 ) + { // convert polygon point pairs to HalfTrapezoids // connect the polygon point with the first one if needed XPointFixed aOldXPF = { 0, 0 }; XPointFixed aNewXPF; for( int nPointIdx = 0; nPointIdx <= nPointCount; ++nPointIdx, aOldXPF = aNewXPF ) { + // auto-close the polygon if needed const int k = (nPointIdx < nPointCount) ? nPointIdx : 0; const ::basegfx::B2DPoint& aPoint = aInnerPolygon.getB2DPoint( k ); @@ -1551,3 +1567,4 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, const : } // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + diff --git a/vcl/unx/source/plugadapt/salplug.cxx b/vcl/unx/source/plugadapt/salplug.cxx index 8a1ed05b8e25..14de25b13e4d 100644 --- a/vcl/unx/source/plugadapt/salplug.cxx +++ b/vcl/unx/source/plugadapt/salplug.cxx @@ -6,9 +6,6 @@ * * OpenOffice.org - a multi-platform office productivity suite * - * $RCSfile: salplug.cxx,v $ - * $Revision: 1.30 $ - * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify @@ -31,18 +28,14 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" -#include <osl/module.h> -#include <osl/process.h> +#include "osl/module.h" +#include "osl/process.h" -#include <rtl/ustrbuf.hxx> +#include "rtl/ustrbuf.hxx" -#include <svunx.h> -#include <tools/prex.h> -#include <X11/Xatom.h> -#include <tools/postx.h> -#include <vcl/salinst.hxx> -#include <saldata.hxx> +#include "vcl/salinst.hxx" +#include "saldata.hxx" #include <cstdio> #include <unistd.h> @@ -130,292 +123,45 @@ static SalInstance* tryInstance( const OUString& rModuleBase ) return pInst; } -static bool is_gnome_desktop( Display* pDisplay ) +static const rtl::OUString& get_desktop_environment() { - 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 ) + static rtl::OUString aRet; + if( ! aRet.getLength() ) { - 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 ) ) + 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 ) { - return true; + rtl::OUString (*pSym)() = (rtl::OUString(*)()) + osl_getAsciiFunctionSymbol( aMod, "get_desktop_environment" ); + if( pSym ) + aRet = pSym(); } + osl_unloadModule( aMod ); } - - 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; -} - - -static const char * get_desktop_environment() -{ - static const char *pRet = NULL; - static const char *pOverride = getenv( "OOO_FORCE_DESKTOP" ); - - if ( pOverride && *pOverride ) - { - OString aOver( pOverride ); - - if ( aOver.equalsIgnoreAsciiCase( "cde" ) ) - pRet = desktop_strings[DESKTOP_CDE]; - if ( aOver.equalsIgnoreAsciiCase( "kde" ) ) - pRet = desktop_strings[DESKTOP_KDE]; - if ( aOver.equalsIgnoreAsciiCase( "kde4" ) ) - pRet = desktop_strings[DESKTOP_KDE4]; - if ( aOver.equalsIgnoreAsciiCase( "gnome" ) ) - pRet = desktop_strings[DESKTOP_GNOME]; - if ( aOver.equalsIgnoreAsciiCase( "none" ) ) - pRet = desktop_strings[DESKTOP_UNKNOWN]; - } - - if ( NULL == pRet ) - { - // get display to connect to - const char* pDisplayStr = getenv( "DISPLAY" ); - int nParams = osl_getCommandArgCount(); - OUString aParam; - OString aBParm; - for( int i = 0; i < nParams; i++ ) - { - osl_getCommandArg( i, &aParam.pData ); - if( aParam.equalsAscii( "-headless" ) ) - { - pDisplayStr = NULL; - break; - } - if( i < nParams-1 && (aParam.equalsAscii( "-display" ) || aParam.equalsAscii( "--display" )) ) - { - osl_getCommandArg( i+1, &aParam.pData ); - aBParm = OUStringToOString( aParam, osl_getThreadTextEncoding() ); - pDisplayStr = aBParm.getStr(); - break; - } - } - - // no server at all - if( ! pDisplayStr || !*pDisplayStr ) - pRet = desktop_strings[DESKTOP_NONE]; - else - { - Display* pDisplay = XOpenDisplay( pDisplayStr ); - if( pDisplay ) - { - XErrorHandler pOldHdl = XSetErrorHandler( autodect_error_handler ); - - if ( is_kde4_desktop( pDisplay ) ) - pRet = desktop_strings[DESKTOP_KDE4]; - else if ( is_kde_desktop( pDisplay ) ) - pRet = desktop_strings[DESKTOP_KDE]; - else if ( is_gnome_desktop( pDisplay ) ) - pRet = desktop_strings[DESKTOP_GNOME]; - else if ( is_cde_desktop( pDisplay ) ) - pRet = desktop_strings[DESKTOP_CDE]; - else - pRet = desktop_strings[DESKTOP_UNKNOWN]; - - // set the default handler again - XSetErrorHandler( pOldHdl ); - - XCloseDisplay( pDisplay ); - } - } - } - - return pRet; + return aRet; } - static const char* autodetect_plugin() { - const char * desktop = get_desktop_environment(); + const rtl::OUString& desktop( get_desktop_environment() ); const char * pRet = "gen"; // no server at all: dummy plugin - if ( desktop == desktop_strings[DESKTOP_NONE] ) + if ( desktop.equalsAscii( desktop_strings[DESKTOP_NONE] ) ) pRet = "svp"; - else if ( desktop == desktop_strings[DESKTOP_GNOME] ) + else if ( desktop.equalsAscii( desktop_strings[DESKTOP_GNOME] ) ) pRet = "gtk"; - else if( desktop == desktop_strings[DESKTOP_KDE] ) + else if( desktop.equalsAscii( desktop_strings[DESKTOP_KDE] ) ) pRet = "kde"; - else if( desktop == desktop_strings[DESKTOP_KDE4] ) + else if( desktop.equalsAscii( desktop_strings[DESKTOP_KDE4] ) ) pRet = "kde4"; else { @@ -455,19 +201,6 @@ SalInstance *CreateSalInstance() if( !(pUsePlugin && *pUsePlugin) ) pInst = check_headless_plugin(); - if( ! pInst ) - { - /* #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(); - } - if( ! pInst && !(pUsePlugin && *pUsePlugin) ) pUsePlugin = autodetect_plugin(); @@ -527,8 +260,7 @@ void SalAbort( const XubString& rErrorText ) const OUString& SalGetDesktopEnvironment() { - static OUString aRet = OStringToOUString(OString(get_desktop_environment()), RTL_TEXTENCODING_ASCII_US); - return aRet; + return get_desktop_environment(); } SalData::SalData() : diff --git a/vcl/unx/source/printer/ppdparser.cxx b/vcl/unx/source/printer/ppdparser.cxx index 1caf64ef7e2c..95bc7bca41ca 100644 --- a/vcl/unx/source/printer/ppdparser.cxx +++ b/vcl/unx/source/printer/ppdparser.cxx @@ -293,8 +293,14 @@ void PPDParser::initPPDFiles() } } -void PPDParser::getKnownPPDDrivers( std::list< rtl::OUString >& o_rDrivers ) +void PPDParser::getKnownPPDDrivers( std::list< rtl::OUString >& o_rDrivers, bool bRefresh ) { + if( bRefresh ) + { + delete pAllPPDFiles; + pAllPPDFiles = NULL; + } + initPPDFiles(); o_rDrivers.clear(); diff --git a/vcl/unx/source/window/salframe.cxx b/vcl/unx/source/window/salframe.cxx index 04eb9cd32771..6219b50d6ec3 100644 --- a/vcl/unx/source/window/salframe.cxx +++ b/vcl/unx/source/window/salframe.cxx @@ -1212,7 +1212,12 @@ void X11SalFrame::Show( BOOL bVisible, BOOL bNoActivate ) XLIB_Time nUserTime = 0; if( ! bNoActivate && (nStyle_ & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 ) - nUserTime = pDisplay_->GetLastUserEventTime(); + { + if( GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("Metacity") ) + nUserTime = pDisplay_->GetLastUserEventTime( true ); + else + nUserTime = pDisplay_->GetLastUserEventTime(); + } GetDisplay()->getWMAdaptor()->setUserTime( this, nUserTime ); // actually map the window diff --git a/vcl/util/makefile.mk b/vcl/util/makefile.mk index 5bb18f25ecd3..32620d9e966a 100644 --- a/vcl/util/makefile.mk +++ b/vcl/util/makefile.mk @@ -158,6 +158,9 @@ LIB1FILES+= \ $(SLB)$/salwin.lib \ $(SLB)$/salgdi.lib \ $(SLB)$/salapp.lib +.IF "$(GUIBASE)" == "aqua" +LIB1FILES+= $(SLB)$/dtransaqua.lib +.ENDIF .ENDIF SHL1TARGET= vcl$(DLLPOSTFIX) @@ -195,7 +198,8 @@ SHL1USE_EXPORTS=name .IF "$(GUIBASE)"=="aqua" SHL1STDLIBS+= \ $(BASEBMPLIB) \ - -lAppleRemote$(DLLPOSTFIX) + -lAppleRemote$(DLLPOSTFIX) \ + -framework QuickTime LIB1FILES+= \ $(SLB)$/sala11y.lib @@ -268,9 +272,20 @@ STDSHL1 += ft2lib.lib # UNX sal plugins .IF "$(GUI)" == "UNX" && "$(GUIBASE)" != "aqua" +# desktop detector +LIB7TARGET=$(SLB)$/idet +LIB7FILES=$(SLB)$/dtdetect.lib +SHL7TARGET=desktop_detector$(DLLPOSTFIX) +SHL7STDLIBS=\ + $(SALLIB) \ + $(X11LINK_DYNAMIC) +SHL7IMPLIB=idet +SHL7LIBS=$(LIB7TARGET) + # basic pure X11 plugin LIB2TARGET=$(SLB)$/ipure_x LIB2FILES= \ + $(SLB)$/dtransX11.lib \ $(SLB)$/printergfx.lib \ $(SLB)$/salwin.lib \ $(SLB)$/salgdi.lib \ @@ -287,6 +302,9 @@ SHL2STDLIBS=\ $(TOOLSLIB) \ $(VOSLIB) \ $(BASEGFXLIB) \ + $(UNOTOOLSLIB) \ + $(CPPUHELPERLIB) \ + $(CPPULIB) \ $(SALLIB) # prepare linking of Xinerama @@ -362,7 +380,8 @@ SHL4STDLIBS+=\ $(CPPUHELPERLIB) \ $(CPPULIB) \ $(VOSLIB) \ - $(SALLIB) + $(SALLIB) \ + $(X11LINK_DYNAMIC) .IF "$(ENABLE_RANDR)" != "" .IF "$(XRANDR_DLOPEN)" == "FALSE" @@ -390,7 +409,8 @@ SHL5STDLIBS+=\ $(VCLLIB) \ $(TOOLSLIB) \ $(VOSLIB) \ - $(SALLIB) + $(SALLIB) \ + $(X11LINK_DYNAMIC) .IF "$(ENABLE_RANDR)" != "" .IF "$(XRANDR_DLOPEN)" == "FALSE" @@ -419,7 +439,8 @@ SHL6STDLIBS+=\ $(PSPLIB) \ $(TOOLSLIB) \ $(VOSLIB) \ - $(SALLIB) + $(SALLIB) \ + $(X11LINK_DYNAMIC) .IF "$(ENABLE_RANDR)" != "" .IF "$(XRANDR_DLOPEN)" == "FALSE" diff --git a/vcl/util/makefile2.pmk b/vcl/util/makefile2.pmk index 0e57d7aeb80b..63b2889bc15d 100644 --- a/vcl/util/makefile2.pmk +++ b/vcl/util/makefile2.pmk @@ -34,6 +34,5 @@ CDEFS += -DVCL_DLLIMPLEMENTATION VISIBILITY_HIDDEN=TRUE .IF "$(GUIBASE)"=="aqua" -OBJCXXFLAGS=-x objective-c++ -fobjc-exceptions CFLAGSCXX+=$(OBJCXXFLAGS) .ENDIF # "$(GUIBASE)"=="aqua" diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx index 2d335808e4c1..1b80bf578530 100755 --- a/vcl/win/source/gdi/winlayout.cxx +++ b/vcl/win/source/gdi/winlayout.cxx @@ -1920,7 +1920,7 @@ int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, // calculate the absolute position of the first result glyph in pixel units const GOFFSET aGOffset = mpGlyphOffsets[ nStart ]; - Point aRelativePos( nXOffset + aGOffset.du, aGOffset.dv ); + Point aRelativePos( nXOffset + aGOffset.du, -aGOffset.dv ); rPos = GetDrawPosition( aRelativePos ); // fill the result arrays diff --git a/vcl/win/source/window/salframe.cxx b/vcl/win/source/window/salframe.cxx index 3ffc358bd76d..4a49d83918da 100644 --- a/vcl/win/source/window/salframe.cxx +++ b/vcl/win/source/window/salframe.cxx @@ -440,11 +440,11 @@ SalFrame* ImplSalCreateFrame( WinSalInstance* pInst, nExSysStyle |= WS_EX_TOOLWINDOW; pFrame->mbFloatWin = TRUE; - if ( pEnvTransparentFloats && bLayeredAPI == 1 /*&& !(nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE) */) + if ( (bLayeredAPI == 1) && (pEnvTransparentFloats /* does not work remote! || (nSalFrameStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) */ ) ) nExSysStyle |= WS_EX_LAYERED; } - if( nSalFrameStyle & SAL_FRAME_STYLE_TOOLTIP ) + if( (nSalFrameStyle & SAL_FRAME_STYLE_TOOLTIP) || (nSalFrameStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) ) nExSysStyle |= WS_EX_TOPMOST; // init frame data @@ -2930,6 +2930,7 @@ void WinSalFrame::UpdateSettings( AllSettings& rSettings ) aStyleSettings.SetUseFlatBorders( FALSE ); aStyleSettings.SetUseFlatMenues( FALSE ); aStyleSettings.SetMenuTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) ); + aStyleSettings.SetMenuBarTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) ); aStyleSettings.SetActiveColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVECAPTION ) ) ); aStyleSettings.SetActiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_CAPTIONTEXT ) ) ); aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTION ) ) ); diff --git a/vcl/workben/makefile.mk b/vcl/workben/makefile.mk index 34316356a1a6..0b89f031651d 100644 --- a/vcl/workben/makefile.mk +++ b/vcl/workben/makefile.mk @@ -140,6 +140,7 @@ APP5STDLIBS+=-lsocket .ENDIF .INCLUDE : target.mk +.IF "$(L10N_framework)"=="" ALLTAR : $(BIN)$/applicat.rdb @@ -151,4 +152,4 @@ $(BIN)$/applicat.rdb : makefile.mk $(UNOUCRRDB) $(REGCOMP) -register -r applicat.rdb \ -c i18nsearch.uno$(DLLPOST) \ -c i18npool.uno$(DLLPOST) - +.ENDIF |