unipoll: get SolarMutex lock counting right.
[LibreOffice.git] / vcl / osx / DragSource.cxx
blob6203152829ebe7408300c2022ada79c908f35e31
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
35 #include <cassert>
37 using namespace cppu;
38 using namespace osl;
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 OUString("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
71 self = [super init];
73 if (self)
75 mDragSource = pds;
78 return self;
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
98 (void)anImage;
99 (void)aPoint;
100 DragSourceDragEvent dsde(static_cast<OWeakObject*>(mDragSource),
101 new DragSourceContext,
102 mDragSource,
103 DNDConstants::ACTION_COPY,
104 DNDConstants::ACTION_COPY);
106 mDragSource->mXDragSrcListener->dragEnter(dsde);
109 -(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
111 (void)anImage;
112 (void)aPoint;
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),
123 bDropSuccess );
125 mDragSource->mXDragSrcListener->dragDropEnd(dsde);
126 mDragSource->mXDragSrcListener.clear();
129 -(void)draggedImage:(NSImage *)draggedImage movedTo:(NSPoint)screenPoint
131 (void)draggedImage;
132 (void)screenPoint;
133 DragSourceDragEvent dsde(static_cast<OWeakObject*>(mDragSource),
134 new DragSourceContext,
135 mDragSource,
136 DNDConstants::ACTION_COPY,
137 DNDConstants::ACTION_COPY);
139 mDragSource->mXDragSrcListener->dragOver(dsde);
142 @end
144 DragSource::DragSource():
145 WeakComponentImplHelper<XDragSource, XInitialization, XServiceInfo>(m_aMutex),
146 mView(nullptr),
147 mpFrame(nullptr),
148 mLastMouseEventBeforeStartDrag(nil),
149 mDragSourceHelper(nil),
150 m_MouseButton(0)
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];
170 sal_uInt64 tmp = 0;
171 pNSView >>= tmp;
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( )
207 return true;
210 sal_Int32 SAL_CALL DragSource::getDefaultCursor( sal_Int8 /*dragAction*/ )
212 return 0;
215 void SAL_CALL DragSource::startDrag(const DragGestureEvent& trigger,
216 sal_Int8 sourceActions,
217 sal_Int32 /*cursor*/,
218 sal_Int32 /*image*/,
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;
237 NSSize sz;
238 sz.width = 5;
239 sz.height = 5;
241 NSImage* dragImage;
242 dragImage = [[NSImage alloc] initWithSize: sz];
244 NSRect bounds;
245 bounds.origin = NSMakePoint(0,0);
246 bounds.size = sz;
248 [dragImage lockFocus];
249 [[NSColor blackColor] set];
250 [NSBezierPath fillRect: bounds];
251 [dragImage unlockFocus];
253 NSPoint pInWnd = [mLastMouseEventBeforeStartDrag locationInWindow];
254 NSPoint p;
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
266 at: p
267 offset: NSMakeSize(0,0)
268 event: mLastMouseEventBeforeStartDrag
269 pasteboard: clipb->getPasteboard()
270 source: mDragSourceHelper
271 slideBack: 1];
272 SAL_WNODEPRECATED_DECLARATIONS_POP
274 [dragImage release];
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
287 // this DragSource
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
299 internal.
301 unsigned int DragSource::getSupportedDragOperations(bool isLocal) const
303 unsigned int srcActions = OfficeToSystemDragActions(mDragSourceActions);
305 if (isLocal)
307 // Support NSDragOperation generic which means we can
308 // decide which D&D operation to choose. We map
309 // NSDragOperationGenric to DNDConstants::ACTION_DEFAULT
310 // in SystemToOfficeDragActions to signal this and
311 // use it in DropTarget::determineDropAction
312 srcActions |= NSDragOperationGeneric;
314 else
316 // Mask out link and move operations on external DnD
317 srcActions &= ~(NSDragOperationMove | NSDragOperationLink);
320 return srcActions;
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: */