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 // MARKER(update_precomp.py): autogen include statement, do not remove
24 #include "precompiled_dtrans.hxx"
25 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
26 #include <com/sun/star/datatransfer/XTransferable.hpp>
27 #include <com/sun/star/awt/MouseButton.hpp>
28 #include <com/sun/star/awt/MouseEvent.hpp>
29
30 #include <vcl/window.hxx>
31
32 #include "DragSource.hxx"
33 #include "globals.hxx"
34
35 using namespace com::sun::star::datatransfer::dnd::DNDConstants;
36
37 // for AOO internal D&D we provide the Transferable
38 Reference<XTransferable> DragSource::g_XTransferable;
39 // the handle of the window starting the drag
40 HWND DragSource::g_DragSourceHwnd = NULLHANDLE;
41
42
DragSource(const Reference<XMultiServiceFactory> & sf)43 DragSource::DragSource( const Reference<XMultiServiceFactory>& sf):
44 WeakComponentImplHelper4< XDragSource,
45 XInitialization,
46 XDragSourceContext,
47 XServiceInfo >(m_aMutex),
48 m_serviceFactory(sf),
49 pSourceDraginfo(NULL),
50 pSharedMem(NULL),
51 pDTShareMem(NULL)
52 {
53 g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt);
54 debug_printf("DragSource::DragSource");
55 }
56
~DragSource()57 DragSource::~DragSource()
58 {
59 g_moduleCount.modCnt.release( &g_moduleCount.modCnt);
60 debug_printf("DragSource::~DragSource");
61 }
62
63 // XInitialization
64
65 //
66 // aArguments contains a machine id
67 //
initialize(const Sequence<Any> & aArguments)68 void SAL_CALL DragSource::initialize( const Sequence< Any >& aArguments )
69 throw(Exception, RuntimeException)
70 {
71 if (aArguments.getLength() < 2) {
72 throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Not enough parameter.")),
73 static_cast<OWeakObject*>(this));
74 }
75
76 m_hWnd = *(HWND*)aArguments[1].getValue();
77 debug_printf("DragSource::initialize hwnd %x", m_hWnd);
78 // init done in DropTarget, window is already subclassed
79 SetWindowDragSourcePtr( m_hWnd, this);
80 }
81
disposing()82 void SAL_CALL DragSource::disposing()
83 {
84 debug_printf("DragSource::disposing hwnd %x", m_hWnd);
85 SetWindowDragSourcePtr( m_hWnd, 0);
86 }
87
88 // XDragSource
isDragImageSupported()89 sal_Bool SAL_CALL DragSource::isDragImageSupported( )
90 throw(RuntimeException)
91 {
92 return 0;
93 }
94
getDefaultCursor(sal_Int8)95 sal_Int32 SAL_CALL DragSource::getDefaultCursor( sal_Int8 /*dragAction*/ )
96 throw( IllegalArgumentException, RuntimeException)
97 {
98 return 0;
99 }
100
101 //
102 // Notifies the XDragSourceListener by calling dragDropEnd
103 //
startDrag(const DragGestureEvent &,sal_Int8 sourceActions,sal_Int32,sal_Int32,const Reference<XTransferable> & trans,const Reference<XDragSourceListener> & listener)104 void SAL_CALL DragSource::startDrag(
105 const DragGestureEvent& /* trigger */,
106 sal_Int8 sourceActions,
107 sal_Int32 /* cursor */,
108 sal_Int32 /* image */,
109 const Reference<XTransferable >& trans,
110 const Reference<XDragSourceListener >& listener ) throw( RuntimeException)
111 {
112 debug_printf("DragSource::startDrag hwnd %x, sourceActions %d",
113 m_hWnd, sourceActions);
114
115 DRAGITEM dragItem;
116 DRAGIMAGE dimg;
117 HSTR hstrType, hstrRMF;
118 HWND hwndTarget;
119
120 // store transferable for internal AOO d&d operations
121 g_XTransferable = trans;
122 // store drag source window handle in a global field since we can
123 // start only one drag operation at time
124 g_DragSourceHwnd = m_hWnd;
125
126 #if 1
127 // dump data flavours
128 Sequence<DataFlavor> seq = g_XTransferable->getTransferDataFlavors();
129 for( int i=0; i<seq.getLength(); i++) {
130 DataFlavor df = seq[i];
131 debug_printf("DragSource::startDrag mimetype %s",
132 ::rtl::OUStringToOString( df.MimeType, RTL_TEXTENCODING_UTF8 ).getStr());
133 }
134 #endif
135
136 dragSourceListener = listener;
137 debug_printf("DragSource::startDrag dragSourceListener 0x%x", dragSourceListener.get());
138
139 // allocate OS/2 specific resources
140 pSourceDraginfo = DrgAllocDraginfo(1);
141 pSourceDraginfo->hwndSource = m_hWnd;
142
143 hstrType = DrgAddStrHandle( DRT_TEXT);
144 hstrRMF = DrgAddStrHandle( "<DRM_DTSHARE,DRF_TEXT>,<DRM_SHAREDMEM,DRF_TEXT>,<DRM_OS2FILE,DRF_TEXT>");
145
146 dragItem.hwndItem = m_hWnd;
147 dragItem.ulItemID = 1;
148 dragItem.hstrType = hstrType;
149 dragItem.hstrRMF = hstrRMF;
150 dragItem.hstrContainerName = NULL; // force rendering
151 dragItem.hstrSourceName = NULL;
152 dragItem.hstrTargetName = NULL;
153 dragItem.fsControl = 0;
154 dragItem.fsSupportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE;
155
156 dimg.cb = sizeof(dimg);
157 dimg.hImage = WinQuerySysPointer( HWND_DESKTOP, SPTR_FILE, FALSE);
158 dimg.fl = DRG_ICON | DRG_TRANSPARENT;
159 dimg.cxOffset = 0;
160 dimg.cyOffset = 0;
161
162 DrgSetDragitem( pSourceDraginfo, &dragItem, sizeof(dragItem), 0);
163
164 // start PM dragging
165 hwndTarget = DrgDrag( m_hWnd, pSourceDraginfo, &dimg, 1L, VK_BUTTON2, NULL);
166 if (hwndTarget == NULLHANDLE) {
167 // post a dummy message to ourselves to allow freeing resources
168 // (yes, we could call endConversation() directly)
169 WinPostMsg( m_hWnd, DM_AOO_ENDCONVERSATION,
170 0, MPFROMSHORT(DMFL_TARGETFAIL));
171 }
172
173 debug_printf("DragSource::startDrag hwndTarget %x", hwndTarget);
174
175 }
176
177 // XDragSourceContext
getCurrentCursor()178 sal_Int32 SAL_CALL DragSource::getCurrentCursor( )
179 throw( RuntimeException)
180 {
181 return 0;
182 }
183
setCursor(sal_Int32)184 void SAL_CALL DragSource::setCursor( sal_Int32 /*cursorId*/ )
185 throw( RuntimeException)
186 {
187 }
188
setImage(sal_Int32)189 void SAL_CALL DragSource::setImage( sal_Int32 /*imageId*/ )
190 throw( RuntimeException)
191 {
192 }
193
transferablesFlavorsChanged()194 void SAL_CALL DragSource::transferablesFlavorsChanged( )
195 throw( RuntimeException)
196 {
197 }
198
199
200 //
201 // XServiceInfo
202 //
getImplementationName()203 OUString SAL_CALL DragSource::getImplementationName( ) throw (RuntimeException)
204 {
205 return OUString(RTL_CONSTASCII_USTRINGPARAM(OS2_DNDSOURCE_IMPL_NAME));;
206 }
207
supportsService(const OUString & ServiceName)208 sal_Bool SAL_CALL DragSource::supportsService( const OUString& ServiceName ) throw (RuntimeException)
209 {
210 if( ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(OS2_DNDSOURCE_SERVICE_NAME ))))
211 return sal_True;
212 return sal_False;
213 }
214
getSupportedServiceNames()215 Sequence< OUString > SAL_CALL DragSource::getSupportedServiceNames( ) throw (RuntimeException)
216 {
217 OUString names[1]= {OUString(RTL_CONSTASCII_USTRINGPARAM(OS2_DNDSOURCE_SERVICE_NAME))};
218 return Sequence<OUString>(names, 1);
219 }
220
221
222 //
223 // OS/2 specific platform code
224 //
225
226
227 //
228 // AOO as source window vs external drop target.
229 //
230 // this is sent when drop target requests the render
231 //
render(PDRAGTRANSFER pdxfer)232 MRESULT DragSource::render( PDRAGTRANSFER pdxfer)
233 {
234 APIRET rc;
235 ULONG ulLength;
236 PSZ pRMF;
237 bool rv = false;
238
239 ulLength = DrgQueryStrNameLen( pdxfer->hstrSelectedRMF) + 1;
240 pRMF = (PSZ) malloc( ulLength);
241 DrgQueryStrName( pdxfer->hstrSelectedRMF, ulLength, pRMF);
242 debug_printf("DragSource::render RMF:%s", pRMF);
243 debug_printf("DragSource::render hstrRenderToName:%x", pdxfer->hstrRenderToName);
244
245 if (strstr( pRMF, "<DRM_DTSHARE") != 0) {
246
247 char DTShareName[CCHMAXPATH];
248
249 DataFlavor df;
250 df.MimeType = OUString::createFromAscii( "text/plain;charset=utf-16" );
251 df.DataType = getCppuType( static_cast<OUString*>(0));
252
253 Any aAny = DragSource::g_XTransferable->getTransferData(df);
254 OUString utext;
255 aAny >>= utext;
256 OString text = ::rtl::OUStringToOString( utext, RTL_TEXTENCODING_UTF8).getStr();
257 debug_printf("DragSource::render text:%s", text.getStr());
258 debug_printf("DragSource::render text.getLength():%d", text.getLength());
259
260 DrgQueryStrName( pdxfer->hstrRenderToName, sizeof(DTShareName),
261 DTShareName);
262 debug_printf("DragSource::render hstrRenderToName:%s", DTShareName);
263
264 rc = DosGetNamedSharedMem( (PPVOID) &pDTShareMem, DTShareName,
265 PAG_WRITE | PAG_READ);
266 debug_printf("DragSource::render DosGetNamedSharedMem rc:%d", rc);
267 debug_printf("DragSource::render DosGetNamedSharedMem pSharedMem:%x", pSharedMem);
268
269 // the memory is still not committed
270 rc = DosSetMem( pDTShareMem, text.getLength()+1, PAG_DEFAULT | PAG_COMMIT);
271 debug_printf("DragSource::render DosSetMem rc:%d", rc);
272
273 // first ULONG is text length
274 *(ULONG*) pDTShareMem = text.getLength();
275 // text data from 2nd ULONG
276 memcpy( pDTShareMem + sizeof(ULONG), text.getStr(),
277 text.getLength()+1);
278
279 // return success
280 rv = true;
281
282 } else if (strstr( pRMF, "<DRM_SHAREDMEM") != 0) {
283
284 PID pid;
285 TID tid;
286 DataFlavor df;
287 df.MimeType = OUString::createFromAscii( "text/plain;charset=utf-16" );
288 df.DataType = getCppuType( static_cast<OUString*>(0));
289
290 Any aAny = DragSource::g_XTransferable->getTransferData(df);
291 OUString utext;
292 aAny >>= utext;
293 OString text = ::rtl::OUStringToOString( utext, RTL_TEXTENCODING_UTF8).getStr();
294 debug_printf("DragSource::render text:%s", text.getStr());
295 debug_printf("DragSource::render text.getLength():%d", text.getLength());
296
297 rc = DosAllocSharedMem( (PPVOID) &pSharedMem, NULL,
298 text.getLength()+sizeof(ULONG)+1,
299 OBJ_GIVEABLE | PAG_COMMIT |
300 PAG_WRITE | PAG_READ /*| OBJ_ANY*/);
301
302 rc = WinQueryWindowProcess( pdxfer->hwndClient, &pid, &tid);
303 rc = DosGiveSharedMem( pSharedMem, pid, PAG_READ);
304
305 debug_printf("DragSource::render rc:%d", rc);
306 *(ULONG *) pSharedMem = text.getLength();
307 memcpy( pSharedMem + sizeof(ULONG), text.getStr(), text.getLength()+1);
308 pdxfer->hstrRenderToName = (HSTR) pSharedMem;
309
310 // return success
311 rv = true;
312
313 } else if (strstr( pRMF, "<DRM_OS2FILE") != 0) {
314
315 char fileName[CCHMAXPATH];
316
317 DataFlavor df;
318 df.MimeType = OUString::createFromAscii( "text/plain;charset=utf-16" );
319 df.DataType = getCppuType( static_cast<OUString*>(0));
320
321 Any aAny = DragSource::g_XTransferable->getTransferData(df);
322 OUString utext;
323 aAny >>= utext;
324 OString text = ::rtl::OUStringToOString( utext, RTL_TEXTENCODING_UTF8).getStr();
325 debug_printf("DragSource::render text:%s", text.getStr());
326 debug_printf("DragSource::render text.getLength():%d", text.getLength());
327
328 DrgQueryStrName( pdxfer->hstrRenderToName, sizeof(fileName), fileName);
329 debug_printf("DragSource::render hstrRenderToName:%s", fileName);
330
331 // write data to target file
332 FILE* tmp = fopen( fileName, "wb");
333 if (tmp) {
334 fwrite( text.getStr(), 1, text.getLength(), tmp);
335 fclose( tmp);
336 rv = true;
337 }
338
339 } else {
340
341 debug_printf("DragSource::render INTERNAL ERROR unknown type");
342
343 }
344
345 free( pRMF);
346
347 // post rendered data
348 int renderOK = (rv==true) ? DMFL_RENDEROK : DMFL_RENDERFAIL;
349 debug_printf("DragSource::render render:%d", renderOK);
350 rc = DrgPostTransferMsg( pdxfer->hwndClient, DM_RENDERCOMPLETE, pdxfer,
351 renderOK, 0, FALSE);
352 debug_printf("DragSource::render DrgPostTransferMsg:%d", rc);
353
354 // free resources
355 DrgFreeDragtransfer(pdxfer);
356
357 return (MRESULT) rv;
358 }
359
360 //
361 // AOO as source window vs external drop target.
362 //
363 // this is sent when external drop target requests the render
364 //
endConversation(ULONG itemID,ULONG flags)365 MRESULT DragSource::endConversation( ULONG itemID, ULONG flags)
366 {
367 sal_Bool success = ((flags==DMFL_TARGETSUCCESSFUL) ? true : false);
368 sal_Int8 effect = ACTION_NONE;
369
370 debug_printf("DragSource::endConversation itemID %d, flags %d", itemID, flags);
371
372 if (pDTShareMem)
373 DosFreeMem( pDTShareMem);
374 pDTShareMem = NULL;
375 if (pSharedMem)
376 DosFreeMem( pSharedMem);
377 pSharedMem = NULL;
378
379 if (pSourceDraginfo) {
380 // query which kind of operation the target did with our data
381 if (success == true)
382 effect = SystemToOfficeDragActions( pSourceDraginfo->usOperation);
383 debug_printf("DragSource::endConversation usOperation 0x%x", pSourceDraginfo->usOperation);
384 DrgDeleteDraginfoStrHandles( pSourceDraginfo);
385 DrgFreeDraginfo( pSourceDraginfo);
386 }
387 pSourceDraginfo = NULL;
388
389 // terminate AOO drag
390 DragSourceDropEvent de(static_cast<OWeakObject*>(this),
391 static_cast<XDragSourceContext*>(this),
392 static_cast<XDragSource*>(this),
393 effect,
394 success);
395 dragSourceListener->dragDropEnd( de);
396
397 // clear globals
398 g_XTransferable = Reference<XTransferable>();
399 g_DragSourceHwnd = NULLHANDLE;
400 dragSourceListener = Reference<XDragSourceListener>();
401
402 // Reserved value, should be 0
403 return 0;
404 }
405