summaryrefslogtreecommitdiffstats
path: root/vcl/osx/DropTarget.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/osx/DropTarget.cxx')
-rw-r--r--vcl/osx/DropTarget.cxx543
1 files changed, 543 insertions, 0 deletions
diff --git a/vcl/osx/DropTarget.cxx b/vcl/osx/DropTarget.cxx
new file mode 100644
index 000000000..56407a40a
--- /dev/null
+++ b/vcl/osx/DropTarget.cxx
@@ -0,0 +1,543 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp>
+#include <cppuhelper/interfacecontainer.hxx>
+#include "clipboard.hxx"
+#include "DropTarget.hxx"
+#include "DragActionConversion.hxx"
+#include "DragSource.hxx"
+#include <rtl/ustring.h>
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <postmac.h>
+#include <osx/salframe.h>
+#include <osx/salframeview.h>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace cppu;
+using namespace osl;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::datatransfer::dnd::DNDConstants;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star;
+using namespace comphelper;
+
+static OUString dropTarget_getImplementationName()
+{
+ return "com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1";
+}
+
+static Sequence<OUString> dropTarget_getSupportedServiceNames()
+{
+ return { OUString("com.sun.star.datatransfer.dnd.OleDropTarget") };
+}
+
+namespace /* private */
+{
+ // Cocoa's coordinate system has its origin lower-left, VCL's
+ // coordinate system upper-left hence we need to transform
+ // coordinates
+
+ void CocoaToVCL(NSPoint& rPoint, const NSRect& bounds)
+ {
+ rPoint.y = bounds.size.height - rPoint.y;
+ }
+}
+
+@implementation DropTargetHelper
+
+-(DropTargetHelper*)initWithDropTarget:(DropTarget*)pdt
+{
+ self = [super init];
+
+ if (self)
+ {
+ mDropTarget = pdt;
+ }
+
+ return self;
+}
+
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
+{
+ return mDropTarget->draggingEntered(sender);
+}
+
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
+{
+ return mDropTarget->draggingUpdated(sender);
+}
+
+-(void)draggingExited:(id <NSDraggingInfo>)sender
+{
+ mDropTarget->draggingExited(sender);
+}
+
+-(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
+{
+ (void) sender;
+ return DropTarget::prepareForDragOperation();
+}
+
+-(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
+{
+ (void) sender;
+ return mDropTarget->performDragOperation();
+}
+
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender
+{
+ mDropTarget->concludeDragOperation(sender);
+}
+
+@end
+
+DropTarget::DropTarget() :
+ WeakComponentImplHelper<XInitialization, XDropTarget, XDropTargetDragContext, XDropTargetDropContext, XServiceInfo>(m_aMutex),
+ mView(nil),
+ mpFrame(nullptr),
+ mDropTargetHelper(nil),
+ mbActive(false),
+ mDragSourceSupportedActions(DNDConstants::ACTION_NONE),
+ mSelectedDropAction(DNDConstants::ACTION_NONE),
+ mDefaultActions(DNDConstants::ACTION_COPY_OR_MOVE | DNDConstants::ACTION_LINK | DNDConstants::ACTION_DEFAULT)
+{
+ mDataFlavorMapper = std::make_shared<DataFlavorMapper>();
+}
+
+DropTarget::~DropTarget()
+{
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ [static_cast<id <DraggingDestinationHandler>>(mView) unregisterDraggingDestinationHandler:mDropTargetHelper];
+ [mDropTargetHelper release];
+}
+
+sal_Int8 DropTarget::determineDropAction(sal_Int8 dropActions, id sender) const
+{
+ sal_Int8 dropAct = dropActions;
+ bool srcAndDestEqual = false;
+
+ if ([sender draggingSource] != nil)
+ {
+ // Internal DnD
+ NSView* destView = [[sender draggingDestinationWindow] contentView];
+ srcAndDestEqual = (DragSource::g_DragSourceView == destView);
+ }
+
+ // If ACTION_DEFAULT is set this means NSDragOperationGeneric
+ // has been set and we map this to ACTION_MOVE or ACTION_COPY
+ // depending on whether or not source and dest are equal,
+ // this hopefully satisfies all parties
+ if( (dropActions == DNDConstants::ACTION_DEFAULT)
+ || ((dropActions == mDragSourceSupportedActions)
+ && !(~mDragSourceSupportedActions & DNDConstants::ACTION_COPY_OR_MOVE ) ) )
+ {
+ dropAct = srcAndDestEqual ? DNDConstants::ACTION_MOVE :
+ DNDConstants::ACTION_COPY;
+ }
+ // if more than one drop actions have been specified
+ // set ACTION_DEFAULT in order to let the drop target
+ // decide which one to use
+ else if (dropActions != DNDConstants::ACTION_NONE &&
+ dropActions != DNDConstants::ACTION_MOVE &&
+ dropActions != DNDConstants::ACTION_COPY &&
+ dropActions != DNDConstants::ACTION_LINK)
+ {
+ if (srcAndDestEqual)
+ {
+ dropAct = dropActions;
+ }
+ else // source and destination are different
+ {
+ if (dropActions & DNDConstants::ACTION_COPY)
+ dropAct = DNDConstants::ACTION_COPY;
+ else if (dropActions & DNDConstants::ACTION_MOVE)
+ dropAct = DNDConstants::ACTION_MOVE;
+ else if (dropActions & DNDConstants::ACTION_LINK)
+ dropAct = DNDConstants::ACTION_LINK;
+ }
+
+ dropAct |= DNDConstants::ACTION_DEFAULT;
+ }
+
+ return dropAct;
+}
+
+NSDragOperation DropTarget::draggingEntered(id sender)
+{
+ // Initially when DnD will be started no modifier key can be pressed yet
+ // thus we are getting all actions that the drag source supports, we save
+ // this value because later the system masks the drag source actions if
+ // a modifier key will be pressed
+ mDragSourceSupportedActions = SystemToOfficeDragActions([sender draggingSourceOperationMask]);
+
+ // Only if the drop target is really interested in the drag actions
+ // supported by the source
+ if (mDragSourceSupportedActions & mDefaultActions)
+ {
+ sal_Int8 currentAction = determineDropAction(mDragSourceSupportedActions, sender);
+
+ NSRect bounds = [mView bounds];
+ NSPoint mouseLoc = [NSEvent mouseLocation];
+
+ id wnd = [mView window];
+ NSPoint dragLocation = [mView convertPoint:[wnd convertRectFromScreen:NSMakeRect(mouseLoc.x, mouseLoc.y, 1, 1)].origin fromView:nil];
+
+ CocoaToVCL(dragLocation, bounds);
+
+ sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x);
+ sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y);
+
+ NSPasteboard* dragPboard = [sender draggingPasteboard];
+ mXCurrentDragClipboard = new AquaClipboard(dragPboard, false);
+
+ uno::Reference<XTransferable> xTransferable = DragSource::g_XTransferable.is() ?
+ DragSource::g_XTransferable : mXCurrentDragClipboard->getContents();
+
+ DropTargetDragEnterEvent dtdee(static_cast<OWeakObject*>(this),
+ 0,
+ this,
+ currentAction,
+ posX,
+ posY,
+ mDragSourceSupportedActions,
+ xTransferable->getTransferDataFlavors());
+
+ fire_dragEnter(dtdee);
+ }
+
+ return OfficeToSystemDragActions(mSelectedDropAction);
+}
+
+NSDragOperation DropTarget::draggingUpdated(id sender)
+{
+ sal_Int8 currentDragSourceActions =
+ SystemToOfficeDragActions([sender draggingSourceOperationMask]);
+ NSDragOperation dragOp = NSDragOperationNone;
+
+ if (currentDragSourceActions & mDefaultActions)
+ {
+ sal_Int8 currentAction = determineDropAction(currentDragSourceActions, sender);
+ NSRect bounds = [mView bounds];
+ NSPoint mouseLoc = [NSEvent mouseLocation];
+
+ id wnd = [mView window];
+ NSPoint dragLocation = [mView convertPoint:[wnd convertRectFromScreen:NSMakeRect(mouseLoc.x, mouseLoc.y, 1, 1)].origin fromView:nil];
+
+ CocoaToVCL(dragLocation, bounds);
+
+ sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x);
+ sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y);
+
+ DropTargetDragEvent dtde(static_cast<OWeakObject*>(this),
+ 0,
+ this,
+ currentAction,
+ posX,
+ posY,
+ mDragSourceSupportedActions);
+
+ fire_dragOver(dtde);
+
+ // drag over callbacks likely have rendered something
+ [mView setNeedsDisplay: true];
+
+ dragOp = OfficeToSystemDragActions(mSelectedDropAction);
+
+ //NSLog(@"Drag update: Source actions: %x proposed action %x selected action %x", mDragSourceSupportedActions, currentAction, mSelectedDropAction);
+ }
+
+ if (dragOp == NSDragOperationNone)
+ [[NSCursor operationNotAllowedCursor] set];
+ else if (dragOp == NSDragOperationCopy)
+ [[NSCursor dragCopyCursor] set];
+ else
+ [[NSCursor arrowCursor] set];
+
+ return dragOp;
+}
+
+void DropTarget::draggingExited(id /*sender*/)
+{
+ DropTargetEvent dte(static_cast<OWeakObject*>(this), 0);
+ fire_dragExit(dte);
+ mDragSourceSupportedActions = DNDConstants::ACTION_NONE;
+ mSelectedDropAction = DNDConstants::ACTION_NONE;
+ [[NSCursor arrowCursor] set];
+}
+
+BOOL DropTarget::prepareForDragOperation()
+{
+ return true;
+}
+
+BOOL DropTarget::performDragOperation()
+{
+ bool bSuccess = false;
+
+ if (mSelectedDropAction != DNDConstants::ACTION_NONE)
+ {
+ uno::Reference<XTransferable> xTransferable = DragSource::g_XTransferable;
+
+ if (!DragSource::g_XTransferable.is())
+ {
+ xTransferable = mXCurrentDragClipboard->getContents();
+ }
+
+ NSRect bounds = [mView bounds];
+ NSPoint mouseLoc = [NSEvent mouseLocation];
+
+ id wnd = [mView window];
+ NSPoint dragLocation = [mView convertPoint:[wnd convertRectFromScreen:NSMakeRect(mouseLoc.x, mouseLoc.y, 1, 1)].origin fromView:nil];
+
+ CocoaToVCL(dragLocation, bounds);
+
+ sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x);
+ sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y);
+
+ DropTargetDropEvent dtde(static_cast<OWeakObject*>(this),
+ 0,
+ this,
+ mSelectedDropAction,
+ posX,
+ posY,
+ mDragSourceSupportedActions,
+ xTransferable);
+
+ fire_drop(dtde);
+
+ bSuccess = true;
+ }
+
+ return bSuccess;
+}
+
+void DropTarget::concludeDragOperation(id /*sender*/)
+{
+ mDragSourceSupportedActions = DNDConstants::ACTION_NONE;
+ mSelectedDropAction = DNDConstants::ACTION_NONE;
+ mXCurrentDragClipboard.clear();
+ [[NSCursor arrowCursor] set];
+}
+
+// called from WeakComponentImplHelperX::dispose
+// WeakComponentImplHelper calls disposing before it destroys
+// itself.
+void SAL_CALL DropTarget::disposing()
+{
+}
+
+void SAL_CALL DropTarget::initialize(const Sequence< Any >& aArguments)
+{
+ if (aArguments.getLength() < 2)
+ {
+ throw RuntimeException("DropTarget::initialize: Cannot install window event handler",
+ static_cast<OWeakObject*>(this));
+ }
+
+ Any pNSView = aArguments[0];
+ sal_uInt64 tmp = 0;
+ pNSView >>= tmp;
+ mView = reinterpret_cast<id>(tmp);
+ mpFrame = [static_cast<SalFrameView*>(mView) getSalFrame];
+
+ mDropTargetHelper = [[DropTargetHelper alloc] initWithDropTarget: this];
+
+ [static_cast<id <DraggingDestinationHandler>>(mView) registerDraggingDestinationHandler:mDropTargetHelper];
+ [mView registerForDraggedTypes: DataFlavorMapper::getAllSupportedPboardTypes()];
+
+ id wnd = [mView window];
+ NSWindow* parentWnd = [wnd parentWindow];
+ unsigned int topWndStyle = (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable);
+ unsigned int wndStyles = [wnd styleMask] & topWndStyle;
+
+ if (parentWnd == nil && (wndStyles == topWndStyle))
+ {
+ [wnd registerDraggingDestinationHandler:mDropTargetHelper];
+SAL_WNODEPRECATED_DECLARATIONS_PUSH
+ // "'NSFilenamesPboardType' is deprecated: first deprecated in macOS 10.14 - Create
+ // multiple pasteboard items with NSPasteboardTypeFileURL or kUTTypeFileURL instead"
+ [wnd registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
+SAL_WNODEPRECATED_DECLARATIONS_POP
+ }
+}
+
+void SAL_CALL DropTarget::addDropTargetListener(const uno::Reference<XDropTargetListener>& dtl)
+{
+ rBHelper.addListener(cppu::UnoType<decltype(dtl)>::get(), dtl);
+}
+
+void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference<XDropTargetListener>& dtl)
+{
+ rBHelper.removeListener(cppu::UnoType<decltype(dtl)>::get(), dtl);
+}
+
+sal_Bool SAL_CALL DropTarget::isActive( )
+{
+ return mbActive;
+}
+
+void SAL_CALL DropTarget::setActive(sal_Bool active)
+{
+ mbActive = active;
+}
+
+sal_Int8 SAL_CALL DropTarget::getDefaultActions()
+{
+ return mDefaultActions;
+}
+
+void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions)
+{
+ OSL_ENSURE( actions < 8, "No valid default actions");
+ mDefaultActions= actions;
+}
+
+void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation)
+{
+ mSelectedDropAction = dragOperation;
+}
+
+void SAL_CALL DropTarget::rejectDrag()
+{
+ mSelectedDropAction = DNDConstants::ACTION_NONE;
+}
+
+void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation)
+{
+ mSelectedDropAction = dropOperation;
+}
+
+void SAL_CALL DropTarget::rejectDrop()
+{
+ mSelectedDropAction = DNDConstants::ACTION_NONE;
+}
+
+void SAL_CALL DropTarget::dropComplete(sal_Bool success)
+{
+ // Reset the internal transferable used as shortcut in case this is
+ // an internal D&D operation
+ DragSource::g_XTransferable.clear();
+ DragSource::g_DropSuccessSet = true;
+ DragSource::g_DropSuccess = success;
+}
+
+void DropTarget::fire_drop( const DropTargetDropEvent& dte)
+{
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->drop( dte); }
+ catch(RuntimeException&) {}
+ }
+ }
+}
+
+void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e)
+{
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->dragEnter( e); }
+ catch (RuntimeException&) {}
+ }
+ }
+}
+
+void DropTarget::fire_dragExit(const DropTargetEvent& dte)
+{
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
+
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->dragExit( dte); }
+ catch (RuntimeException&) {}
+ }
+ }
+}
+
+void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde)
+{
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer );
+ while( iter.hasMoreElements())
+ {
+ uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->dragOver( dtde); }
+ catch (RuntimeException&) {}
+ }
+ }
+}
+
+void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde)
+{
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->dropActionChanged( dtde); }
+ catch (RuntimeException&) {}
+ }
+ }
+}
+
+OUString SAL_CALL DropTarget::getImplementationName()
+{
+ return dropTarget_getImplementationName();
+}
+
+sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( )
+{
+ return dropTarget_getSupportedServiceNames();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */