LibreOffice Module vcl (master)  1
dndeventdispatcher.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <dndeventdispatcher.hxx>
21 #include <dndlistenercontainer.hxx>
22 #include <sal/log.hxx>
23 
24 #include <osl/mutex.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/settings.hxx>
27 
28 using namespace ::cppu;
29 using namespace ::com::sun::star::uno;
30 using namespace ::com::sun::star::lang;
31 using namespace ::com::sun::star::datatransfer;
32 using namespace ::com::sun::star::datatransfer::dnd;
33 
35  m_pTopWindow( pTopWindow ),
36  m_pCurrentWindow( nullptr )
37 {
38 }
39 
41 {
42  designate_currentwindow(nullptr);
43 }
44 
46 {
47  SolarMutexGuard aSolarGuard;
48 
49  // find the window that is toplevel for this coordinates
50  // because those coordinates come from outside, they must be mirrored if RTL layout is active
52  m_pTopWindow->ImplMirrorFramePos( location );
53  vcl::Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
54 
55  if( nullptr == pChildWindow )
56  pChildWindow = m_pTopWindow;
57 
58  while( pChildWindow->ImplGetClientWindow() )
59  pChildWindow = pChildWindow->ImplGetClientWindow();
60 
61  if( pChildWindow->ImplIsAntiparallel() )
62  {
63  const OutputDevice *pChildWinOutDev = pChildWindow->GetOutDev();
64  pChildWinOutDev->ReMirror( location );
65  }
66 
67  return pChildWindow;
68 }
69 
70 IMPL_LINK(DNDEventDispatcher, WindowEventListener, VclWindowEvent&, rEvent, void)
71 {
72  if (rEvent.GetId() == VclEventId::ObjectDying)
73  {
74  designate_currentwindow(nullptr);
75  }
76 }
77 
79 {
80  if (m_pCurrentWindow)
81  m_pCurrentWindow->RemoveEventListener(LINK(this, DNDEventDispatcher, WindowEventListener));
82  m_pCurrentWindow = pWindow;
83  if (m_pCurrentWindow)
84  m_pCurrentWindow->AddEventListener(LINK(this, DNDEventDispatcher, WindowEventListener));
85 }
86 
87 void SAL_CALL DNDEventDispatcher::drop( const DropTargetDropEvent& dtde )
88 {
89  osl::MutexGuard aImplGuard( m_aMutex );
90 
91  Point location( dtde.LocationX, dtde.LocationY );
92 
93  vcl::Window* pChildWindow = findTopLevelWindow(location);
94 
95  // handle the case that drop is in another vcl window than the last dragOver
96  if( pChildWindow != m_pCurrentWindow.get() )
97  {
98  // fire dragExit on listeners of previous window
100 
101  fireDragEnterEvent( pChildWindow, static_cast < XDropTargetDragContext * > (this),
102  dtde.DropAction, location, dtde.SourceActions, m_aDataFlavorList );
103  }
104 
105  // send drop event to the child window
106  sal_Int32 nListeners = fireDropEvent( pChildWindow, dtde.Context, dtde.DropAction,
107  location, dtde.SourceActions, dtde.Transferable );
108 
109  // reject drop if no listeners found
110  if( nListeners == 0 ) {
111  SAL_WARN( "vcl", "rejecting drop due to missing listeners." );
112  dtde.Context->rejectDrop();
113  }
114 
115  // this is a drop -> no further drag overs
116  designate_currentwindow(nullptr);
117  m_aDataFlavorList.realloc( 0 );
118 }
119 
120 void SAL_CALL DNDEventDispatcher::dragEnter( const DropTargetDragEnterEvent& dtdee )
121 {
122  osl::MutexGuard aImplGuard( m_aMutex );
123  Point location( dtdee.LocationX, dtdee.LocationY );
124 
125  vcl::Window * pChildWindow = findTopLevelWindow(location);
126 
127  // assume pointer write operation to be atomic
128  designate_currentwindow(pChildWindow);
129  m_aDataFlavorList = dtdee.SupportedDataFlavors;
130 
131  // fire dragEnter on listeners of current window
132  sal_Int32 nListeners = fireDragEnterEvent( pChildWindow, dtdee.Context, dtdee.DropAction, location,
133  dtdee.SourceActions, dtdee.SupportedDataFlavors );
134 
135  // reject drag if no listener found
136  if( nListeners == 0 ) {
137  SAL_WARN( "vcl", "rejecting drag enter due to missing listeners." );
138  dtdee.Context->rejectDrag();
139  }
140 
141 }
142 
143 void SAL_CALL DNDEventDispatcher::dragExit( const DropTargetEvent& /*dte*/ )
144 {
145  osl::MutexGuard aImplGuard( m_aMutex );
146 
148 
149  // reset member values
150  designate_currentwindow(nullptr);
151  m_aDataFlavorList.realloc( 0 );
152 }
153 
154 void SAL_CALL DNDEventDispatcher::dragOver( const DropTargetDragEvent& dtde )
155 {
156  osl::MutexGuard aImplGuard( m_aMutex );
157 
158  Point location( dtde.LocationX, dtde.LocationY );
159  sal_Int32 nListeners;
160 
161  vcl::Window * pChildWindow = findTopLevelWindow(location);
162 
163  if( pChildWindow != m_pCurrentWindow.get() )
164  {
165  // fire dragExit on listeners of previous window
167 
168  // remember new window
169  designate_currentwindow(pChildWindow);
170 
171  // fire dragEnter on listeners of current window
172  nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
173  dtde.SourceActions, m_aDataFlavorList );
174  }
175  else
176  {
177  // fire dragOver on listeners of current window
178  nListeners = fireDragOverEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
179  dtde.SourceActions );
180  }
181 
182  // reject drag if no listener found
183  if( nListeners == 0 )
184  {
185  SAL_WARN( "vcl", "rejecting drag over due to missing listeners." );
186  dtde.Context->rejectDrag();
187  }
188 }
189 
190 void SAL_CALL DNDEventDispatcher::dropActionChanged( const DropTargetDragEvent& dtde )
191 {
192  osl::MutexGuard aImplGuard( m_aMutex );
193 
194  Point location( dtde.LocationX, dtde.LocationY );
195  sal_Int32 nListeners;
196 
197  vcl::Window* pChildWindow = findTopLevelWindow(location);
198 
199  if( pChildWindow != m_pCurrentWindow.get() )
200  {
201  // fire dragExit on listeners of previous window
203 
204  // remember new window
205  designate_currentwindow(pChildWindow);
206 
207  // fire dragEnter on listeners of current window
208  nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
209  dtde.SourceActions, m_aDataFlavorList );
210  }
211  else
212  {
213  // fire dropActionChanged on listeners of current window
214  nListeners = fireDropActionChangedEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
215  dtde.SourceActions );
216  }
217 
218  // reject drag if no listener found
219  if( nListeners == 0 )
220  {
221  SAL_WARN( "vcl", "rejecting dropActionChanged due to missing listeners." );
222  dtde.Context->rejectDrag();
223  }
224 }
225 
226 void SAL_CALL DNDEventDispatcher::dragGestureRecognized( const DragGestureEvent& dge )
227 {
228  osl::MutexGuard aImplGuard( m_aMutex );
229 
230  Point origin( dge.DragOriginX, dge.DragOriginY );
231 
232  vcl::Window* pChildWindow = findTopLevelWindow(origin);
233 
234  fireDragGestureEvent( pChildWindow, dge.DragSource, dge.Event, origin, dge.DragAction );
235 }
236 
237 void SAL_CALL DNDEventDispatcher::disposing( const EventObject& )
238 {
239 }
240 
241 void SAL_CALL DNDEventDispatcher::acceptDrag( sal_Int8 /*dropAction*/ )
242 {
243 }
244 
246 {
247 }
248 
250  const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
251  const Point& rLocation, const sal_Int8 nSourceActions, const Sequence< DataFlavor >& aFlavorList
252 )
253 {
254  sal_Int32 n = 0;
255 
256  if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
257  {
258  SolarMutexClearableGuard aSolarGuard;
259 
260  // query DropTarget from window
261  Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
262 
263  if( xDropTarget.is() )
264  {
265  // retrieve relative mouse position
266  Point relLoc = pWindow->ImplFrameToOutput( rLocation );
267  aSolarGuard.clear();
268 
269  n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragEnterEvent(
270  xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, aFlavorList );
271  }
272  }
273 
274  return n;
275 }
276 
278  const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
279  const Point& rLocation, const sal_Int8 nSourceActions
280 )
281 {
282  sal_Int32 n = 0;
283 
284  if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
285  {
286  SolarMutexClearableGuard aSolarGuard;
287 
288  // query DropTarget from window
289  Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
290 
291  if( xDropTarget.is() )
292  {
293  // retrieve relative mouse position
294  Point relLoc = pWindow->ImplFrameToOutput( rLocation );
295  aSolarGuard.clear();
296 
297  n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragOverEvent(
298  xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions );
299  }
300  }
301 
302  return n;
303 }
304 
306 {
307  sal_Int32 n = 0;
308 
309  if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
310  {
312 
313  // query DropTarget from window
314  Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
315 
316  aGuard.clear();
317 
318  if( xDropTarget.is() )
319  n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragExitEvent();
320  }
321 
322  return n;
323 }
324 
326  const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
327  const Point& rLocation, const sal_Int8 nSourceActions
328 )
329 {
330  sal_Int32 n = 0;
331 
332  if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
333  {
335 
336  // query DropTarget from window
337  Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
338 
339  if( xDropTarget.is() )
340  {
341  // retrieve relative mouse position
342  Point relLoc = pWindow->ImplFrameToOutput( rLocation );
343  aGuard.clear();
344 
345  n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropActionChangedEvent(
346  xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions );
347  }
348  }
349 
350  return n;
351 }
352 
354  const Reference< XDropTargetDropContext >& xContext, const sal_Int8 nDropAction, const Point& rLocation,
355  const sal_Int8 nSourceActions, const Reference< XTransferable >& xTransferable
356 )
357 {
358  sal_Int32 n = 0;
359 
360  if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
361  {
363 
364  // query DropTarget from window
365  Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
366 
367  // window may be destroyed in drop event handler
368  VclPtr<vcl::Window> xWindow = pWindow;
369 
370  if( xDropTarget.is() )
371  {
372  // retrieve relative mouse position
373  Point relLoc = pWindow->ImplFrameToOutput( rLocation );
374  aGuard.clear();
375 
376  n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropEvent(
377  xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, xTransferable );
378  }
379  }
380 
381  return n;
382 }
383 
385  const Reference< XDragSource >& xSource, const Any& event,
386  const Point& rOrigin, const sal_Int8 nDragAction
387 )
388 {
389  sal_Int32 n = 0;
390 
391  if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
392  {
394 
395  // query DropTarget from window
396  Reference< XDragGestureRecognizer > xDragGestureRecognizer = pWindow->GetDragGestureRecognizer();
397 
398  if( xDragGestureRecognizer.is() )
399  {
400  // retrieve relative mouse position
401  Point relLoc = pWindow->ImplFrameToOutput( rOrigin );
402  aGuard.clear();
403 
404  n = static_cast < DNDListenerContainer * > ( xDragGestureRecognizer.get() )->fireDragGestureEvent(
405  nDragAction, relLoc.X(), relLoc.Y(), xSource, event );
406  }
407  }
408 
409  return n;
410 }
411 
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Sequence< css::datatransfer::DataFlavor > m_aDataFlavorList
SAL_DLLPRIVATE vcl::Window * ImplFindWindow(const Point &rFramePos)
Definition: stacking.cxx:633
bool IsInputEnabled() const
Definition: window2.cxx:1121
signed char sal_Int8
static sal_Int32 fireDragEnterEvent(vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext > &xContext, const sal_Int8 nDropAction, const Point &rLocation, const sal_Int8 nSourceAction, const css::uno::Sequence< css::datatransfer::DataFlavor > &aFlavorList)
virtual void SAL_CALL drop(const css::datatransfer::dnd::DropTargetDropEvent &dtde) override
DNDEventDispatcher(vcl::Window *pTopWindow)
SAL_DLLPRIVATE void ReMirror(Point &rPoint) const
Definition: outdev.cxx:620
virtual void SAL_CALL dragGestureRecognized(const css::datatransfer::dnd::DragGestureEvent &dge) override
virtual ~DNDEventDispatcher() override
css::uno::Reference< css::datatransfer::dnd::XDragGestureRecognizer > GetDragGestureRecognizer()
Definition: mouse.cxx:783
void designate_currentwindow(vcl::Window *pWindow)
virtual void SAL_CALL disposing(const css::lang::EventObject &eo) override
virtual void SAL_CALL dropActionChanged(const css::datatransfer::dnd::DropTargetDragEvent &dtde) override
static sal_Int32 fireDragExitEvent(vcl::Window *pWindow)
virtual void SAL_CALL dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent &dtdee) override
static sal_Int32 fireDragOverEvent(vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext > &xContext, const sal_Int8 nDropAction, const Point &rLocation, const sal_Int8 nSourceAction)
SAL_DLLPRIVATE bool ImplIsAntiparallel() const
Definition: outdev.cxx:604
css::uno::Reference< css::datatransfer::dnd::XDropTarget > GetDropTarget()
Definition: mouse.cxx:657
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:304
static bool GetLayoutRTL()
bool IsInModalMode() const
A window is in modal mode if one of its children or subchildren is a running modal window (a modal di...
Definition: window.cxx:3455
SAL_DLLPRIVATE vcl::Window * ImplGetClientWindow() const
Definition: window2.cxx:869
long X() const
IMPL_LINK(DNDEventDispatcher, WindowEventListener, VclWindowEvent &, rEvent, void)
VclPtr< vcl::Window > m_pTopWindow
static sal_Int32 fireDragGestureEvent(vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDragSource > &xSource, const css::uno::Any &event, const Point &rOrigin, const sal_Int8 nDragAction)
void AddEventListener(const Link< VclWindowEvent &, void > &rEventListener)
Definition: event.cxx:292
SAL_DLLPRIVATE void ImplMirrorFramePos(Point &pt) const
Definition: window.cxx:3449
::OutputDevice const * GetOutDev() const
Definition: window.cxx:570
static sal_Int32 fireDropActionChangedEvent(vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext > &xContext, const sal_Int8 nDropAction, const Point &rLocation, const sal_Int8 nSourceAction)
virtual void SAL_CALL dragOver(const css::datatransfer::dnd::DropTargetDragEvent &dtde) override
SAL_DLLPRIVATE Point ImplFrameToOutput(const Point &rPos)
Definition: window2.cxx:936
virtual void SAL_CALL rejectDrag() override
virtual void SAL_CALL acceptDrag(sal_Int8 dropAction) override
vcl::Window * findTopLevelWindow(Point location)
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
#define SAL_WARN(area, stream)
void RemoveEventListener(const Link< VclWindowEvent &, void > &rEventListener)
Definition: event.cxx:297
static sal_Int32 fireDropEvent(vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDropTargetDropContext > &xContext, const sal_Int8 nDropAction, const Point &rLocation, const sal_Int8 nSourceAction, const css::uno::Reference< css::datatransfer::XTransferable > &xTransferable)
virtual void SAL_CALL dragExit(const css::datatransfer::dnd::DropTargetEvent &dte) override
VclPtr< vcl::Window > m_pCurrentWindow
long Y() const