1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 //------------------------------------------------------------------------ 29 // includes 30 //------------------------------------------------------------------------ 31 32 #include "Os2Clipboard.hxx" 33 34 //------------------------------------------------------------------------ 35 // namespace directives 36 //------------------------------------------------------------------------ 37 38 using namespace com::sun::star::datatransfer; 39 using namespace com::sun::star::datatransfer::clipboard; 40 using namespace com::sun::star::datatransfer::clipboard::RenderingCapabilities; 41 using namespace com::sun::star::lang; 42 using namespace com::sun::star::uno; 43 using namespace cppu; 44 using namespace osl; 45 using namespace rtl; 46 using namespace os2; 47 48 const Type CPPUTYPE_SEQINT8 = getCppuType( ( Sequence< sal_Int8 >* )0 ); 49 const Type CPPUTYPE_OUSTRING = getCppuType( (OUString*)0 ); 50 51 #define DTRANS_OBJ_CLASSNAME "DTRANSOBJWND" 52 53 // ----------------------------------------------------------------------- 54 55 inline void SetWindowPtr( HWND hWnd, Os2Clipboard* pThis ) 56 { 57 WinSetWindowULong( hWnd, QWL_USER, (ULONG)pThis ); 58 } 59 60 inline Os2Clipboard* GetWindowPtr( HWND hWnd ) 61 { 62 return (Os2Clipboard*)WinQueryWindowULong( hWnd, QWL_USER ); 63 } 64 65 // ----------------------------------------------------------------------- 66 67 MRESULT EXPENTRY DtransObjWndProc( HWND hWnd, ULONG nMsg, MPARAM nMP1, MPARAM nMP2 ) 68 { 69 70 switch ( nMsg ) 71 { 72 case WM_DRAWCLIPBOARD: // clipboard content has changed 73 { 74 Os2Clipboard* os2Clipboard = GetWindowPtr( hWnd); 75 if (os2Clipboard) 76 { 77 //MutexGuard aGuard(os2Clipboard->m_aMutex); 78 debug_printf("WM_DRAWCLIPBOARD os2Clipboard %08x\n", os2Clipboard); 79 if (os2Clipboard->m_bInSetClipboardData) 80 { 81 debug_printf("WM_DRAWCLIPBOARD our change\n"); 82 } 83 else 84 { 85 // notify listener for clipboard change 86 debug_printf("WM_DRAWCLIPBOARD notify change\n"); 87 os2Clipboard->notifyAllClipboardListener(); 88 } 89 } 90 } 91 break; 92 } 93 94 return WinDefWindowProc( hWnd, nMsg, nMP1, nMP2 ); 95 } 96 97 // ----------------------------------------------------------------------- 98 99 Os2Clipboard::Os2Clipboard() : 100 m_aMutex(), 101 WeakComponentImplHelper4< XClipboardEx, XClipboardNotifier, XServiceInfo, XInitialization > (m_aMutex), 102 m_bInitialized(sal_False), 103 m_bInSetClipboardData(sal_False) 104 { 105 MutexGuard aGuard(m_aMutex); 106 107 debug_printf("Os2Clipboard::Os2Clipboard\n"); 108 hAB = WinQueryAnchorBlock( HWND_DESKTOP ); 109 hText = 0; 110 hBitmap = 0; 111 112 #if 0 113 // register object class 114 if ( WinRegisterClass( hAB, (PSZ)DTRANS_OBJ_CLASSNAME, 115 (PFNWP)DtransObjWndProc, 0, sizeof(ULONG) )) 116 { 117 APIRET rc; 118 // create object window to get clip viewer messages 119 hObjWnd = WinCreateWindow( HWND_OBJECT, (PCSZ)DTRANS_OBJ_CLASSNAME, 120 (PCSZ)"", 0, 0, 0, 0, 0, 121 HWND_OBJECT, HWND_TOP, 122 222, NULL, NULL); 123 // store pointer 124 SetWindowPtr( hObjWnd, this); 125 // register the viewer window 126 rc = WinOpenClipbrd(hAB); 127 rc = WinSetClipbrdViewer(hAB, hObjWnd); 128 rc = WinCloseClipbrd(hAB); 129 } 130 #endif 131 132 } 133 134 Os2Clipboard::~Os2Clipboard() 135 { 136 debug_printf("Os2Clipboard::~Os2Clipboard\n"); 137 } 138 139 void SAL_CALL Os2Clipboard::initialize( const Sequence< Any >& aArguments ) 140 throw(Exception, RuntimeException) 141 { 142 if (!m_bInitialized) 143 { 144 for (sal_Int32 n = 0, nmax = aArguments.getLength(); n < nmax; n++) 145 if (aArguments[n].getValueType() == getCppuType((OUString *) 0)) 146 { 147 aArguments[0] >>= m_aName; 148 break; 149 } 150 } 151 } 152 153 OUString SAL_CALL Os2Clipboard::getImplementationName() throw( RuntimeException ) 154 { 155 debug_printf("Os2Clipboard::getImplementationName\n"); 156 return OUString::createFromAscii( OS2_CLIPBOARD_IMPL_NAME ); 157 } 158 159 sal_Bool SAL_CALL Os2Clipboard::supportsService( const OUString& ServiceName ) throw( RuntimeException ) 160 { 161 debug_printf("Os2Clipboard::supportsService\n"); 162 Sequence < OUString > SupportedServicesNames = Os2Clipboard_getSupportedServiceNames(); 163 164 for ( sal_Int32 n = SupportedServicesNames.getLength(); n--; ) 165 if (SupportedServicesNames[n].compareTo(ServiceName) == 0) 166 return sal_True; 167 168 return sal_False; 169 } 170 171 Sequence< OUString > SAL_CALL Os2Clipboard::getSupportedServiceNames() throw( RuntimeException ) 172 { 173 debug_printf("Os2Clipboard::getSupportedServiceNames\n"); 174 return Os2Clipboard_getSupportedServiceNames(); 175 } 176 177 Reference< XTransferable > SAL_CALL Os2Clipboard::getContents() throw( RuntimeException ) 178 { 179 debug_printf("Os2Clipboard::getContents\n"); 180 MutexGuard aGuard(m_aMutex); 181 182 // os2 can have only one viewer at time, and we don't get a notification 183 // when the viewer changes. So we need to check handles of clipboard 184 // data and compare with previous handles 185 if (UWinOpenClipbrd(hAB)) { 186 sal_Bool fireChanged = sal_False; 187 ULONG handle = UWinQueryClipbrdData( hAB, UCLIP_CF_UNICODETEXT); 188 if (handle) { 189 if (handle != hText) { 190 hText = handle; 191 fireChanged = sal_True; 192 } 193 } 194 handle = UWinQueryClipbrdData( hAB, UCLIP_CF_BITMAP); 195 if (handle) { 196 if (handle != hBitmap) { 197 hBitmap = handle; 198 fireChanged = sal_True; 199 } 200 } 201 UWinCloseClipbrd( hAB); 202 if (fireChanged) 203 { 204 // notify listener for clipboard change 205 debug_printf("Os2Clipboard::getContents notify change\n"); 206 notifyAllClipboardListener(); 207 } 208 } 209 210 if( ! m_aContents.is() ) 211 m_aContents = new Os2Transferable( static_cast< OWeakObject* >(this) ); 212 213 return m_aContents; 214 } 215 216 void SAL_CALL Os2Clipboard::setContents( const Reference< XTransferable >& xTrans, const Reference< XClipboardOwner >& xClipboardOwner ) throw( RuntimeException ) 217 { 218 debug_printf("Os2Clipboard::setContents\n"); 219 // remember old values for callbacks before setting the new ones. 220 ClearableMutexGuard aGuard(m_aMutex); 221 222 Reference< XClipboardOwner > oldOwner(m_aOwner); 223 m_aOwner = xClipboardOwner; 224 225 Reference< XTransferable > oldContents(m_aContents); 226 m_aContents = xTrans; 227 228 aGuard.clear(); 229 230 // notify old owner on loss of ownership 231 if( oldOwner.is() ) 232 oldOwner->lostOwnership(static_cast < XClipboard * > (this), oldContents); 233 234 // notify all listeners on content changes 235 OInterfaceContainerHelper *pContainer = 236 rBHelper.aLC.getContainer(getCppuType( (Reference < XClipboardListener > *) 0)); 237 if (pContainer) 238 { 239 ClipboardEvent aEvent(static_cast < XClipboard * > (this), m_aContents); 240 OInterfaceIteratorHelper aIterator(*pContainer); 241 242 while (aIterator.hasMoreElements()) 243 { 244 Reference < XClipboardListener > xListener(aIterator.next(), UNO_QUERY); 245 if (xListener.is()) 246 xListener->changedContents(aEvent); 247 } 248 } 249 250 #if OSL_DEBUG_LEVEL>0 251 // dump list of available mimetypes 252 Sequence< DataFlavor > aFlavors( m_aContents->getTransferDataFlavors() ); 253 for( int i = 0; i < aFlavors.getLength(); i++ ) 254 debug_printf("Os2Clipboard::setContents available mimetype: %d %s\n", 255 i, CHAR_POINTER(aFlavors.getConstArray()[i].MimeType)); 256 #endif 257 258 // we can only export text or bitmap 259 DataFlavor nFlavorText( OUString::createFromAscii( "text/plain;charset=utf-16" ), 260 OUString::createFromAscii( "Unicode-Text" ), CPPUTYPE_OUSTRING); 261 DataFlavor nFlavorBitmap( OUString::createFromAscii( "application/x-openoffice-bitmap;windows_formatname=\"Bitmap\"" ), 262 OUString::createFromAscii( "Bitmap" ), CPPUTYPE_DEFAULT); 263 264 // try text transfer data (if any) 265 PSZ pSharedText = NULL; 266 HBITMAP hbm = NULL; 267 try 268 { 269 Any aAny = m_aContents->getTransferData( nFlavorText ); 270 if (aAny.hasValue()) 271 { 272 APIRET rc; 273 // copy unicode text to clipboard 274 OUString aString; 275 aAny >>= aString; 276 // share text 277 rc = DosAllocSharedMem( (PPVOID) &pSharedText, NULL, 278 aString.getLength() * 2 + 2, 279 PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE | OBJ_ANY); 280 if (!rc) 281 memcpy( pSharedText, aString.getStr(), aString.getLength() * 2 + 2 ); 282 else 283 pSharedText = NULL; 284 debug_printf("Os2Clipboard::setContents SetClipbrdData text done\n"); 285 } 286 } catch ( UnsupportedFlavorException&) { 287 debug_printf("Os2Clipboard::setContents UnsupportedFlavorException (no text)\n"); 288 } 289 290 // copy to clipboard 291 if ( UWinOpenClipbrd( hAB) && (pSharedText || hbm)) 292 { 293 // set the flag, so we will ignore the next WM_DRAWCLIPBOARD 294 // since we generate it with following code. 295 m_bInSetClipboardData = sal_True; 296 UWinEmptyClipbrd( hAB); 297 // give pointer to clipboard (it will become owner of pSharedText!) 298 if (pSharedText) { 299 UWinSetClipbrdData( hAB, (ULONG) pSharedText, UCLIP_CF_UNICODETEXT, CFI_POINTER); 300 // update internal handle to avoid detection of this text as new data 301 hText = (ULONG)pSharedText; 302 } 303 // give bitmap to clipboard 304 if (hbm) { 305 UWinSetClipbrdData( hAB, (ULONG) hbm, UCLIP_CF_BITMAP, CFI_HANDLE); 306 // update internal handle to avoid detection of this bitmap as new data 307 hBitmap = hbm; 308 } 309 // reset the flag, so we will not ignore next WM_DRAWCLIPBOARD 310 m_bInSetClipboardData = sal_False; 311 UWinCloseClipbrd( hAB); 312 } 313 314 } 315 316 OUString SAL_CALL Os2Clipboard::getName() throw( RuntimeException ) 317 { 318 debug_printf("Os2Clipboard::getName\n"); 319 return m_aName; 320 } 321 322 sal_Int8 SAL_CALL Os2Clipboard::getRenderingCapabilities() throw( RuntimeException ) 323 { 324 debug_printf("Os2Clipboard::getRenderingCapabilities\n"); 325 return Delayed; 326 } 327 328 //======================================================================== 329 // XClipboardNotifier 330 //======================================================================== 331 332 void SAL_CALL Os2Clipboard::addClipboardListener( const Reference< XClipboardListener >& listener ) throw( RuntimeException ) 333 { 334 debug_printf("Os2Clipboard::addClipboardListener\n"); 335 MutexGuard aGuard( rBHelper.rMutex ); 336 OSL_ENSURE( !rBHelper.bInDispose, "do not add listeners in the dispose call" ); 337 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); 338 if (!rBHelper.bInDispose && !rBHelper.bDisposed) 339 rBHelper.aLC.addInterface( getCppuType( (const ::com::sun::star::uno::Reference< XClipboardListener > *) 0), listener ); 340 } 341 342 void SAL_CALL Os2Clipboard::removeClipboardListener( const Reference< XClipboardListener >& listener ) throw( RuntimeException ) 343 { 344 debug_printf("Os2Clipboard::removeClipboardListener\n"); 345 MutexGuard aGuard( rBHelper.rMutex ); 346 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); 347 if (!rBHelper.bInDispose && !rBHelper.bDisposed) 348 rBHelper.aLC.removeInterface( getCppuType( (const Reference< XClipboardListener > *) 0 ), listener ); \ 349 } 350 351 // ------------------------------------------------------------------------ 352 353 void SAL_CALL Os2Clipboard::notifyAllClipboardListener( ) 354 { 355 if ( !rBHelper.bDisposed ) 356 { 357 ClearableMutexGuard aGuard( rBHelper.rMutex ); 358 if ( !rBHelper.bDisposed ) 359 { 360 aGuard.clear( ); 361 362 ClearableMutexGuard aGuard(m_aMutex); 363 // copy member references on stack so they can be called 364 // without having the mutex 365 Reference< XClipboardOwner > xOwner( m_aOwner ); 366 Reference< XTransferable > xTrans( m_aContents ); 367 // clear members 368 m_aOwner.clear(); 369 m_aContents.clear(); 370 // release the mutex 371 aGuard.clear(); 372 373 // inform previous owner of lost ownership 374 if ( xOwner.is() ) 375 xOwner->lostOwnership(static_cast < XClipboard * > (this), m_aContents); 376 377 OInterfaceContainerHelper* pICHelper = rBHelper.aLC.getContainer( 378 getCppuType( ( Reference< XClipboardListener > * ) 0 ) ); 379 380 if ( pICHelper ) 381 { 382 try 383 { 384 OInterfaceIteratorHelper iter(*pICHelper); 385 m_aContents = 0; 386 m_aContents = new Os2Transferable( static_cast< OWeakObject* >(this) ); 387 ClipboardEvent aClipbEvent(static_cast<XClipboard*>(this), m_aContents); 388 389 while(iter.hasMoreElements()) 390 { 391 try 392 { 393 Reference<XClipboardListener> xCBListener(iter.next(), UNO_QUERY); 394 if (xCBListener.is()) 395 xCBListener->changedContents(aClipbEvent); 396 } 397 catch(RuntimeException&) 398 { 399 OSL_ENSURE( false, "RuntimeException caught" ); 400 debug_printf( "RuntimeException caught" ); 401 } 402 } 403 } 404 catch(const ::com::sun::star::lang::DisposedException&) 405 { 406 OSL_ENSURE(false, "Service Manager disposed"); 407 debug_printf( "Service Manager disposed"); 408 409 // no further clipboard changed notifications 410 //m_pImpl->unregisterClipboardViewer(); 411 } 412 413 } // end if 414 } // end if 415 } // end if 416 } 417 418 // ------------------------------------------------------------------------ 419 420 Sequence< OUString > SAL_CALL Os2Clipboard_getSupportedServiceNames() 421 { 422 Sequence< OUString > aRet(1); 423 aRet[0] = OUString::createFromAscii( OS2_CLIPBOARD_SERVICE_NAME ); 424 return aRet; 425 } 426 427 // ------------------------------------------------------------------------ 428 429 Reference< XInterface > SAL_CALL Os2Clipboard_createInstance( 430 const Reference< XMultiServiceFactory > & xMultiServiceFactory) 431 { 432 return Reference < XInterface >( ( OWeakObject * ) new Os2Clipboard()); 433 } 434 435