blob: 17b45d6499e1b464abb8758a8031d6cb002b25e1 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
//------------------------------------------------------------------------
// includes
//------------------------------------------------------------------------
#include <svpm.h>
#include <string.h>
#include "Os2Clipboard.hxx"
//------------------------------------------------------------------------
// namespace directives
//------------------------------------------------------------------------
using namespace com::sun::star::datatransfer;
using namespace com::sun::star::datatransfer::clipboard;
using namespace com::sun::star::datatransfer::clipboard::RenderingCapabilities;
using namespace com::sun::star::lang;
using namespace com::sun::star::uno;
using namespace cppu;
using namespace osl;
using namespace rtl;
using namespace os2;
const Type CPPUTYPE_SEQINT8 = getCppuType( ( Sequence< sal_Int8 >* )0 );
const Type CPPUTYPE_OUSTRING = getCppuType( (OUString*)0 );
#define DTRANS_OBJ_CLASSNAME "DTRANSOBJWND"
// -----------------------------------------------------------------------
inline void SetWindowPtr( HWND hWnd, Os2Clipboard* pThis )
{
WinSetWindowULong( hWnd, QWL_USER, (ULONG)pThis );
}
inline Os2Clipboard* GetWindowPtr( HWND hWnd )
{
return (Os2Clipboard*)WinQueryWindowULong( hWnd, QWL_USER );
}
// -----------------------------------------------------------------------
MRESULT EXPENTRY DtransObjWndProc( HWND hWnd, ULONG nMsg, MPARAM nMP1, MPARAM nMP2 )
{
switch ( nMsg )
{
case WM_DRAWCLIPBOARD: // clipboard content has changed
{
Os2Clipboard* os2Clipboard = GetWindowPtr( hWnd);
if (os2Clipboard)
{
//MutexGuard aGuard(os2Clipboard->m_aMutex);
debug_printf("WM_DRAWCLIPBOARD os2Clipboard %08x\n", os2Clipboard);
if (os2Clipboard->m_bInSetClipboardData)
{
debug_printf("WM_DRAWCLIPBOARD our change\n");
}
else
{
// notify listener for clipboard change
debug_printf("WM_DRAWCLIPBOARD notify change\n");
os2Clipboard->notifyAllClipboardListener();
}
}
}
break;
}
return WinDefWindowProc( hWnd, nMsg, nMP1, nMP2 );
}
// -----------------------------------------------------------------------
Os2Clipboard::Os2Clipboard() :
m_aMutex(),
WeakComponentImplHelper4< XClipboardEx, XClipboardNotifier, XServiceInfo, XInitialization > (m_aMutex),
m_bInitialized(sal_False),
m_bInSetClipboardData(sal_False)
{
MutexGuard aGuard(m_aMutex);
debug_printf("Os2Clipboard::Os2Clipboard\n");
hAB = WinQueryAnchorBlock( HWND_DESKTOP );
hText = 0;
hBitmap = 0;
#if 0
// register object class
if ( WinRegisterClass( hAB, (PSZ)DTRANS_OBJ_CLASSNAME,
(PFNWP)DtransObjWndProc, 0, sizeof(ULONG) ))
{
APIRET rc;
// create object window to get clip viewer messages
hObjWnd = WinCreateWindow( HWND_OBJECT, (PCSZ)DTRANS_OBJ_CLASSNAME,
(PCSZ)"", 0, 0, 0, 0, 0,
HWND_OBJECT, HWND_TOP,
222, NULL, NULL);
// store pointer
SetWindowPtr( hObjWnd, this);
// register the viewer window
rc = WinOpenClipbrd(hAB);
rc = WinSetClipbrdViewer(hAB, hObjWnd);
rc = WinCloseClipbrd(hAB);
}
#endif
}
Os2Clipboard::~Os2Clipboard()
{
debug_printf("Os2Clipboard::~Os2Clipboard\n");
}
void SAL_CALL Os2Clipboard::initialize( const Sequence< Any >& aArguments )
throw(Exception, RuntimeException)
{
if (!m_bInitialized)
{
for (sal_Int32 n = 0, nmax = aArguments.getLength(); n < nmax; n++)
if (aArguments[n].getValueType() == getCppuType((OUString *) 0))
{
aArguments[0] >>= m_aName;
break;
}
}
}
OUString SAL_CALL Os2Clipboard::getImplementationName() throw( RuntimeException )
{
debug_printf("Os2Clipboard::getImplementationName\n");
return OUString::createFromAscii( OS2_CLIPBOARD_IMPL_NAME );
}
sal_Bool SAL_CALL Os2Clipboard::supportsService( const OUString& ServiceName ) throw( RuntimeException )
{
debug_printf("Os2Clipboard::supportsService\n");
Sequence < OUString > SupportedServicesNames = Os2Clipboard_getSupportedServiceNames();
for ( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
if (SupportedServicesNames[n].compareTo(ServiceName) == 0)
return sal_True;
return sal_False;
}
Sequence< OUString > SAL_CALL Os2Clipboard::getSupportedServiceNames() throw( RuntimeException )
{
debug_printf("Os2Clipboard::getSupportedServiceNames\n");
return Os2Clipboard_getSupportedServiceNames();
}
Reference< XTransferable > SAL_CALL Os2Clipboard::getContents() throw( RuntimeException )
{
debug_printf("Os2Clipboard::getContents\n");
MutexGuard aGuard(m_aMutex);
// os2 can have only one viewer at time, and we don't get a notification
// when the viewer changes. So we need to check handles of clipboard
// data and compare with previous handles
if (UWinOpenClipbrd(hAB)) {
sal_Bool fireChanged = sal_False;
ULONG handle = UWinQueryClipbrdData( hAB, UCLIP_CF_UNICODETEXT);
if (handle) {
if (handle != hText) {
hText = handle;
fireChanged = sal_True;
}
}
handle = UWinQueryClipbrdData( hAB, UCLIP_CF_BITMAP);
if (handle) {
if (handle != hBitmap) {
hBitmap = handle;
fireChanged = sal_True;
}
}
UWinCloseClipbrd( hAB);
if (fireChanged)
{
// notify listener for clipboard change
debug_printf("Os2Clipboard::getContents notify change\n");
notifyAllClipboardListener();
}
}
if( ! m_aContents.is() )
m_aContents = new Os2Transferable( static_cast< OWeakObject* >(this) );
return m_aContents;
}
void SAL_CALL Os2Clipboard::setContents( const Reference< XTransferable >& xTrans, const Reference< XClipboardOwner >& xClipboardOwner ) throw( RuntimeException )
{
debug_printf("Os2Clipboard::setContents\n");
// remember old values for callbacks before setting the new ones.
ClearableMutexGuard aGuard(m_aMutex);
Reference< XClipboardOwner > oldOwner(m_aOwner);
m_aOwner = xClipboardOwner;
Reference< XTransferable > oldContents(m_aContents);
m_aContents = xTrans;
aGuard.clear();
// notify old owner on loss of ownership
if( oldOwner.is() )
oldOwner->lostOwnership(static_cast < XClipboard * > (this), oldContents);
// notify all listeners on content changes
OInterfaceContainerHelper *pContainer =
rBHelper.aLC.getContainer(getCppuType( (Reference < XClipboardListener > *) 0));
if (pContainer)
{
ClipboardEvent aEvent(static_cast < XClipboard * > (this), m_aContents);
OInterfaceIteratorHelper aIterator(*pContainer);
while (aIterator.hasMoreElements())
{
Reference < XClipboardListener > xListener(aIterator.next(), UNO_QUERY);
if (xListener.is())
xListener->changedContents(aEvent);
}
}
#if OSL_DEBUG_LEVEL>0
// dump list of available mimetypes
Sequence< DataFlavor > aFlavors( m_aContents->getTransferDataFlavors() );
for( int i = 0; i < aFlavors.getLength(); i++ )
debug_printf("Os2Clipboard::setContents available mimetype: %d %s\n",
i, CHAR_POINTER(aFlavors.getConstArray()[i].MimeType));
#endif
// we can only export text or bitmap
DataFlavor nFlavorText( OUString::createFromAscii( "text/plain;charset=utf-16" ),
OUString::createFromAscii( "Unicode-Text" ), CPPUTYPE_OUSTRING);
DataFlavor nFlavorBitmap( OUString::createFromAscii( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" ),
OUString::createFromAscii( "Bitmap" ), CPPUTYPE_DEFAULT);
// try text transfer data (if any)
PSZ pSharedText = NULL;
HBITMAP hbm = NULL;
try
{
Any aAny = m_aContents->getTransferData( nFlavorText );
if (aAny.hasValue())
{
APIRET rc;
// copy unicode text to clipboard
OUString aString;
aAny >>= aString;
// share text
rc = DosAllocSharedMem( (PPVOID) &pSharedText, NULL,
aString.getLength() * 2 + 2,
PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE | OBJ_ANY);
if (!rc)
memcpy( pSharedText, aString.getStr(), aString.getLength() * 2 + 2 );
else
pSharedText = NULL;
debug_printf("Os2Clipboard::setContents SetClipbrdData text done\n");
}
} catch ( UnsupportedFlavorException&) {
debug_printf("Os2Clipboard::setContents UnsupportedFlavorException (no text)\n");
}
// try bitmap transfer data (if any)
try
{
Any aAnyB = m_aContents->getTransferData( nFlavorBitmap );
if (aAnyB.hasValue())
{
hbm = OOoBmpToOS2Handle( aAnyB);
debug_printf("Os2Clipboard::setContents SetClipbrdData bitmap done\n");
}
} catch ( UnsupportedFlavorException&) {
debug_printf("Os2Clipboard::setContents UnsupportedFlavorException (no bitmap)\n");
}
// copy to clipboard only if we have data available, otherwise clipboard
// remains in use and locks all other applications.
if ( (pSharedText || hbm) && UWinOpenClipbrd( hAB) )
{
// set the flag, so we will ignore the next WM_DRAWCLIPBOARD
// since we generate it with following code.
m_bInSetClipboardData = sal_True;
UWinEmptyClipbrd( hAB);
// give pointer to clipboard (it will become owner of pSharedText!)
if (pSharedText) {
UWinSetClipbrdData( hAB, (ULONG) pSharedText, UCLIP_CF_UNICODETEXT, CFI_POINTER);
// update internal handle to avoid detection of this text as new data
hText = (ULONG)pSharedText;
}
// give bitmap to clipboard
if (hbm) {
UWinSetClipbrdData( hAB, (ULONG) hbm, UCLIP_CF_BITMAP, CFI_HANDLE);
// update internal handle to avoid detection of this bitmap as new data
hBitmap = hbm;
}
// reset the flag, so we will not ignore next WM_DRAWCLIPBOARD
m_bInSetClipboardData = sal_False;
UWinCloseClipbrd( hAB);
}
}
OUString SAL_CALL Os2Clipboard::getName() throw( RuntimeException )
{
debug_printf("Os2Clipboard::getName\n");
return m_aName;
}
sal_Int8 SAL_CALL Os2Clipboard::getRenderingCapabilities() throw( RuntimeException )
{
debug_printf("Os2Clipboard::getRenderingCapabilities\n");
return Delayed;
}
//========================================================================
// XClipboardNotifier
//========================================================================
void SAL_CALL Os2Clipboard::addClipboardListener( const Reference< XClipboardListener >& listener ) throw( RuntimeException )
{
debug_printf("Os2Clipboard::addClipboardListener\n");
MutexGuard aGuard( rBHelper.rMutex );
OSL_ENSURE( !rBHelper.bInDispose, "do not add listeners in the dispose call" );
OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
if (!rBHelper.bInDispose && !rBHelper.bDisposed)
rBHelper.aLC.addInterface( getCppuType( (const ::com::sun::star::uno::Reference< XClipboardListener > *) 0), listener );
}
void SAL_CALL Os2Clipboard::removeClipboardListener( const Reference< XClipboardListener >& listener ) throw( RuntimeException )
{
debug_printf("Os2Clipboard::removeClipboardListener\n");
MutexGuard aGuard( rBHelper.rMutex );
OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" );
if (!rBHelper.bInDispose && !rBHelper.bDisposed)
rBHelper.aLC.removeInterface( getCppuType( (const Reference< XClipboardListener > *) 0 ), listener ); \
}
// ------------------------------------------------------------------------
void SAL_CALL Os2Clipboard::notifyAllClipboardListener( )
{
if ( !rBHelper.bDisposed )
{
ClearableMutexGuard aGuard( rBHelper.rMutex );
if ( !rBHelper.bDisposed )
{
aGuard.clear( );
ClearableMutexGuard aGuard(m_aMutex);
// 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(static_cast < XClipboard * > (this), m_aContents);
OInterfaceContainerHelper* pICHelper = rBHelper.aLC.getContainer(
getCppuType( ( Reference< XClipboardListener > * ) 0 ) );
if ( pICHelper )
{
try
{
OInterfaceIteratorHelper iter(*pICHelper);
m_aContents = 0;
m_aContents = new Os2Transferable( static_cast< OWeakObject* >(this) );
ClipboardEvent aClipbEvent(static_cast<XClipboard*>(this), m_aContents);
while(iter.hasMoreElements())
{
try
{
Reference<XClipboardListener> xCBListener(iter.next(), UNO_QUERY);
if (xCBListener.is())
xCBListener->changedContents(aClipbEvent);
}
catch(RuntimeException&)
{
OSL_ENSURE( false, "RuntimeException caught" );
debug_printf( "RuntimeException caught" );
}
}
}
catch(const ::com::sun::star::lang::DisposedException&)
{
OSL_ENSURE(false, "Service Manager disposed");
debug_printf( "Service Manager disposed");
// no further clipboard changed notifications
//m_pImpl->unregisterClipboardViewer();
}
} // end if
} // end if
} // end if
}
// ------------------------------------------------------------------------
Sequence< OUString > SAL_CALL Os2Clipboard_getSupportedServiceNames()
{
Sequence< OUString > aRet(1);
aRet[0] = OUString::createFromAscii( OS2_CLIPBOARD_SERVICE_NAME );
return aRet;
}
// ------------------------------------------------------------------------
Reference< XInterface > SAL_CALL Os2Clipboard_createInstance(
const Reference< XMultiServiceFactory > & xMultiServiceFactory)
{
return Reference < XInterface >( ( OWeakObject * ) new Os2Clipboard());
}