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 "slideshowviewimpl.hxx"
21 #include "slideshowimpl.hxx"
24 #include <vcl/svapp.hxx>
26 #include <com/sun/star/awt/Pointer.hpp>
27 #include <com/sun/star/awt/XWindow.hpp>
28 #include <com/sun/star/awt/XWindowPeer.hpp>
29 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <basegfx/polygon/b2dpolygon.hxx>
32 #include <basegfx/polygon/b2dpolygontools.hxx>
33 #include <basegfx/matrix/b2dhommatrixtools.hxx>
34 #include <basegfx/matrix/b2dhommatrix.hxx>
36 #include <cppcanvas/vclfactory.hxx>
37 #include <cppcanvas/basegfxfactory.hxx>
38 #include <basegfx/utils/canvastools.hxx>
40 #include <toolkit/helper/vclunohelper.hxx>
41 #include <comphelper/processfactory.hxx>
43 using ::com::sun::star::uno::Reference
;
44 using ::com::sun::star::uno::WeakReference
;
45 using ::com::sun::star::uno::Exception
;
47 using namespace ::com::sun::star
;
52 void SlideShowViewMouseListeners::notify( std::unique_lock
<std::mutex
>& rGuard
, const WrappedMouseEvent
& rEvent
)
55 [&rEvent
] (const Reference
<css::awt::XMouseListener
>& rListener
)
57 switch( rEvent
.meType
)
59 case WrappedMouseEvent::PRESSED
:
60 rListener
->mousePressed( rEvent
.maEvent
);
63 case WrappedMouseEvent::RELEASED
:
64 rListener
->mouseReleased( rEvent
.maEvent
);
67 case WrappedMouseEvent::ENTERED
:
68 rListener
->mouseEntered( rEvent
.maEvent
);
71 case WrappedMouseEvent::EXITED
:
72 rListener
->mouseExited( rEvent
.maEvent
);
79 void SlideShowViewMouseMotionListeners::notify( std::unique_lock
<std::mutex
>& rGuard
,const WrappedMouseMotionEvent
& rEvent
)
82 [&rEvent
] (const Reference
< awt::XMouseMotionListener
>& rListener
)
84 switch( rEvent
.meType
)
86 case WrappedMouseMotionEvent::DRAGGED
:
87 rListener
->mouseDragged( rEvent
.maEvent
);
90 case WrappedMouseMotionEvent::MOVED
:
91 rListener
->mouseMoved( rEvent
.maEvent
);
98 SlideShowView::SlideShowView( ShowWindow
& rOutputWindow
,
100 AnimationMode eAnimationMode
,
101 SlideshowImpl
* pSlideShow
,
103 : mpCanvas( ::cppcanvas::VCLFactory::createSpriteCanvas( rOutputWindow
) ),
104 mxWindow( VCLUnoHelper::GetInterface( &rOutputWindow
), uno::UNO_SET_THROW
),
105 mxWindowPeer( mxWindow
, uno::UNO_QUERY_THROW
),
106 mpSlideShow( pSlideShow
),
107 mrOutputWindow( rOutputWindow
),
109 mbIsMouseMotionListener( false ),
110 meAnimationMode( eAnimationMode
),
111 mbFirstPaint( true ),
112 mbMousePressedEaten( false )
114 mxWindow
->addWindowListener( this );
115 mxWindow
->addMouseListener( this );
117 mxPointer
= awt::Pointer::create( ::comphelper::getProcessComponentContext() );
121 // #i48939# only switch on kind of hacky scroll optimization, when
122 // running fullscreen. this minimizes the probability that other
123 // windows partially cover the show.
128 Reference
< beans::XPropertySet
> xCanvasProps( getCanvas(),
129 uno::UNO_QUERY_THROW
);
130 xCanvasProps
->setPropertyValue(u
"UnsafeScrolling"_ustr
,
133 catch( uno::Exception
& )
138 mTranslationOffset
.Width
= 0;
139 mTranslationOffset
.Height
= 0;
142 // Dispose all internal references
143 void SlideShowView::disposing(std::unique_lock
<std::mutex
>& rGuard
)
145 mpSlideShow
= nullptr;
147 // deregister listeners
150 mxWindow
->removeWindowListener( this );
151 mxWindow
->removeMouseListener( this );
153 if( mbIsMouseMotionListener
)
154 mxWindow
->removeMouseMotionListener( this );
160 // clear all listener containers
161 disposingImpl(rGuard
);
164 // Disposing our broadcaster
165 void SAL_CALL
SlideShowView::disposing( const lang::EventObject
& )
167 std::unique_lock
aGuard( m_aMutex
);
169 disposingImpl(aGuard
);
172 // Disposing our broadcaster
173 void SlideShowView::disposingImpl(std::unique_lock
<std::mutex
>& rGuard
)
175 // notify all listeners that _we_ are going down (send a disposing()),
176 // then delete listener containers:
177 lang::EventObject
const evt( static_cast<OWeakObject
*>(this) );
178 if (!maViewListeners
.empty())
180 auto tmp
= std::move(maViewListeners
);
182 for( const auto& rxListener
: tmp
)
184 Reference
< util::XModifyListener
> xListener( rxListener
);
186 xListener
->disposing( evt
);
190 if (maPaintListeners
.getLength(rGuard
))
192 maPaintListeners
.disposeAndClear( rGuard
, evt
);
195 if (maMouseListeners
.getLength(rGuard
))
197 maMouseListeners
.disposeAndClear( rGuard
, evt
);
200 if (maMouseMotionListeners
.getLength(rGuard
))
202 maMouseMotionListeners
.disposeAndClear( rGuard
, evt
);
207 void SlideShowView::paint( const awt::PaintEvent
& e
)
209 std::unique_lock
aGuard( m_aMutex
);
213 mbFirstPaint
= false;
214 SlideshowImpl
* pSlideShow
= mpSlideShow
;
217 pSlideShow
->onFirstPaint();
221 // Change event source, to enable listeners to match event
223 awt::PaintEvent
aEvent( e
);
224 aEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
225 maPaintListeners
.notifyEach( aGuard
, &css::awt::XPaintListener::windowPaint
, aEvent
);
226 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
230 // XSlideShowView methods
231 Reference
< rendering::XSpriteCanvas
> SAL_CALL
SlideShowView::getCanvas( )
233 std::unique_lock
aGuard( m_aMutex
);
235 return mpCanvas
? mpCanvas
->getUNOSpriteCanvas() : Reference
< rendering::XSpriteCanvas
>();
238 void SAL_CALL
SlideShowView::clear()
240 // paint background in black
241 std::unique_lock
aGuard( m_aMutex
);
242 SolarMutexGuard aSolarGuard
;
244 // fill the bounds rectangle in black
246 const Size
aWindowSize( mrOutputWindow
.GetSizePixel() );
248 ::basegfx::B2DPolygon
aPoly( ::basegfx::utils::createPolygonFromRect(
249 ::basegfx::B2DRectangle(0.0,0.0,
251 aWindowSize
.Height() ) ) );
252 ::cppcanvas::PolyPolygonSharedPtr
pPolyPoly(
253 ::cppcanvas::BaseGfxFactory::createPolyPolygon( mpCanvas
, aPoly
) );
257 pPolyPoly
->setRGBAFillColor( 0x000000FFU
);
262 geometry::IntegerSize2D SAL_CALL
SlideShowView::getTranslationOffset( )
264 return mTranslationOffset
;
267 geometry::AffineMatrix2D SAL_CALL
SlideShowView::getTransformation( )
269 std::unique_lock
aGuard( m_aMutex
);
270 SolarMutexGuard aSolarGuard
;
272 const Size
aTmpSize( mrOutputWindow
.GetSizePixel() );
274 if (aTmpSize
.IsEmpty())
276 return geometry::AffineMatrix2D (1,0,0,0,1,0);
279 const Size
aWindowSize( mrOutputWindow
.GetSizePixel() );
280 Size
aOutputSize( aWindowSize
);
282 if( meAnimationMode
!= ANIMATIONMODE_SHOW
)
284 aOutputSize
.setWidth( static_cast<::tools::Long
>( aOutputSize
.Width() / 1.03 ) );
285 aOutputSize
.setHeight( static_cast<::tools::Long
>( aOutputSize
.Height() / 1.03 ) );
288 SdPage
* pP
= mpDoc
->GetSdPage( 0, PageKind::Standard
);
289 Size
aPageSize( pP
->GetSize() );
291 const double page_ratio
= static_cast<double>(aPageSize
.Width()) / static_cast<double>(aPageSize
.Height());
292 const double output_ratio
= static_cast<double>(aOutputSize
.Width()) / static_cast<double>(aOutputSize
.Height());
294 if( page_ratio
> output_ratio
)
296 aOutputSize
.setHeight( ( aOutputSize
.Width() * aPageSize
.Height() ) / aPageSize
.Width() );
298 else if( page_ratio
< output_ratio
)
300 aOutputSize
.setWidth( ( aOutputSize
.Height() * aPageSize
.Width() ) / aPageSize
.Height() );
303 Point
aOutputOffset( ( aWindowSize
.Width() - aOutputSize
.Width() ) >> 1,
304 ( aWindowSize
.Height() - aOutputSize
.Height() ) >> 1 );
306 // Reduce available width by one, as the slides might actually
307 // render one pixel wider and higher as aPageSize below specifies
308 // (when shapes of page size have visible border lines)
309 aOutputSize
.AdjustWidth( -1 );
310 aOutputSize
.AdjustHeight( -1 );
312 // Record mTranslationOffset
313 mTranslationOffset
.Height
= aOutputOffset
.Y();
314 mTranslationOffset
.Width
= aOutputOffset
.X();
316 // scale presentation into available window rect (minus 10%); center in the window
317 const basegfx::B2DHomMatrix
aMatrix(basegfx::utils::createScaleTranslateB2DHomMatrix(
318 aOutputSize
.Width(), aOutputSize
.Height(), aOutputOffset
.X(), aOutputOffset
.Y()));
320 geometry::AffineMatrix2D aRes
;
322 return ::basegfx::unotools::affineMatrixFromHomMatrix( aRes
, aMatrix
);
325 void SAL_CALL
SlideShowView::addTransformationChangedListener( const Reference
< util::XModifyListener
>& xListener
)
327 std::unique_lock
aGuard( m_aMutex
);
331 WeakReference
< util::XModifyListener
> xWeak( xListener
);
332 if( std::find( maViewListeners
.begin(), maViewListeners
.end(), xWeak
) == maViewListeners
.end() )
333 maViewListeners
.push_back( xWeak
);
336 void SAL_CALL
SlideShowView::removeTransformationChangedListener( const Reference
< util::XModifyListener
>& xListener
)
338 std::unique_lock
aGuard( m_aMutex
);
342 WeakReference
< util::XModifyListener
> xWeak( xListener
);
343 auto aIter( std::find( maViewListeners
.begin(), maViewListeners
.end(), xWeak
) );
344 if( aIter
!= maViewListeners
.end() )
345 maViewListeners
.erase( aIter
);
348 void SAL_CALL
SlideShowView::addPaintListener( const Reference
< awt::XPaintListener
>& xListener
)
350 std::unique_lock
aGuard( m_aMutex
);
353 maPaintListeners
.addInterface( aGuard
, xListener
);
356 void SAL_CALL
SlideShowView::removePaintListener( const Reference
< awt::XPaintListener
>& xListener
)
358 std::unique_lock
aGuard( m_aMutex
);
361 maPaintListeners
.removeInterface( aGuard
, xListener
);
364 void SAL_CALL
SlideShowView::addMouseListener( const Reference
< awt::XMouseListener
>& xListener
)
366 std::unique_lock
aGuard( m_aMutex
);
369 maMouseListeners
.addInterface( aGuard
, xListener
);
372 void SAL_CALL
SlideShowView::removeMouseListener( const Reference
< awt::XMouseListener
>& xListener
)
374 std::unique_lock
aGuard( m_aMutex
);
377 maMouseListeners
.removeInterface( aGuard
, xListener
);
380 void SAL_CALL
SlideShowView::addMouseMotionListener( const Reference
< awt::XMouseMotionListener
>& xListener
)
382 std::unique_lock
aGuard( m_aMutex
);
387 if( !mbIsMouseMotionListener
&& mxWindow
.is() )
389 // delay motion event registration, until we really
391 mbIsMouseMotionListener
= true;
392 mxWindow
->addMouseMotionListener( this );
395 maMouseMotionListeners
.addInterface( aGuard
, xListener
);
398 void SAL_CALL
SlideShowView::removeMouseMotionListener( const Reference
< awt::XMouseMotionListener
>& xListener
)
400 std::unique_lock
aGuard( m_aMutex
);
403 maMouseMotionListeners
.removeInterface( aGuard
, xListener
);
405 // TODO(P1): Might be nice to deregister for mouse motion
406 // events, when the last listener is gone.
409 void SAL_CALL
SlideShowView::setMouseCursor( sal_Int16 nPointerShape
)
411 std::unique_lock
aGuard( m_aMutex
);
415 mxPointer
->setType( nPointerShape
);
417 if( mxWindowPeer
.is() )
418 mxWindowPeer
->setPointer( mxPointer
);
421 awt::Rectangle SAL_CALL
SlideShowView::getCanvasArea( )
423 awt::Rectangle aRectangle
;
426 return mxWindow
->getPosSize();
428 aRectangle
.X
= aRectangle
.Y
= aRectangle
.Width
= aRectangle
.Height
= 0;
433 void SlideShowView::updateimpl( std::unique_lock
<std::mutex
>& rGuard
, SlideshowImpl
* pSlideShow
)
438 ::rtl::Reference
< SlideshowImpl
> xKeepAlive( pSlideShow
);
442 mbFirstPaint
= false;
443 SlideshowImpl
* pTmpSlideShow
= mpSlideShow
;
446 pTmpSlideShow
->onFirstPaint();
450 pSlideShow
->startUpdateTimer();
453 // XWindowListener methods
454 void SAL_CALL
SlideShowView::windowResized( const awt::WindowEvent
& e
)
456 std::unique_lock
aGuard( m_aMutex
);
461 if (!maViewListeners
.empty())
463 // Change event source, to enable listeners to match event
465 awt::WindowEvent
aEvent( e
);
466 aEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
467 auto aIter( maViewListeners
.begin() );
468 while( aIter
!= maViewListeners
.end() )
470 Reference
< util::XModifyListener
> xListener( *aIter
);
474 xListener
->modified( aEvent
);
480 aIter
= maViewListeners
.erase( aIter
);
485 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
488 void SAL_CALL
SlideShowView::windowMoved( const awt::WindowEvent
& )
493 void SAL_CALL
SlideShowView::windowShown( const lang::EventObject
& )
498 void SAL_CALL
SlideShowView::windowHidden( const lang::EventObject
& )
503 // XMouseListener implementation
504 void SAL_CALL
SlideShowView::mousePressed( const awt::MouseEvent
& e
)
506 std::unique_lock
aGuard( m_aMutex
);
510 if( mpSlideShow
&& mpSlideShow
->isInputFreezed() )
512 mbMousePressedEaten
= true;
516 mbMousePressedEaten
= false;
518 // Change event source, to enable listeners to match event
520 WrappedMouseEvent aEvent
;
521 aEvent
.meType
= WrappedMouseEvent::PRESSED
;
523 aEvent
.maEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
525 maMouseListeners
.notify( aGuard
, aEvent
);
526 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
530 void SAL_CALL
SlideShowView::mouseReleased( const awt::MouseEvent
& e
)
532 std::unique_lock
aGuard( m_aMutex
);
536 if( mbMousePressedEaten
)
538 // if mouse button down was ignored, also ignore mouse button up
539 mbMousePressedEaten
= false;
541 else if( mpSlideShow
&& !mpSlideShow
->isInputFreezed() )
543 // Change event source, to enable listeners to match event
545 WrappedMouseEvent aEvent
;
546 aEvent
.meType
= WrappedMouseEvent::RELEASED
;
548 aEvent
.maEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
550 maMouseListeners
.notify( aGuard
, aEvent
);
551 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
555 void SlideShowView::ignoreNextMouseReleased()
557 std::unique_lock
aGuard( m_aMutex
);
558 mbMousePressedEaten
= true;
561 void SAL_CALL
SlideShowView::mouseEntered( const awt::MouseEvent
& e
)
563 std::unique_lock
aGuard( m_aMutex
);
567 // Change event source, to enable listeners to match event
569 WrappedMouseEvent aEvent
;
570 aEvent
.meType
= WrappedMouseEvent::ENTERED
;
572 aEvent
.maEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
574 maMouseListeners
.notify( aGuard
, aEvent
);
575 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
578 void SAL_CALL
SlideShowView::mouseExited( const awt::MouseEvent
& e
)
580 std::unique_lock
aGuard( m_aMutex
);
584 // Change event source, to enable listeners to match event
586 WrappedMouseEvent aEvent
;
587 aEvent
.meType
= WrappedMouseEvent::EXITED
;
589 aEvent
.maEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
591 maMouseListeners
.notify( aGuard
, aEvent
);
592 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
595 // XMouseMotionListener implementation
596 void SAL_CALL
SlideShowView::mouseDragged( const awt::MouseEvent
& e
)
598 std::unique_lock
aGuard( m_aMutex
);
602 // Change event source, to enable listeners to match event
604 WrappedMouseMotionEvent aEvent
;
605 aEvent
.meType
= WrappedMouseMotionEvent::DRAGGED
;
607 aEvent
.maEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
609 maMouseMotionListeners
.notify( aGuard
, aEvent
);
610 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
613 void SAL_CALL
SlideShowView::mouseMoved( const awt::MouseEvent
& e
)
615 std::unique_lock
aGuard( m_aMutex
);
619 // Change event source, to enable listeners to match event
621 WrappedMouseMotionEvent aEvent
;
622 aEvent
.meType
= WrappedMouseMotionEvent::MOVED
;
624 aEvent
.maEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
626 maMouseMotionListeners
.notify( aGuard
, aEvent
);
627 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
632 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */