1 
2 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of the LibreOffice project.
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * This file incorporates work covered by the following license notice:
11  *
12  *   Licensed to the Apache Software Foundation (ASF) under one or more
13  *   contributor license agreements. See the NOTICE file distributed
14  *   with this work for additional information regarding copyright
15  *   ownership. The ASF licenses this file to you under the Apache
16  *   License, Version 2.0 (the "License"); you may not use this file
17  *   except in compliance with the License. You may obtain a copy of
18  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
19  */
20 
21 #include "PresenterSlideShowView.hxx"
22 #include "PresenterCanvasHelper.hxx"
23 #include "PresenterGeometryHelper.hxx"
24 #include "PresenterHelper.hxx"
25 #include "PresenterPaneContainer.hxx"
26 #include <com/sun/star/awt/InvalidateStyle.hpp>
27 #include <com/sun/star/awt/PosSize.hpp>
28 #include <com/sun/star/awt/Pointer.hpp>
29 #include <com/sun/star/awt/Toolkit.hpp>
30 #include <com/sun/star/awt/WindowAttribute.hpp>
31 #include <com/sun/star/awt/XWindow.hpp>
32 #include <com/sun/star/awt/XWindowPeer.hpp>
33 #include <com/sun/star/drawing/XPresenterHelper.hpp>
34 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
35 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
36 #include <com/sun/star/rendering/CompositeOperation.hpp>
37 #include <com/sun/star/rendering/TextDirection.hpp>
38 #include <com/sun/star/rendering/TexturingMode.hpp>
39 #include <osl/mutex.hxx>
40 
41 using namespace ::com::sun::star;
42 using namespace ::com::sun::star::uno;
43 using namespace ::com::sun::star::drawing::framework;
44 
45 namespace sdext::presenter {
46 
47 //===== PresenterSlideShowView ================================================
48 
PresenterSlideShowView(const css::uno::Reference<css::uno::XComponentContext> & rxContext,const css::uno::Reference<css::drawing::framework::XResourceId> & rxViewId,const css::uno::Reference<css::frame::XController> & rxController,const::rtl::Reference<PresenterController> & rpPresenterController)49 PresenterSlideShowView::PresenterSlideShowView (
50     const css::uno::Reference<css::uno::XComponentContext>& rxContext,
51     const css::uno::Reference<css::drawing::framework::XResourceId>& rxViewId,
52     const css::uno::Reference<css::frame::XController>& rxController,
53     const ::rtl::Reference<PresenterController>& rpPresenterController)
54     : PresenterSlideShowViewInterfaceBase(m_aMutex),
55       mxComponentContext(rxContext),
56       mpPresenterController(rpPresenterController),
57       mxViewId(rxViewId),
58       mxController(rxController),
59       mxSlideShowController(PresenterHelper::GetSlideShowController(rxController)),
60       mxSlideShow(),
61       mxCanvas(),
62       mxViewCanvas(),
63       mxPointer(),
64       mxWindow(),
65       mxViewWindow(),
66       mxTopPane(),
67       mxPresenterHelper(),
68       mxBackgroundPolygon1(),
69       mxBackgroundPolygon2(),
70       mbIsViewAdded(false),
71       mnPageAspectRatio(28.0/21.0),
72       maBroadcaster(m_aMutex),
73       mpBackground(),
74       mbIsForcedPaintPending(false),
75       mbIsPaintPending(true),
76       msClickToExitPresentationText(),
77       msClickToExitPresentationTitle(),
78       msTitleTemplate(),
79       mbIsEndSlideVisible(false),
80       mxCurrentSlide()
81 {
82     if (mpPresenterController)
83     {
84         mnPageAspectRatio = mpPresenterController->GetSlideAspectRatio();
85         mpBackground = mpPresenterController->GetViewBackground(mxViewId->getResourceURL());
86     }
87 }
88 
LateInit()89 void PresenterSlideShowView::LateInit()
90 {
91     mxSlideShow.set( mxSlideShowController->getSlideShow(), UNO_SET_THROW);
92     Reference<lang::XComponent> xSlideShowComponent (mxSlideShow, UNO_QUERY);
93     xSlideShowComponent->addEventListener(static_cast<awt::XWindowListener*>(this));
94 
95     Reference<lang::XMultiComponentFactory> xFactory (
96         mxComponentContext->getServiceManager(), UNO_SET_THROW);
97     mxPresenterHelper.set (xFactory->createInstanceWithContext(
98                    "com.sun.star.comp.Draw.PresenterHelper",
99                    mxComponentContext),
100                UNO_QUERY_THROW);
101 
102     // Use view id and controller to retrieve window and canvas from
103     // configuration controller.
104     Reference<XControllerManager> xCM (mxController, UNO_QUERY_THROW);
105     Reference<XConfigurationController> xCC (xCM->getConfigurationController());
106 
107     if (xCC.is())
108     {
109         mxTopPane.set(xCC->getResource(mxViewId->getAnchor()->getAnchor()), UNO_QUERY);
110 
111         Reference<XPane> xPane (xCC->getResource(mxViewId->getAnchor()), UNO_QUERY_THROW);
112 
113         mxWindow = xPane->getWindow();
114         mxCanvas = xPane->getCanvas();
115 
116         if (mxWindow.is())
117         {
118             mxWindow->addPaintListener(this);
119             mxWindow->addWindowListener(this);
120         }
121 
122         // The window does not have to paint a background.  We do
123         // that ourself.
124         Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
125         if (xPeer.is())
126             xPeer->setBackground(util::Color(0xff000000));
127     }
128 
129     // Create a window for the actual slide show view.  It is places
130     // centered and with maximal size inside the pane.
131     mxViewWindow = CreateViewWindow(mxWindow);
132 
133     mxViewCanvas = CreateViewCanvas(mxViewWindow);
134 
135     if (mxViewWindow.is())
136     {
137         // Register listeners at window.
138         mxViewWindow->addPaintListener(this);
139         mxViewWindow->addMouseListener(this);
140         mxViewWindow->addMouseMotionListener(this);
141     }
142 
143     if (mxViewWindow.is())
144         Resize();
145 
146     if (mxWindow.is())
147         mxWindow->setVisible(true);
148 
149     // Add the new slide show view to the slide show.
150     if (mxSlideShow.is() && ! mbIsViewAdded)
151     {
152         impl_addAndConfigureView();
153         mbIsViewAdded = true;
154     }
155 
156     // Read text for one past last slide.
157     PresenterConfigurationAccess aConfiguration (
158         mxComponentContext,
159         PresenterConfigurationAccess::msPresenterScreenRootName,
160         PresenterConfigurationAccess::READ_ONLY);
161     aConfiguration.GetConfigurationNode(
162         "Presenter/Views/CurrentSlidePreview/"
163         "Strings/ClickToExitPresentationText/String")
164         >>= msClickToExitPresentationText;
165     aConfiguration.GetConfigurationNode(
166         "Presenter/Views/CurrentSlidePreview/"
167         "Strings/ClickToExitPresentationTitle/String")
168         >>= msClickToExitPresentationTitle;
169 }
170 
~PresenterSlideShowView()171 PresenterSlideShowView::~PresenterSlideShowView()
172 {
173 }
174 
disposing()175 void PresenterSlideShowView::disposing()
176 {
177     // Tell all listeners that we are disposed.
178     lang::EventObject aEvent;
179     aEvent.Source = static_cast<XWeak*>(this);
180 
181     ::cppu::OInterfaceContainerHelper* pIterator
182           = maBroadcaster.getContainer(cppu::UnoType<lang::XEventListener>::get());
183     if (pIterator != nullptr)
184         pIterator->disposeAndClear(aEvent);
185 
186     // Do this for
187     // XPaintListener, XModifyListener,XMouseListener,XMouseMotionListener,XWindowListener?
188 
189     if (mxWindow.is())
190     {
191         mxWindow->removePaintListener(this);
192         mxWindow->removeMouseListener(this);
193         mxWindow->removeMouseMotionListener(this);
194         mxWindow->removeWindowListener(this);
195         mxWindow = nullptr;
196     }
197     mxSlideShowController = nullptr;
198     mxSlideShow = nullptr;
199     if (mxViewCanvas.is())
200     {
201         Reference<XComponent> xComponent (mxViewCanvas, UNO_QUERY);
202         mxViewCanvas = nullptr;
203         if (xComponent.is())
204             xComponent->dispose();
205     }
206     if (mxViewWindow.is())
207     {
208         Reference<XComponent> xComponent = mxViewWindow;
209         mxViewWindow = nullptr;
210         if (xComponent.is())
211             xComponent->dispose();
212     }
213     if (mxPointer.is())
214     {
215         Reference<XComponent> xComponent (mxPointer, UNO_QUERY);
216         mxPointer = nullptr;
217         if (xComponent.is())
218             xComponent->dispose();
219     }
220     if (mxBackgroundPolygon1.is())
221     {
222         Reference<XComponent> xComponent (mxBackgroundPolygon1, UNO_QUERY);
223         mxBackgroundPolygon1 = nullptr;
224         if (xComponent.is())
225             xComponent->dispose();
226     }
227     if (mxBackgroundPolygon2.is())
228     {
229         Reference<XComponent> xComponent (mxBackgroundPolygon2, UNO_QUERY);
230         mxBackgroundPolygon2 = nullptr;
231         if (xComponent.is())
232             xComponent->dispose();
233     }
234 
235     mxComponentContext = nullptr;
236     mpPresenterController = nullptr;
237     mxViewId = nullptr;
238     mxController = nullptr;
239     mxCanvas = nullptr;
240     mpBackground.reset();
241     msClickToExitPresentationText.clear();
242     msClickToExitPresentationTitle.clear();
243     msTitleTemplate.clear();
244     mxCurrentSlide = nullptr;
245 }
246 
247 //----- XDrawView -------------------------------------------------------------
248 
setCurrentPage(const css::uno::Reference<css::drawing::XDrawPage> & rxSlide)249 void SAL_CALL PresenterSlideShowView::setCurrentPage (
250     const css::uno::Reference<css::drawing::XDrawPage>& rxSlide)
251 {
252     mxCurrentSlide = rxSlide;
253     if (mpPresenterController
254         && mxSlideShowController.is()
255         && ! mpPresenterController->GetCurrentSlide().is()
256         && ! mxSlideShowController->isPaused())
257     {
258         mbIsEndSlideVisible = true;
259         Reference<awt::XWindowPeer> xPeer (mxViewWindow, UNO_QUERY);
260         if (xPeer.is())
261             xPeer->invalidate(awt::InvalidateStyle::NOTRANSPARENT);
262 
263         // For the end slide we use a special title, without the (n of m)
264         // part.  Save the title template for the case that the user goes
265         // backwards.
266         PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
267             mpPresenterController->GetPaneContainer()->FindViewURL(mxViewId->getResourceURL()));
268         if (pDescriptor)
269         {
270             msTitleTemplate = pDescriptor->msTitleTemplate;
271             pDescriptor->msTitleTemplate = msClickToExitPresentationTitle;
272             mpPresenterController->UpdatePaneTitles();
273         }
274     }
275     else if (mbIsEndSlideVisible)
276     {
277         mbIsEndSlideVisible = false;
278 
279         // Restore the title template.
280         PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
281             mpPresenterController->GetPaneContainer()->FindViewURL(mxViewId->getResourceURL()));
282         if (pDescriptor)
283         {
284             pDescriptor->msTitleTemplate = msTitleTemplate;
285             pDescriptor->msTitle.clear();
286             mpPresenterController->UpdatePaneTitles();
287         }
288     }
289 }
290 
getCurrentPage()291 css::uno::Reference<css::drawing::XDrawPage> SAL_CALL PresenterSlideShowView::getCurrentPage()
292 {
293     return mxCurrentSlide;
294 }
295 
296 //----- CachablePresenterView -------------------------------------------------
297 
ReleaseView()298 void PresenterSlideShowView::ReleaseView()
299 {
300     if (mxSlideShow.is() && mbIsViewAdded)
301     {
302         mxSlideShow->removeView(this);
303         mbIsViewAdded = false;
304     }
305 }
306 
307 //----- XSlideShowView --------------------------------------------------------
308 
getCanvas()309 Reference<rendering::XSpriteCanvas> SAL_CALL PresenterSlideShowView::getCanvas()
310 {
311     ThrowIfDisposed();
312 
313     return Reference<rendering::XSpriteCanvas>(mxViewCanvas, UNO_QUERY);
314 }
315 
clear()316 void SAL_CALL PresenterSlideShowView::clear()
317 {
318     ThrowIfDisposed();
319     mbIsForcedPaintPending = false;
320     mbIsPaintPending = false;
321 
322     if (!(mxViewCanvas.is() && mxViewWindow.is()))
323         return;
324 
325     // Create a polygon for the window outline.
326     awt::Rectangle aViewWindowBox (mxViewWindow->getPosSize());
327     Reference<rendering::XPolyPolygon2D> xPolygon (PresenterGeometryHelper::CreatePolygon(
328         awt::Rectangle(0,0, aViewWindowBox.Width,aViewWindowBox.Height),
329         mxViewCanvas->getDevice()));
330 
331     rendering::ViewState aViewState (
332         geometry::AffineMatrix2D(1,0,0, 0,1,0),
333         nullptr);
334     double const aColor[4] = {0,0,0,0};
335     rendering::RenderState aRenderState(
336         geometry::AffineMatrix2D(1,0,0, 0,1,0),
337         nullptr,
338         Sequence<double>(aColor,4),
339         rendering::CompositeOperation::SOURCE);
340     mxViewCanvas->fillPolyPolygon(xPolygon, aViewState, aRenderState);
341 }
342 
getTransformation()343 geometry::AffineMatrix2D SAL_CALL PresenterSlideShowView::getTransformation()
344 {
345     ThrowIfDisposed();
346 
347     if (mxViewWindow.is())
348     {
349         // When the mbIsInModifyNotification is set then a slightly modified
350         // version of the transformation is returned in order to get past
351         // optimizations the avoid updates when the transformation is
352         // unchanged (when the window size changes then due to the constant
353         // aspect ratio the size of the preview may remain the same while
354         // the position changes.  The position, however, is represented by
355         // the position of the view window.  This transformation is given
356         // relative to the view window and therefore does not contain the
357         // position.)
358         const awt::Rectangle aWindowBox = mxViewWindow->getPosSize();
359         return geometry::AffineMatrix2D(
360             aWindowBox.Width-1, 0, 0,
361             0, aWindowBox.Height-1, 0);
362     }
363     else
364     {
365         return geometry::AffineMatrix2D(1,0,0, 0,1,0);
366     }
367 }
368 
getTranslationOffset()369 geometry::IntegerSize2D SAL_CALL PresenterSlideShowView::getTranslationOffset()
370 {
371     ThrowIfDisposed();
372     return geometry::IntegerSize2D(0,0);
373 }
374 
addTransformationChangedListener(const Reference<util::XModifyListener> & rxListener)375 void SAL_CALL PresenterSlideShowView::addTransformationChangedListener(
376     const Reference<util::XModifyListener>& rxListener)
377 {
378     ThrowIfDisposed();
379     maBroadcaster.addListener(
380         cppu::UnoType<util::XModifyListener>::get(),
381         rxListener);
382 }
383 
removeTransformationChangedListener(const Reference<util::XModifyListener> & rxListener)384 void SAL_CALL PresenterSlideShowView::removeTransformationChangedListener(
385     const Reference<util::XModifyListener>& rxListener)
386 {
387     ThrowIfDisposed();
388     maBroadcaster.removeListener(
389         cppu::UnoType<util::XModifyListener>::get(),
390         rxListener);
391 }
392 
addPaintListener(const Reference<awt::XPaintListener> & rxListener)393 void SAL_CALL PresenterSlideShowView::addPaintListener(
394     const Reference<awt::XPaintListener>& rxListener)
395 {
396     ThrowIfDisposed();
397     maBroadcaster.addListener(
398         cppu::UnoType<awt::XPaintListener>::get(),
399         rxListener);
400 }
401 
removePaintListener(const Reference<awt::XPaintListener> & rxListener)402 void SAL_CALL PresenterSlideShowView::removePaintListener(
403     const Reference<awt::XPaintListener>& rxListener)
404 {
405     ThrowIfDisposed();
406     maBroadcaster.removeListener(
407         cppu::UnoType<awt::XPaintListener>::get(),
408         rxListener);
409 }
410 
addMouseListener(const Reference<awt::XMouseListener> & rxListener)411 void SAL_CALL PresenterSlideShowView::addMouseListener(
412     const Reference<awt::XMouseListener>& rxListener)
413 {
414     ThrowIfDisposed();
415     maBroadcaster.addListener(
416         cppu::UnoType<awt::XMouseListener>::get(),
417         rxListener);
418 }
419 
removeMouseListener(const Reference<awt::XMouseListener> & rxListener)420 void SAL_CALL PresenterSlideShowView::removeMouseListener(
421     const Reference<awt::XMouseListener>& rxListener)
422 {
423     ThrowIfDisposed();
424     maBroadcaster.removeListener(
425         cppu::UnoType<awt::XMouseListener>::get(),
426         rxListener);
427 }
428 
addMouseMotionListener(const Reference<awt::XMouseMotionListener> & rxListener)429 void SAL_CALL PresenterSlideShowView::addMouseMotionListener(
430     const Reference<awt::XMouseMotionListener>& rxListener)
431 {
432     ThrowIfDisposed();
433     maBroadcaster.addListener(
434         cppu::UnoType<awt::XMouseMotionListener>::get(),
435         rxListener);
436 }
437 
removeMouseMotionListener(const Reference<awt::XMouseMotionListener> & rxListener)438 void SAL_CALL PresenterSlideShowView::removeMouseMotionListener(
439     const Reference<awt::XMouseMotionListener>& rxListener)
440 {
441     ThrowIfDisposed();
442     maBroadcaster.removeListener(
443         cppu::UnoType<awt::XMouseMotionListener>::get(),
444         rxListener);
445 }
446 
setMouseCursor(::sal_Int16 nPointerShape)447 void SAL_CALL PresenterSlideShowView::setMouseCursor(::sal_Int16 nPointerShape)
448 {
449     ThrowIfDisposed();
450 
451     // Create a pointer when it does not yet exist.
452     if ( ! mxPointer.is())
453     {
454         mxPointer = awt::Pointer::create(mxComponentContext);
455     }
456 
457     // Set the pointer to the given shape and the window(peer) to the
458     // pointer.
459     Reference<awt::XWindowPeer> xPeer (mxViewWindow, UNO_QUERY);
460     if (mxPointer.is() && xPeer.is())
461     {
462         mxPointer->setType(nPointerShape);
463         xPeer->setPointer(mxPointer);
464     }
465 }
466 
getCanvasArea()467 awt::Rectangle SAL_CALL PresenterSlideShowView::getCanvasArea(  )
468 {
469     if( mxViewWindow.is() && mxTopPane.is() )
470         return mxPresenterHelper->getWindowExtentsRelative( mxViewWindow, mxTopPane->getWindow() );
471 
472     awt::Rectangle aRectangle;
473 
474     aRectangle.X = aRectangle.Y = aRectangle.Width = aRectangle.Height = 0;
475 
476     return aRectangle;
477 }
478 
479 //----- lang::XEventListener --------------------------------------------------
480 
disposing(const lang::EventObject & rEvent)481 void SAL_CALL PresenterSlideShowView::disposing (const lang::EventObject& rEvent)
482 {
483     if (rEvent.Source == mxViewWindow)
484         mxViewWindow = nullptr;
485     else if (rEvent.Source == mxSlideShow)
486         mxSlideShow = nullptr;
487 }
488 
489 //----- XPaintListener --------------------------------------------------------
490 
windowPaint(const awt::PaintEvent & rEvent)491 void SAL_CALL PresenterSlideShowView::windowPaint (const awt::PaintEvent& rEvent)
492 {
493     // Deactivated views must not be painted.
494     if ( ! mbIsPresenterViewActive)
495         return;
496 
497     awt::Rectangle aViewWindowBox (mxViewWindow->getPosSize());
498     if (aViewWindowBox.Width <= 0 || aViewWindowBox.Height <= 0)
499         return;
500 
501     if (rEvent.Source == mxWindow)
502         PaintOuterWindow(rEvent.UpdateRect);
503     else if (mbIsEndSlideVisible)
504         PaintEndSlide(rEvent.UpdateRect);
505     else
506         PaintInnerWindow(rEvent);
507 }
508 
509 //----- XMouseListener --------------------------------------------------------
510 
mousePressed(const awt::MouseEvent & rEvent)511 void SAL_CALL PresenterSlideShowView::mousePressed (const awt::MouseEvent& rEvent)
512 {
513     awt::MouseEvent aEvent (rEvent);
514     aEvent.Source = static_cast<XWeak*>(this);
515     ::cppu::OInterfaceContainerHelper* pIterator
516         = maBroadcaster.getContainer(cppu::UnoType<awt::XMouseListener>::get());
517     if (pIterator != nullptr)
518     {
519         pIterator->notifyEach(&awt::XMouseListener::mousePressed, aEvent);
520     }
521 
522     // Only when the end slide is displayed we forward the mouse event to
523     // the PresenterController so that it switches to the next slide and
524     // ends the presentation.
525     if (mbIsEndSlideVisible)
526         if (mpPresenterController)
527             mpPresenterController->HandleMouseClick(rEvent);
528 }
529 
mouseReleased(const awt::MouseEvent & rEvent)530 void SAL_CALL PresenterSlideShowView::mouseReleased (const awt::MouseEvent& rEvent)
531 {
532     awt::MouseEvent aEvent (rEvent);
533     aEvent.Source = static_cast<XWeak*>(this);
534     ::cppu::OInterfaceContainerHelper* pIterator
535         = maBroadcaster.getContainer(cppu::UnoType<awt::XMouseListener>::get());
536     if (pIterator != nullptr)
537     {
538         pIterator->notifyEach(&awt::XMouseListener::mouseReleased, aEvent);
539     }
540 }
541 
mouseEntered(const awt::MouseEvent & rEvent)542 void SAL_CALL PresenterSlideShowView::mouseEntered (const awt::MouseEvent& rEvent)
543 {
544     awt::MouseEvent aEvent (rEvent);
545     aEvent.Source = static_cast<XWeak*>(this);
546     ::cppu::OInterfaceContainerHelper* pIterator
547         = maBroadcaster.getContainer(cppu::UnoType<awt::XMouseListener>::get());
548     if (pIterator != nullptr)
549     {
550         pIterator->notifyEach(&awt::XMouseListener::mouseEntered, aEvent);
551     }
552 }
553 
mouseExited(const awt::MouseEvent & rEvent)554 void SAL_CALL PresenterSlideShowView::mouseExited (const awt::MouseEvent& rEvent)
555 {
556     awt::MouseEvent aEvent (rEvent);
557     aEvent.Source = static_cast<XWeak*>(this);
558     ::cppu::OInterfaceContainerHelper* pIterator
559         = maBroadcaster.getContainer(cppu::UnoType<awt::XMouseListener>::get());
560     if (pIterator != nullptr)
561     {
562         pIterator->notifyEach(&awt::XMouseListener::mouseExited, aEvent);
563     }
564 }
565 
566 //----- XMouseMotionListener --------------------------------------------------
567 
mouseDragged(const awt::MouseEvent & rEvent)568 void SAL_CALL PresenterSlideShowView::mouseDragged (const awt::MouseEvent& rEvent)
569 {
570     awt::MouseEvent aEvent (rEvent);
571     aEvent.Source = static_cast<XWeak*>(this);
572     ::cppu::OInterfaceContainerHelper* pIterator
573         = maBroadcaster.getContainer(cppu::UnoType<awt::XMouseMotionListener>::get());
574     if (pIterator != nullptr)
575     {
576         pIterator->notifyEach(&awt::XMouseMotionListener::mouseDragged, aEvent);
577     }
578 }
579 
mouseMoved(const awt::MouseEvent & rEvent)580 void SAL_CALL PresenterSlideShowView::mouseMoved (const awt::MouseEvent& rEvent)
581 {
582     awt::MouseEvent aEvent (rEvent);
583     aEvent.Source = static_cast<XWeak*>(this);
584     ::cppu::OInterfaceContainerHelper* pIterator
585         = maBroadcaster.getContainer(cppu::UnoType<awt::XMouseMotionListener>::get());
586     if (pIterator != nullptr)
587     {
588         pIterator->notifyEach(&awt::XMouseMotionListener::mouseMoved, aEvent);
589     }
590 }
591 
592 //----- XWindowListener -------------------------------------------------------
593 
windowResized(const awt::WindowEvent &)594 void SAL_CALL PresenterSlideShowView::windowResized (const awt::WindowEvent&)
595 {
596     ThrowIfDisposed();
597     ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
598 
599     Resize();
600 }
601 
windowMoved(const awt::WindowEvent &)602 void SAL_CALL PresenterSlideShowView::windowMoved (const awt::WindowEvent&)
603 {
604     if ( ! mbIsPaintPending)
605         mbIsForcedPaintPending = true;
606 }
607 
windowShown(const lang::EventObject &)608 void SAL_CALL PresenterSlideShowView::windowShown (const lang::EventObject&)
609 {
610     Resize();
611 }
612 
windowHidden(const lang::EventObject &)613 void SAL_CALL PresenterSlideShowView::windowHidden (const lang::EventObject&) {}
614 
615 //----- XView -----------------------------------------------------------------
616 
getResourceId()617 Reference<XResourceId> SAL_CALL PresenterSlideShowView::getResourceId()
618 {
619     return mxViewId;
620 }
621 
isAnchorOnly()622 sal_Bool SAL_CALL PresenterSlideShowView::isAnchorOnly()
623 {
624     return false;
625 }
626 
627 //----- CachablePresenterView -------------------------------------------------
628 
ActivatePresenterView()629 void PresenterSlideShowView::ActivatePresenterView()
630 {
631     if (mxSlideShow.is() && ! mbIsViewAdded)
632     {
633         impl_addAndConfigureView();
634         mbIsViewAdded = true;
635     }
636 }
637 
DeactivatePresenterView()638 void PresenterSlideShowView::DeactivatePresenterView()
639 {
640     if (mxSlideShow.is() && mbIsViewAdded)
641     {
642         mxSlideShow->removeView(this);
643         mbIsViewAdded = false;
644     }
645 }
646 
647 
PaintOuterWindow(const awt::Rectangle & rRepaintBox)648 void PresenterSlideShowView::PaintOuterWindow (const awt::Rectangle& rRepaintBox)
649 {
650     if ( ! mxCanvas.is())
651         return;
652 
653     if (!mpBackground)
654         return;
655 
656     const rendering::ViewState aViewState(
657         geometry::AffineMatrix2D(1,0,0, 0,1,0),
658         PresenterGeometryHelper::CreatePolygon(rRepaintBox, mxCanvas->getDevice()));
659 
660     rendering::RenderState aRenderState (
661         geometry::AffineMatrix2D(1,0,0, 0,1,0),
662         nullptr,
663         Sequence<double>(4),
664         rendering::CompositeOperation::SOURCE);
665 
666     Reference<rendering::XBitmap> xBackgroundBitmap (mpBackground->GetNormalBitmap());
667     if (xBackgroundBitmap.is())
668     {
669         const geometry::IntegerSize2D aBitmapSize(xBackgroundBitmap->getSize());
670         Sequence<rendering::Texture> aTextures
671         {
672             {
673                 geometry::AffineMatrix2D( aBitmapSize.Width,0,0, 0,aBitmapSize.Height,0),
674                 1,
675                 0,
676                 xBackgroundBitmap,
677                 nullptr,
678                 nullptr,
679                 rendering::StrokeAttributes(),
680                 rendering::TexturingMode::REPEAT,
681                 rendering::TexturingMode::REPEAT
682             }
683         };
684 
685         if (mxBackgroundPolygon1.is())
686             mxCanvas->fillTexturedPolyPolygon(
687                 mxBackgroundPolygon1,
688                 aViewState,
689                 aRenderState,
690                 aTextures);
691         if (mxBackgroundPolygon2.is())
692             mxCanvas->fillTexturedPolyPolygon(
693                 mxBackgroundPolygon2,
694                 aViewState,
695                 aRenderState,
696                 aTextures);
697     }
698     else
699     {
700         PresenterCanvasHelper::SetDeviceColor(aRenderState, mpBackground->maReplacementColor);
701 
702         if (mxBackgroundPolygon1.is())
703             mxCanvas->fillPolyPolygon(mxBackgroundPolygon1, aViewState, aRenderState);
704         if (mxBackgroundPolygon2.is())
705             mxCanvas->fillPolyPolygon(mxBackgroundPolygon2, aViewState, aRenderState);
706     }
707 }
708 
PaintEndSlide(const awt::Rectangle & rRepaintBox)709 void PresenterSlideShowView::PaintEndSlide (const awt::Rectangle& rRepaintBox)
710 {
711     if ( ! mxCanvas.is())
712         return;
713 
714     const rendering::ViewState aViewState(
715         geometry::AffineMatrix2D(1,0,0, 0,1,0),
716         PresenterGeometryHelper::CreatePolygon(rRepaintBox, mxCanvas->getDevice()));
717 
718     rendering::RenderState aRenderState (
719         geometry::AffineMatrix2D(1,0,0, 0,1,0),
720         nullptr,
721         Sequence<double>(4),
722         rendering::CompositeOperation::SOURCE);
723     PresenterCanvasHelper::SetDeviceColor(aRenderState, util::Color(0x00000000));
724     mxCanvas->fillPolyPolygon(
725         PresenterGeometryHelper::CreatePolygon(mxViewWindow->getPosSize(), mxCanvas->getDevice()),
726         aViewState,
727         aRenderState);
728 
729     do
730     {
731         if (!mpPresenterController)
732             break;
733         std::shared_ptr<PresenterTheme> pTheme (mpPresenterController->GetTheme());
734         if (pTheme == nullptr)
735             break;
736 
737         const OUString sViewStyle (pTheme->GetStyleName(mxViewId->getResourceURL()));
738         PresenterTheme::SharedFontDescriptor pFont (pTheme->GetFont(sViewStyle));
739         if (!pFont)
740             break;
741 
742         /// this is responsible of the " presentation exit " text inside the slide windows
743         PresenterCanvasHelper::SetDeviceColor(aRenderState, util::Color(0x00ffffff));
744         aRenderState.AffineTransform.m02 = 20;
745         aRenderState.AffineTransform.m12 = 40;
746         const rendering::StringContext aContext (
747             msClickToExitPresentationText, 0, msClickToExitPresentationText.getLength());
748         pFont->PrepareFont(mxCanvas);
749         const Reference<rendering::XTextLayout> xLayout (
750             pFont->mxFont->createTextLayout(aContext,rendering::TextDirection::WEAK_LEFT_TO_RIGHT,0));
751         mxCanvas->drawTextLayout(
752             xLayout,
753             aViewState,
754             aRenderState);
755     }
756     while (false);
757 
758     // Finally, in double buffered environments, request the changes to be
759     // made visible.
760     Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
761     if (xSpriteCanvas.is())
762         xSpriteCanvas->updateScreen(true);
763 }
764 
PaintInnerWindow(const awt::PaintEvent & rEvent)765 void PresenterSlideShowView::PaintInnerWindow (const awt::PaintEvent& rEvent)
766 {
767     // Forward window paint to listeners.
768     awt::PaintEvent aEvent (rEvent);
769     aEvent.Source = static_cast<XWeak*>(this);
770     ::cppu::OInterfaceContainerHelper* pIterator
771         = maBroadcaster.getContainer(cppu::UnoType<awt::XPaintListener>::get());
772     if (pIterator != nullptr)
773     {
774         pIterator->notifyEach(&awt::XPaintListener::windowPaint, aEvent);
775     }
776 
777     /** The slide show relies on the back buffer of the canvas not being
778         modified.  With a shared canvas there are times when that can not be
779         guaranteed.
780     */
781     if (mbIsForcedPaintPending && mxSlideShow.is() && mbIsViewAdded)
782     {
783         mxSlideShow->removeView(this);
784         impl_addAndConfigureView();
785     }
786 
787     // Finally, in double buffered environments, request the changes to be
788     // made visible.
789     Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
790     if (xSpriteCanvas.is())
791         xSpriteCanvas->updateScreen(true);
792 }
793 
CreateViewWindow(const Reference<awt::XWindow> & rxParentWindow) const794 Reference<awt::XWindow> PresenterSlideShowView::CreateViewWindow (
795     const Reference<awt::XWindow>& rxParentWindow) const
796 {
797     Reference<awt::XWindow> xViewWindow;
798     try
799     {
800         Reference<lang::XMultiComponentFactory> xFactory (mxComponentContext->getServiceManager());
801         if ( ! xFactory.is())
802             return xViewWindow;
803 
804         Reference<awt::XToolkit2> xToolkit = awt::Toolkit::create(mxComponentContext);
805         awt::WindowDescriptor aWindowDescriptor (
806             awt::WindowClass_CONTAINER,
807             OUString(),
808             Reference<awt::XWindowPeer>(rxParentWindow,UNO_QUERY_THROW),
809             -1, // parent index not available
810             awt::Rectangle(0,0,10,10),
811             awt::WindowAttribute::SIZEABLE
812                 | awt::WindowAttribute::MOVEABLE
813                 | awt::WindowAttribute::NODECORATION);
814         xViewWindow.set( xToolkit->createWindow(aWindowDescriptor),UNO_QUERY_THROW);
815 
816         // Make the background transparent.  The slide show paints its own background.
817         Reference<awt::XWindowPeer> xPeer (xViewWindow, UNO_QUERY_THROW);
818         xPeer->setBackground(0xff000000);
819 
820         xViewWindow->setVisible(true);
821     }
822     catch (RuntimeException&)
823     {
824     }
825     return xViewWindow;
826 }
827 
CreateViewCanvas(const Reference<awt::XWindow> & rxViewWindow) const828 Reference<rendering::XCanvas> PresenterSlideShowView::CreateViewCanvas (
829     const Reference<awt::XWindow>& rxViewWindow) const
830 {
831     // Create a canvas for the view window.
832     return mxPresenterHelper->createSharedCanvas(
833         Reference<rendering::XSpriteCanvas>(mxTopPane->getCanvas(), UNO_QUERY),
834         mxTopPane->getWindow(),
835         mxTopPane->getCanvas(),
836         mxTopPane->getWindow(),
837         rxViewWindow);
838 }
839 
Resize()840 void PresenterSlideShowView::Resize()
841 {
842     if ( ! mxWindow.is() || ! mxViewWindow.is())
843         return;
844 
845     const awt::Rectangle aWindowBox (mxWindow->getPosSize());
846     if (aWindowBox.Height > 0)
847     {
848         awt::Rectangle aViewWindowBox;
849         const double nWindowAspectRatio (
850             double(aWindowBox.Width) / double(aWindowBox.Height));
851         if (nWindowAspectRatio > mnPageAspectRatio)
852         {
853             // Slides will be painted with the full parent window height.
854             aViewWindowBox.Width = sal_Int32(aWindowBox.Height * mnPageAspectRatio + 0.5);
855             aViewWindowBox.Height = aWindowBox.Height;
856             aViewWindowBox.X = (aWindowBox.Width - aViewWindowBox.Width) / 2;
857             aViewWindowBox.Y = 0;
858         }
859         else
860         {
861             // Slides will be painted with the full parent window width.
862             aViewWindowBox.Width = aWindowBox.Width;
863             aViewWindowBox.Height = sal_Int32(aWindowBox.Width / mnPageAspectRatio + 0.5);
864             aViewWindowBox.X = 0;
865             aViewWindowBox.Y = (aWindowBox.Height - aViewWindowBox.Height) / 2;
866         }
867         mxViewWindow->setPosSize(
868             aViewWindowBox.X,
869             aViewWindowBox.Y,
870             aViewWindowBox.Width,
871             aViewWindowBox.Height,
872             awt::PosSize::POSSIZE);
873     }
874 
875     // Clear the background polygon so that on the next paint it is created
876     // for the new size.
877     CreateBackgroundPolygons();
878 
879     // Notify listeners that the transformation that maps the view into the
880     // window has changed.
881     lang::EventObject aEvent (static_cast<XWeak*>(this));
882     ::cppu::OInterfaceContainerHelper* pIterator
883         = maBroadcaster.getContainer(cppu::UnoType<util::XModifyListener>::get());
884     if (pIterator != nullptr)
885     {
886         pIterator->notifyEach(&util::XModifyListener::modified, aEvent);
887     }
888 
889     // Due to constant aspect ratio resizing may lead a preview that changes
890     // its position but not its size.  This invalidates the back buffer and
891     // we have to enforce a complete repaint.
892     if ( ! mbIsPaintPending)
893         mbIsForcedPaintPending = true;
894 }
895 
CreateBackgroundPolygons()896 void PresenterSlideShowView::CreateBackgroundPolygons()
897 {
898     const awt::Rectangle aWindowBox (mxWindow->getPosSize());
899     const awt::Rectangle aViewWindowBox (mxViewWindow->getPosSize());
900     if (aWindowBox.Height == aViewWindowBox.Height && aWindowBox.Width == aViewWindowBox.Width)
901     {
902         mxBackgroundPolygon1 = nullptr;
903         mxBackgroundPolygon2 = nullptr;
904     }
905     else if (aWindowBox.Height == aViewWindowBox.Height)
906     {
907         // Paint two boxes to the left and right of the view window.
908         mxBackgroundPolygon1 = PresenterGeometryHelper::CreatePolygon(
909             awt::Rectangle(
910                 0,
911                 0,
912                 aViewWindowBox.X,
913                 aWindowBox.Height),
914             mxCanvas->getDevice());
915         mxBackgroundPolygon2 = PresenterGeometryHelper::CreatePolygon(
916             awt::Rectangle(
917                 aViewWindowBox.X + aViewWindowBox.Width,
918                 0,
919                 aWindowBox.Width - aViewWindowBox.X - aViewWindowBox.Width,
920                 aWindowBox.Height),
921             mxCanvas->getDevice());
922     }
923     else
924     {
925         // Paint two boxes above and below the view window.
926         mxBackgroundPolygon1 = PresenterGeometryHelper::CreatePolygon(
927             awt::Rectangle(
928                 0,
929                 0,
930                 aWindowBox.Width,
931                 aViewWindowBox.Y),
932             mxCanvas->getDevice());
933         mxBackgroundPolygon2 = PresenterGeometryHelper::CreatePolygon(
934             awt::Rectangle(
935                 0,
936                 aViewWindowBox.Y + aViewWindowBox.Height,
937                 aWindowBox.Width,
938                 aWindowBox.Height - aViewWindowBox.Y - aViewWindowBox.Height),
939             mxCanvas->getDevice());
940     }
941 }
942 
ThrowIfDisposed()943 void PresenterSlideShowView::ThrowIfDisposed()
944 {
945     if (rBHelper.bDisposed || rBHelper.bInDispose)
946     {
947         throw lang::DisposedException (
948             "PresenterSlideShowView object has already been disposed",
949             static_cast<uno::XWeak*>(this));
950     }
951 }
952 
impl_addAndConfigureView()953 void PresenterSlideShowView::impl_addAndConfigureView()
954 {
955     Reference<presentation::XSlideShowView> xView (this);
956     mxSlideShow->addView(xView);
957     // Prevent embedded sounds being played twice at the same time by
958     // disabling sound for the new slide show view.
959     beans::PropertyValue aProperty;
960     aProperty.Name = "IsSoundEnabled";
961     Sequence<Any> aValues (2);
962     aValues[0] <<= xView;
963     aValues[1] <<= false;
964     aProperty.Value <<= aValues;
965     mxSlideShow->setProperty(aProperty);
966 }
967 
968 } // end of namespace ::sd::presenter
969 
970 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
971