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 // try bitmap transfer data (if any) 291 try 292 { 293 Any aAnyB = m_aContents->getTransferData( nFlavorBitmap ); 294 if (aAnyB.hasValue()) 295 { 296 hbm = OOoBmpToOS2Handle( aAnyB); 297 debug_printf("Os2Clipboard::setContents SetClipbrdData bitmap done\n"); 298 } 299 } catch ( UnsupportedFlavorException&) { 300 debug_printf("Os2Clipboard::setContents UnsupportedFlavorException (no bitmap)\n"); 301 } 302 303 // copy to clipboard 304 if ( UWinOpenClipbrd( hAB) && (pSharedText || hbm)) 305 { 306 // set the flag, so we will ignore the next WM_DRAWCLIPBOARD 307 // since we generate it with following code. 308 m_bInSetClipboardData = sal_True; 309 UWinEmptyClipbrd( hAB); 310 // give pointer to clipboard (it will become owner of pSharedText!) 311 if (pSharedText) { 312 UWinSetClipbrdData( hAB, (ULONG) pSharedText, UCLIP_CF_UNICODETEXT, CFI_POINTER); 313 // update internal handle to avoid detection of this text as new data 314 hText = (ULONG)pSharedText; 315 } 316 // give bitmap to clipboard 317 if (hbm) { 318 UWinSetClipbrdData( hAB, (ULONG) hbm, UCLIP_CF_BITMAP, CFI_HANDLE); 319 // update internal handle to avoid detection of this bitmap as new data 320 hBitmap = hbm; 321 } 322 // reset the flag, so we will not ignore next WM_DRAWCLIPBOARD 323 m_bInSetClipboardData = sal_False; 324 UWinCloseClipbrd( hAB); 325 } 326 327 } 328 329 OUString SAL_CALL Os2Clipboard::getName() throw( RuntimeException ) 330 { 331 debug_printf("Os2Clipboard::getName\n"); 332 return m_aName; 333 } 334 335 sal_Int8 SAL_CALL Os2Clipboard::getRenderingCapabilities() throw( RuntimeException ) 336 { 337 debug_printf("Os2Clipboard::getRenderingCapabilities\n"); 338 return Delayed; 339 } 340 341 //======================================================================== 342 // XClipboardNotifier 343 //======================================================================== 344 345 void SAL_CALL Os2Clipboard::addClipboardListener( const Reference< XClipboardListener >& listener ) throw( RuntimeException ) 346 { 347 debug_printf("Os2Clipboard::addClipboardListener\n"); 348 MutexGuard aGuard( rBHelper.rMutex ); 349 OSL_ENSURE( !rBHelper.bInDispose, "do not add listeners in the dispose call" ); 350 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); 351 if (!rBHelper.bInDispose && !rBHelper.bDisposed) 352 rBHelper.aLC.addInterface( getCppuType( (const ::com::sun::star::uno::Reference< XClipboardListener > *) 0), listener ); 353 } 354 355 void SAL_CALL Os2Clipboard::removeClipboardListener( const Reference< XClipboardListener >& listener ) throw( RuntimeException ) 356 { 357 debug_printf("Os2Clipboard::removeClipboardListener\n"); 358 MutexGuard aGuard( rBHelper.rMutex ); 359 OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); 360 if (!rBHelper.bInDispose && !rBHelper.bDisposed) 361 rBHelper.aLC.removeInterface( getCppuType( (const Reference< XClipboardListener > *) 0 ), listener ); \ 362 } 363 364 // ------------------------------------------------------------------------ 365 366 void SAL_CALL Os2Clipboard::notifyAllClipboardListener( ) 367 { 368 if ( !rBHelper.bDisposed ) 369 { 370 ClearableMutexGuard aGuard( rBHelper.rMutex ); 371 if ( !rBHelper.bDisposed ) 372 { 373 aGuard.clear( ); 374 375 ClearableMutexGuard aGuard(m_aMutex); 376 // copy member references on stack so they can be called 377 // without having the mutex 378 Reference< XClipboardOwner > xOwner( m_aOwner ); 379 Reference< XTransferable > xTrans( m_aContents ); 380 // clear members 381 m_aOwner.clear(); 382 m_aContents.clear(); 383 // release the mutex 384 aGuard.clear(); 385 386 // inform previous owner of lost ownership 387 if ( xOwner.is() ) 388 xOwner->lostOwnership(static_cast < XClipboard * > (this), m_aContents); 389 390 OInterfaceContainerHelper* pICHelper = rBHelper.aLC.getContainer( 391 getCppuType( ( Reference< XClipboardListener > * ) 0 ) ); 392 393 if ( pICHelper ) 394 { 395 try 396 { 397 OInterfaceIteratorHelper iter(*pICHelper); 398 m_aContents = 0; 399 m_aContents = new Os2Transferable( static_cast< OWeakObject* >(this) ); 400 ClipboardEvent aClipbEvent(static_cast<XClipboard*>(this), m_aContents); 401 402 while(iter.hasMoreElements()) 403 { 404 try 405 { 406 Reference<XClipboardListener> xCBListener(iter.next(), UNO_QUERY); 407 if (xCBListener.is()) 408 xCBListener->changedContents(aClipbEvent); 409 } 410 catch(RuntimeException&) 411 { 412 OSL_ENSURE( false, "RuntimeException caught" ); 413 debug_printf( "RuntimeException caught" ); 414 } 415 } 416 } 417 catch(const ::com::sun::star::lang::DisposedException&) 418 { 419 OSL_ENSURE(false, "Service Manager disposed"); 420 debug_printf( "Service Manager disposed"); 421 422 // no further clipboard changed notifications 423 //m_pImpl->unregisterClipboardViewer(); 424 } 425 426 } // end if 427 } // end if 428 } // end if 429 } 430 431 // ------------------------------------------------------------------------ 432 433 Sequence< OUString > SAL_CALL Os2Clipboard_getSupportedServiceNames() 434 { 435 Sequence< OUString > aRet(1); 436 aRet[0] = OUString::createFromAscii( OS2_CLIPBOARD_SERVICE_NAME ); 437 return aRet; 438 } 439 440 // ------------------------------------------------------------------------ 441 442 Reference< XInterface > SAL_CALL Os2Clipboard_createInstance( 443 const Reference< XMultiServiceFactory > & xMultiServiceFactory) 444 { 445 return Reference < XInterface >( ( OWeakObject * ) new Os2Clipboard()); 446 } 447 448