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