| /************************************************************** |
| * |
| * 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()); |
| } |
| |