1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
21 #include <com/sun/star/datatransfer/XTransferable.hpp>
22 #include <com/sun/star/awt/MouseButton.hpp>
24 #include <rtl/ustring.hxx>
26 #include <cppuhelper/supportsservice.hxx>
28 #include "DragSource.hxx"
29 #include "DragSourceContext.hxx"
30 #include "clipboard.hxx"
31 #include "DragActionConversion.hxx"
33 #include <osx/salframe.h>
39 using namespace com::sun::star
;
40 using namespace com::sun::star::datatransfer
;
41 using namespace com::sun::star::datatransfer::clipboard
;
42 using namespace com::sun::star::datatransfer::dnd
;
43 using namespace com::sun::star::datatransfer::dnd::DNDConstants
;
44 using namespace com::sun::star::uno
;
45 using namespace com::sun::star::awt::MouseButton
;
46 using namespace com::sun::star::awt
;
47 using namespace com::sun::star::lang
;
48 using namespace comphelper
;
50 // For LibreOffice internal D&D we provide the Transferable without NSDragPboard
51 // interference as a shortcut, see tdf#100097 for how dbaccess depends on this
52 uno::Reference
<XTransferable
> DragSource::g_XTransferable
;
53 NSView
* DragSource::g_DragSourceView
= nil
;
54 bool DragSource::g_DropSuccessSet
= false;
55 bool DragSource::g_DropSuccess
= false;
57 static OUString
dragSource_getImplementationName()
59 return "com.sun.star.comp.datatransfer.dnd.OleDragSource_V1";
62 static Sequence
<OUString
> dragSource_getSupportedServiceNames()
64 return { OUString("com.sun.star.datatransfer.dnd.OleDragSource") };
67 @implementation DragSourceHelper
;
69 -(DragSourceHelper
*)initWithDragSource
: (DragSource
*) pds
81 -(void)mouseDown
: (NSEvent
*)theEvent
83 mDragSource
->saveMouseEvent(theEvent
);
86 -(void)mouseDragged
: (NSEvent
*)theEvent
88 mDragSource
->saveMouseEvent(theEvent
);
91 -(unsigned int)draggingSourceOperationMaskForLocal
: (BOOL
)isLocal
93 return mDragSource
->getSupportedDragOperations(isLocal
);
96 -(void)draggedImage
:(NSImage
*)anImage beganAt
:(NSPoint
)aPoint
100 DragSourceDragEvent
dsde(static_cast<OWeakObject
*>(mDragSource
),
101 new DragSourceContext
,
103 DNDConstants::ACTION_COPY
,
104 DNDConstants::ACTION_COPY
);
106 mDragSource
->mXDragSrcListener
->dragEnter(dsde
);
109 -(void)draggedImage
:(NSImage
*)anImage endedAt
:(NSPoint
)aPoint operation
:(NSDragOperation
)operation
113 // an internal drop can accept the drop but fail with dropComplete( false )
114 // this is different than the Cocoa API
115 bool bDropSuccess
= operation
!= NSDragOperationNone
;
116 if( DragSource::g_DropSuccessSet
)
117 bDropSuccess
= DragSource::g_DropSuccess
;
119 DragSourceDropEvent
dsde(static_cast<OWeakObject
*>(mDragSource
),
120 new DragSourceContext
,
121 static_cast< XDragSource
* >(mDragSource
),
122 SystemToOfficeDragActions(operation
),
125 mDragSource
->mXDragSrcListener
->dragDropEnd(dsde
);
126 mDragSource
->mXDragSrcListener
.clear();
129 -(void)draggedImage
:(NSImage
*)draggedImage movedTo
:(NSPoint
)screenPoint
133 DragSourceDragEvent
dsde(static_cast<OWeakObject
*>(mDragSource
),
134 new DragSourceContext
,
136 DNDConstants::ACTION_COPY
,
137 DNDConstants::ACTION_COPY
);
139 mDragSource
->mXDragSrcListener
->dragOver(dsde
);
144 DragSource::DragSource():
145 WeakComponentImplHelper
<XDragSource
, XInitialization
, XServiceInfo
>(m_aMutex
),
148 mLastMouseEventBeforeStartDrag(nil
),
149 mDragSourceHelper(nil
),
154 DragSource::~DragSource()
156 if( mpFrame
&& AquaSalFrame::isAlive( mpFrame
) )
157 [static_cast<id
<MouseEventListener
>>(mView
) unregisterMouseEventListener
: mDragSourceHelper
];
158 [mDragSourceHelper release
];
161 void SAL_CALL
DragSource::initialize(const Sequence
< Any
>& aArguments
)
163 if (aArguments
.getLength() < 2)
165 throw Exception("DragSource::initialize: Not enough parameter.",
166 static_cast<OWeakObject
*>(this));
169 Any pNSView
= aArguments
[1];
172 mView
= reinterpret_cast<NSView
*>(tmp
);
174 /* All SalFrameView the base class for all VCL system views inherits from
175 NSView in order to get mouse and other events. This is the only way to
176 get these events. In order to start a drag operation we need to provide
177 the mouse event which was the trigger. SalFrameView therefore implements
178 a hook mechanism so that we can get mouse events for our purpose.
180 if (![mView respondsToSelector
: @
selector(registerMouseEventListener
:)] ||
181 ![mView respondsToSelector
: @
selector(unregisterMouseEventListener
:)])
183 throw Exception("DragSource::initialize: Provided view doesn't support mouse listener",
184 static_cast<OWeakObject
*>(this));
186 NSWindow
* pWin
= [mView window
];
187 if( ! pWin
|| ![pWin respondsToSelector
: @
selector(getSalFrame
)] )
189 throw Exception("DragSource::initialize: Provided view is not attached to a vcl frame",
190 static_cast<OWeakObject
*>(this));
192 mpFrame
= reinterpret_cast<AquaSalFrame
*>([pWin performSelector
: @
selector(getSalFrame
)]);
194 mDragSourceHelper
= [[DragSourceHelper alloc
] initWithDragSource
: this];
196 if (mDragSourceHelper
== nil
)
198 throw Exception("DragSource::initialize: Cannot initialize DragSource",
199 static_cast<OWeakObject
*>(this));
202 [static_cast<id
<MouseEventListener
>>(mView
) registerMouseEventListener
: mDragSourceHelper
];
205 sal_Bool SAL_CALL
DragSource::isDragImageSupported( )
210 sal_Int32 SAL_CALL
DragSource::getDefaultCursor( sal_Int8
/*dragAction*/ )
215 void SAL_CALL
DragSource::startDrag(const DragGestureEvent
& trigger
,
216 sal_Int8 sourceActions
,
217 sal_Int32
/*cursor*/,
219 const uno::Reference
<XTransferable
>& transferable
,
220 const uno::Reference
<XDragSourceListener
>& listener
)
222 MutexGuard
guard(m_aMutex
);
224 assert(listener
.is() && "DragSource::startDrag: No XDragSourceListener provided");
225 assert(transferable
.is() && "DragSource::startDrag: No transferable provided");
227 trigger
.Event
>>= mMouseEvent
;
228 m_MouseButton
= mMouseEvent
.Buttons
;
229 mXDragSrcListener
= listener
;
230 mXCurrentContext
= static_cast<XDragSourceContext
*>(new DragSourceContext
);
231 rtl::Reference
<AquaClipboard
> clipb(new AquaClipboard(nullptr, false));
232 g_XTransferable
= transferable
;
233 clipb
->setContents(g_XTransferable
, uno::Reference
<XClipboardOwner
>());
234 mDragSourceActions
= sourceActions
;
235 g_DragSourceView
= mView
;
242 dragImage
= [[NSImage alloc
] initWithSize
: sz
];
245 bounds
.origin
= NSMakePoint(0,0);
248 [dragImage lockFocus
];
249 [[NSColor blackColor
] set
];
250 [NSBezierPath fillRect
: bounds
];
251 [dragImage unlockFocus
];
253 NSPoint pInWnd
= [mLastMouseEventBeforeStartDrag locationInWindow
];
255 p
= [mView convertPoint
: pInWnd fromView
: nil
];
256 p
.x
= p
.x
- sz
.width
/2;
257 p
.y
= p
.y
- sz
.height
/2;
259 // reset drop success flags
260 g_DropSuccessSet
= false;
261 g_DropSuccess
= false;
263 SAL_WNODEPRECATED_DECLARATIONS_PUSH
264 //TODO: 10.7 dragImage:at:offset:event:pasteboard:source:slideBack:
265 [mView dragImage
: dragImage
267 offset
: NSMakeSize(0,0)
268 event
: mLastMouseEventBeforeStartDrag
269 pasteboard
: clipb
->getPasteboard()
270 source
: mDragSourceHelper
272 SAL_WNODEPRECATED_DECLARATIONS_POP
276 g_XTransferable
.clear();
277 g_DragSourceView
= nil
;
279 // reset drop success flags
280 g_DropSuccessSet
= false;
281 g_DropSuccess
= false;
284 // In order to initiate a D&D operation we need to
285 // provide the triggering mouse event which we get
286 // from the SalFrameView that is associated with
288 void DragSource::saveMouseEvent(NSEvent
* theEvent
)
290 if (mLastMouseEventBeforeStartDrag
!= nil
)
292 [mLastMouseEventBeforeStartDrag release
];
295 mLastMouseEventBeforeStartDrag
= theEvent
;
298 /* isLocal indicates whether or not the DnD operation is OOo
301 unsigned int DragSource::getSupportedDragOperations(bool isLocal
) const
303 unsigned int srcActions
= OfficeToSystemDragActions(mDragSourceActions
);
307 // Support NSDragOperation generic which means we can
308 // decide which D&D operation to choose. We map
309 // NSDragOperationGeneric to DNDConstants::ACTION_DEFAULT
310 // in SystemToOfficeDragActions to signal this and
311 // use it in DropTarget::determineDropAction
312 srcActions
|= NSDragOperationGeneric
;
316 // Mask out link and move operations on external DnD
317 srcActions
&= ~(NSDragOperationMove
| NSDragOperationLink
);
323 OUString SAL_CALL
DragSource::getImplementationName( )
325 return dragSource_getImplementationName();
328 sal_Bool SAL_CALL
DragSource::supportsService( const OUString
& ServiceName
)
330 return cppu::supportsService(this, ServiceName
);
333 Sequence
< OUString
> SAL_CALL
DragSource::getSupportedServiceNames()
335 return dragSource_getSupportedServiceNames();
338 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */