/* -*- 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 "slideshowviewimpl.hxx" #include "slideshowimpl.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::WeakReference; using ::com::sun::star::uno::Exception; using namespace ::com::sun::star; namespace sd { void SlideShowViewMouseListeners::notify( std::unique_lock& rGuard, const WrappedMouseEvent& rEvent ) { forEach(rGuard, [&rEvent] (const Reference& rListener) { switch( rEvent.meType ) { case WrappedMouseEvent::PRESSED: rListener->mousePressed( rEvent.maEvent ); break; case WrappedMouseEvent::RELEASED: rListener->mouseReleased( rEvent.maEvent ); break; case WrappedMouseEvent::ENTERED: rListener->mouseEntered( rEvent.maEvent ); break; case WrappedMouseEvent::EXITED: rListener->mouseExited( rEvent.maEvent ); break; } }); } void SlideShowViewMouseMotionListeners::notify( std::unique_lock& rGuard,const WrappedMouseMotionEvent& rEvent ) { forEach(rGuard, [&rEvent] (const Reference< awt::XMouseMotionListener >& rListener) { switch( rEvent.meType ) { case WrappedMouseMotionEvent::DRAGGED: rListener->mouseDragged( rEvent.maEvent ); break; case WrappedMouseMotionEvent::MOVED: rListener->mouseMoved( rEvent.maEvent ); break; } }); } // SlideShowView SlideShowView::SlideShowView( ShowWindow& rOutputWindow, SdDrawDocument* pDoc, AnimationMode eAnimationMode, SlideshowImpl* pSlideShow, bool bFullScreen ) : mpCanvas( ::cppcanvas::VCLFactory::createSpriteCanvas( rOutputWindow ) ), mxWindow( VCLUnoHelper::GetInterface( &rOutputWindow ), uno::UNO_SET_THROW ), mxWindowPeer( mxWindow, uno::UNO_QUERY_THROW ), mpSlideShow( pSlideShow ), mrOutputWindow( rOutputWindow ), mpDoc( pDoc ), mbIsMouseMotionListener( false ), meAnimationMode( eAnimationMode ), mbFirstPaint( true ), mbMousePressedEaten( false ) { mxWindow->addWindowListener( this ); mxWindow->addMouseListener( this ); mxPointer = awt::Pointer::create( ::comphelper::getProcessComponentContext() ); getTransformation(); // #i48939# only switch on kind of hacky scroll optimization, when // running fullscreen. this minimizes the probability that other // windows partially cover the show. if( bFullScreen ) { try { Reference< beans::XPropertySet > xCanvasProps( getCanvas(), uno::UNO_QUERY_THROW ); xCanvasProps->setPropertyValue(u"UnsafeScrolling"_ustr, uno::Any( true ) ); } catch( uno::Exception& ) { } } mTranslationOffset.Width = 0; mTranslationOffset.Height = 0; } // Dispose all internal references void SlideShowView::disposing(std::unique_lock& rGuard) { mpSlideShow = nullptr; // deregister listeners if( mxWindow.is() ) { mxWindow->removeWindowListener( this ); mxWindow->removeMouseListener( this ); if( mbIsMouseMotionListener ) mxWindow->removeMouseMotionListener( this ); } mpCanvas.reset(); mxWindow.clear(); // clear all listener containers disposingImpl(rGuard); } // Disposing our broadcaster void SAL_CALL SlideShowView::disposing( const lang::EventObject& ) { std::unique_lock aGuard( m_aMutex ); disposingImpl(aGuard); } // Disposing our broadcaster void SlideShowView::disposingImpl(std::unique_lock& rGuard) { // notify all listeners that _we_ are going down (send a disposing()), // then delete listener containers: lang::EventObject const evt( static_cast(this) ); if (!maViewListeners.empty()) { auto tmp = std::move(maViewListeners); rGuard.unlock(); for( const auto& rxListener : tmp ) { Reference< util::XModifyListener > xListener( rxListener ); if( xListener.is() ) xListener->disposing( evt ); } rGuard.lock(); } if (maPaintListeners.getLength(rGuard)) { maPaintListeners.disposeAndClear( rGuard, evt ); rGuard.lock(); } if (maMouseListeners.getLength(rGuard)) { maMouseListeners.disposeAndClear( rGuard, evt ); rGuard.lock(); } if (maMouseMotionListeners.getLength(rGuard)) { maMouseMotionListeners.disposeAndClear( rGuard, evt ); rGuard.lock(); } } void SlideShowView::paint( const awt::PaintEvent& e ) { std::unique_lock aGuard( m_aMutex ); if( mbFirstPaint ) { mbFirstPaint = false; SlideshowImpl* pSlideShow = mpSlideShow; aGuard.unlock(); if( pSlideShow ) pSlideShow->onFirstPaint(); } else { // Change event source, to enable listeners to match event // with view awt::PaintEvent aEvent( e ); aEvent.Source = static_cast< ::cppu::OWeakObject* >( this ); maPaintListeners.notifyEach( aGuard, &css::awt::XPaintListener::windowPaint, aEvent ); updateimpl( aGuard, mpSlideShow ); // warning: clears guard! } } // XSlideShowView methods Reference< rendering::XSpriteCanvas > SAL_CALL SlideShowView::getCanvas( ) { std::unique_lock aGuard( m_aMutex ); return mpCanvas ? mpCanvas->getUNOSpriteCanvas() : Reference< rendering::XSpriteCanvas >(); } void SAL_CALL SlideShowView::clear() { // paint background in black std::unique_lock aGuard( m_aMutex ); SolarMutexGuard aSolarGuard; // fill the bounds rectangle in black const Size aWindowSize( mrOutputWindow.GetSizePixel() ); ::basegfx::B2DPolygon aPoly( ::basegfx::utils::createPolygonFromRect( ::basegfx::B2DRectangle(0.0,0.0, aWindowSize.Width(), aWindowSize.Height() ) ) ); ::cppcanvas::PolyPolygonSharedPtr pPolyPoly( ::cppcanvas::BaseGfxFactory::createPolyPolygon( mpCanvas, aPoly ) ); if( pPolyPoly ) { pPolyPoly->setRGBAFillColor( 0x000000FFU ); pPolyPoly->draw(); } } geometry::IntegerSize2D SAL_CALL SlideShowView::getTranslationOffset( ) { return mTranslationOffset; } geometry::AffineMatrix2D SAL_CALL SlideShowView::getTransformation( ) { std::unique_lock aGuard( m_aMutex ); SolarMutexGuard aSolarGuard; const Size aTmpSize( mrOutputWindow.GetSizePixel() ); if (aTmpSize.IsEmpty()) { return geometry::AffineMatrix2D (1,0,0,0,1,0); } const Size aWindowSize( mrOutputWindow.GetSizePixel() ); Size aOutputSize( aWindowSize ); if( meAnimationMode != ANIMATIONMODE_SHOW ) { aOutputSize.setWidth( static_cast<::tools::Long>( aOutputSize.Width() / 1.03 ) ); aOutputSize.setHeight( static_cast<::tools::Long>( aOutputSize.Height() / 1.03 ) ); } SdPage* pP = mpDoc->GetSdPage( 0, PageKind::Standard ); Size aPageSize( pP->GetSize() ); const double page_ratio = static_cast(aPageSize.Width()) / static_cast(aPageSize.Height()); const double output_ratio = static_cast(aOutputSize.Width()) / static_cast(aOutputSize.Height()); if( page_ratio > output_ratio ) { aOutputSize.setHeight( ( aOutputSize.Width() * aPageSize.Height() ) / aPageSize.Width() ); } else if( page_ratio < output_ratio ) { aOutputSize.setWidth( ( aOutputSize.Height() * aPageSize.Width() ) / aPageSize.Height() ); } Point aOutputOffset( ( aWindowSize.Width() - aOutputSize.Width() ) >> 1, ( aWindowSize.Height() - aOutputSize.Height() ) >> 1 ); // Reduce available width by one, as the slides might actually // render one pixel wider and higher as aPageSize below specifies // (when shapes of page size have visible border lines) aOutputSize.AdjustWidth( -1 ); aOutputSize.AdjustHeight( -1 ); // Record mTranslationOffset mTranslationOffset.Height = aOutputOffset.Y(); mTranslationOffset.Width = aOutputOffset.X(); // scale presentation into available window rect (minus 10%); center in the window const basegfx::B2DHomMatrix aMatrix(basegfx::utils::createScaleTranslateB2DHomMatrix( aOutputSize.Width(), aOutputSize.Height(), aOutputOffset.X(), aOutputOffset.Y())); geometry::AffineMatrix2D aRes; return ::basegfx::unotools::affineMatrixFromHomMatrix( aRes, aMatrix ); } void SAL_CALL SlideShowView::addTransformationChangedListener( const Reference< util::XModifyListener >& xListener ) { std::unique_lock aGuard( m_aMutex ); if (m_bDisposed) return; WeakReference< util::XModifyListener > xWeak( xListener ); if( std::find( maViewListeners.begin(), maViewListeners.end(), xWeak ) == maViewListeners.end() ) maViewListeners.push_back( xWeak ); } void SAL_CALL SlideShowView::removeTransformationChangedListener( const Reference< util::XModifyListener >& xListener ) { std::unique_lock aGuard( m_aMutex ); if (m_bDisposed) return; WeakReference< util::XModifyListener > xWeak( xListener ); auto aIter( std::find( maViewListeners.begin(), maViewListeners.end(), xWeak ) ); if( aIter != maViewListeners.end() ) maViewListeners.erase( aIter ); } void SAL_CALL SlideShowView::addPaintListener( const Reference< awt::XPaintListener >& xListener ) { std::unique_lock aGuard( m_aMutex ); if (!m_bDisposed) maPaintListeners.addInterface( aGuard, xListener ); } void SAL_CALL SlideShowView::removePaintListener( const Reference< awt::XPaintListener >& xListener ) { std::unique_lock aGuard( m_aMutex ); if (!m_bDisposed) maPaintListeners.removeInterface( aGuard, xListener ); } void SAL_CALL SlideShowView::addMouseListener( const Reference< awt::XMouseListener >& xListener ) { std::unique_lock aGuard( m_aMutex ); if (!m_bDisposed) maMouseListeners.addInterface( aGuard, xListener ); } void SAL_CALL SlideShowView::removeMouseListener( const Reference< awt::XMouseListener >& xListener ) { std::unique_lock aGuard( m_aMutex ); if (!m_bDisposed) maMouseListeners.removeInterface( aGuard, xListener ); } void SAL_CALL SlideShowView::addMouseMotionListener( const Reference< awt::XMouseMotionListener >& xListener ) { std::unique_lock aGuard( m_aMutex ); if (m_bDisposed) return; if( !mbIsMouseMotionListener && mxWindow.is() ) { // delay motion event registration, until we really // need it mbIsMouseMotionListener = true; mxWindow->addMouseMotionListener( this ); } maMouseMotionListeners.addInterface( aGuard, xListener ); } void SAL_CALL SlideShowView::removeMouseMotionListener( const Reference< awt::XMouseMotionListener >& xListener ) { std::unique_lock aGuard( m_aMutex ); if (!m_bDisposed) maMouseMotionListeners.removeInterface( aGuard, xListener ); // TODO(P1): Might be nice to deregister for mouse motion // events, when the last listener is gone. } void SAL_CALL SlideShowView::setMouseCursor( sal_Int16 nPointerShape ) { std::unique_lock aGuard( m_aMutex ); // forward to window if( mxPointer.is() ) mxPointer->setType( nPointerShape ); if( mxWindowPeer.is() ) mxWindowPeer->setPointer( mxPointer ); } awt::Rectangle SAL_CALL SlideShowView::getCanvasArea( ) { awt::Rectangle aRectangle; if( mxWindow.is() ) return mxWindow->getPosSize(); aRectangle.X = aRectangle.Y = aRectangle.Width = aRectangle.Height = 0; return aRectangle; } void SlideShowView::updateimpl( std::unique_lock& rGuard, SlideshowImpl* pSlideShow ) { if( !pSlideShow ) return; ::rtl::Reference< SlideshowImpl > xKeepAlive( pSlideShow ); if( mbFirstPaint ) { mbFirstPaint = false; SlideshowImpl* pTmpSlideShow = mpSlideShow; rGuard.unlock(); if( pTmpSlideShow ) pTmpSlideShow->onFirstPaint(); } else rGuard.unlock(); pSlideShow->startUpdateTimer(); } // XWindowListener methods void SAL_CALL SlideShowView::windowResized( const awt::WindowEvent& e ) { std::unique_lock aGuard( m_aMutex ); if (m_bDisposed) return; if (!maViewListeners.empty()) { // Change event source, to enable listeners to match event // with view awt::WindowEvent aEvent( e ); aEvent.Source = static_cast< ::cppu::OWeakObject* >( this ); auto aIter( maViewListeners.begin() ); while( aIter != maViewListeners.end() ) { Reference< util::XModifyListener > xListener( *aIter ); if( xListener.is() ) { aGuard.unlock(); xListener->modified( aEvent ); aGuard.lock(); ++aIter; } else { aIter = maViewListeners.erase( aIter ); } } } updateimpl( aGuard, mpSlideShow ); // warning: clears guard! } void SAL_CALL SlideShowView::windowMoved( const awt::WindowEvent& ) { // ignored } void SAL_CALL SlideShowView::windowShown( const lang::EventObject& ) { // ignored } void SAL_CALL SlideShowView::windowHidden( const lang::EventObject& ) { // ignored } // XMouseListener implementation void SAL_CALL SlideShowView::mousePressed( const awt::MouseEvent& e ) { std::unique_lock aGuard( m_aMutex ); if (m_bDisposed) return; if( mpSlideShow && mpSlideShow->isInputFreezed() ) { mbMousePressedEaten = true; } else { mbMousePressedEaten = false; // Change event source, to enable listeners to match event // with view WrappedMouseEvent aEvent; aEvent.meType = WrappedMouseEvent::PRESSED; aEvent.maEvent = e; aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this ); maMouseListeners.notify( aGuard, aEvent ); updateimpl( aGuard, mpSlideShow ); // warning: clears guard! } } void SAL_CALL SlideShowView::mouseReleased( const awt::MouseEvent& e ) { std::unique_lock aGuard( m_aMutex ); if (m_bDisposed) return; if( mbMousePressedEaten ) { // if mouse button down was ignored, also ignore mouse button up mbMousePressedEaten = false; } else if( mpSlideShow && !mpSlideShow->isInputFreezed() ) { // Change event source, to enable listeners to match event // with view WrappedMouseEvent aEvent; aEvent.meType = WrappedMouseEvent::RELEASED; aEvent.maEvent = e; aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this ); maMouseListeners.notify( aGuard, aEvent ); updateimpl( aGuard, mpSlideShow ); // warning: clears guard! } } void SlideShowView::ignoreNextMouseReleased() { std::unique_lock aGuard( m_aMutex ); mbMousePressedEaten = true; } void SAL_CALL SlideShowView::mouseEntered( const awt::MouseEvent& e ) { std::unique_lock aGuard( m_aMutex ); if (m_bDisposed) return; // Change event source, to enable listeners to match event // with view WrappedMouseEvent aEvent; aEvent.meType = WrappedMouseEvent::ENTERED; aEvent.maEvent = e; aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this ); maMouseListeners.notify( aGuard, aEvent ); updateimpl( aGuard, mpSlideShow ); // warning: clears guard! } void SAL_CALL SlideShowView::mouseExited( const awt::MouseEvent& e ) { std::unique_lock aGuard( m_aMutex ); if (m_bDisposed) return; // Change event source, to enable listeners to match event // with view WrappedMouseEvent aEvent; aEvent.meType = WrappedMouseEvent::EXITED; aEvent.maEvent = e; aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this ); maMouseListeners.notify( aGuard, aEvent ); updateimpl( aGuard, mpSlideShow ); // warning: clears guard! } // XMouseMotionListener implementation void SAL_CALL SlideShowView::mouseDragged( const awt::MouseEvent& e ) { std::unique_lock aGuard( m_aMutex ); if (m_bDisposed) return; // Change event source, to enable listeners to match event // with view WrappedMouseMotionEvent aEvent; aEvent.meType = WrappedMouseMotionEvent::DRAGGED; aEvent.maEvent = e; aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this ); maMouseMotionListeners.notify( aGuard, aEvent ); updateimpl( aGuard, mpSlideShow ); // warning: clears guard! } void SAL_CALL SlideShowView::mouseMoved( const awt::MouseEvent& e ) { std::unique_lock aGuard( m_aMutex ); if (m_bDisposed) return; // Change event source, to enable listeners to match event // with view WrappedMouseMotionEvent aEvent; aEvent.meType = WrappedMouseMotionEvent::MOVED; aEvent.maEvent = e; aEvent.maEvent.Source = static_cast< ::cppu::OWeakObject* >( this ); maMouseMotionListeners.notify( aGuard, aEvent ); updateimpl( aGuard, mpSlideShow ); // warning: clears guard! } } // namespace ::sd /* vim:set shiftwidth=4 softtabstop=4 expandtab: */