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 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 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 // 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 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 89 sal_Bool SAL_CALL DragSource::isDragImageSupported( ) 90 throw(RuntimeException) 91 { 92 return 0; 93 } 94 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 // 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 178 sal_Int32 SAL_CALL DragSource::getCurrentCursor( ) 179 throw( RuntimeException) 180 { 181 return 0; 182 } 183 184 void SAL_CALL DragSource::setCursor( sal_Int32 /*cursorId*/ ) 185 throw( RuntimeException) 186 { 187 } 188 189 void SAL_CALL DragSource::setImage( sal_Int32 /*imageId*/ ) 190 throw( RuntimeException) 191 { 192 } 193 194 void SAL_CALL DragSource::transferablesFlavorsChanged( ) 195 throw( RuntimeException) 196 { 197 } 198 199 200 // 201 // XServiceInfo 202 // 203 OUString SAL_CALL DragSource::getImplementationName( ) throw (RuntimeException) 204 { 205 return OUString(RTL_CONSTASCII_USTRINGPARAM(OS2_DNDSOURCE_IMPL_NAME));; 206 } 207 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 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 // 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 // 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