xref: /core/sd/source/ui/slideshow/slideshowimpl.cxx (revision 5060c501)
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 <sal/config.h>
21 
22 #include <algorithm>
23 
24 #include <config_features.h>
25 
26 #include <com/sun/star/frame/theAutoRecovery.hpp>
27 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
28 #include <com/sun/star/document/XEventsSupplier.hpp>
29 #include <com/sun/star/drawing/XMasterPageTarget.hpp>
30 #include <com/sun/star/beans/PropertyValue.hpp>
31 #include <com/sun/star/beans/XPropertySetInfo.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/awt/SystemPointer.hpp>
34 #include <com/sun/star/util/URLTransformer.hpp>
35 #include <com/sun/star/util/XURLTransformer.hpp>
36 #include <com/sun/star/frame/XDispatch.hpp>
37 #include <com/sun/star/frame/XLayoutManager.hpp>
38 #include <com/sun/star/presentation/SlideShow.hpp>
39 #include <com/sun/star/media/XPlayer.hpp>
40 #include <officecfg/Office/Common.hxx>
41 #include <svl/stritem.hxx>
42 #include <svl/urihelper.hxx>
43 #include <basic/sbstar.hxx>
44 
45 #include <toolkit/helper/vclunohelper.hxx>
46 #include <tools/diagnose_ex.h>
47 
48 #include <sfx2/infobar.hxx>
49 #include <sfx2/dispatch.hxx>
50 #include <sfx2/docfile.hxx>
51 #include <sfx2/app.hxx>
52 #include <sfx2/viewfrm.hxx>
53 #include <svx/svdoole2.hxx>
54 #include <svx/f3dchild.hxx>
55 #include <svx/imapdlg.hxx>
56 #include <svx/fontwork.hxx>
57 #include <svx/SvxColorChildWindow.hxx>
58 #include <svx/bmpmask.hxx>
59 #include <svx/srchdlg.hxx>
60 #include <svx/hyperdlg.hxx>
61 #include <svx/svxids.hrc>
62 #include <AnimationChildWindow.hxx>
63 #include <notifydocumentevent.hxx>
64 #include "slideshowimpl.hxx"
65 #include "slideshowviewimpl.hxx"
66 #include "PaneHider.hxx"
67 
68 #include <bitmaps.hlst>
69 #include <strings.hrc>
70 #include <sdresid.hxx>
71 #include <vcl/canvastools.hxx>
72 #include <vcl/commandevent.hxx>
73 #include <vcl/weldutils.hxx>
74 
75 #include <vcl/settings.hxx>
76 #include <vcl/svapp.hxx>
77 #include <vcl/help.hxx>
78 #include <comphelper/processfactory.hxx>
79 #include <comphelper/propertyvalue.hxx>
80 #include <rtl/ref.hxx>
81 #include <o3tl/safeint.hxx>
82 #include <o3tl/string_view.hxx>
83 #include <avmedia/mediawindow.hxx>
84 #include <svtools/colrdlg.hxx>
85 #include <DrawDocShell.hxx>
86 #include <ViewShellBase.hxx>
87 #include <PresentationViewShell.hxx>
88 #include <RemoteServer.hxx>
89 #include <customshowlist.hxx>
90 #include <unopage.hxx>
91 #include <sdpage.hxx>
92 #include <sdmod.hxx>
93 #include <app.hrc>
94 #include <cusshow.hxx>
95 #include <optsitem.hxx>
96 
97 #define CM_SLIDES       21
98 
99 using ::com::sun::star::animations::XAnimationNode;
100 using ::com::sun::star::animations::XAnimationListener;
101 using ::com::sun::star::awt::XWindow;
102 using namespace ::com::sun::star;
103 using namespace ::com::sun::star::lang;
104 using namespace ::com::sun::star::uno;
105 using namespace ::com::sun::star::drawing;
106 using namespace ::com::sun::star::container;
107 using namespace ::com::sun::star::document;
108 using namespace ::com::sun::star::presentation;
109 using namespace ::com::sun::star::beans;
110 
111 namespace sd
112 {
113 /** Slots, which will be disabled in the slide show and are managed by Sfx.
114     Have to be sorted in the order of the SIDs */
115 sal_uInt16 const pAllowed[] =
116 {
117     SID_OPENDOC                             , //     5501   ///< that internally jumps work
118     SID_JUMPTOMARK                          , //     5598
119     SID_OPENHYPERLINK                       , //     6676
120     SID_PRESENTATION_END                     //    27218
121 };
122 
123 class AnimationSlideController
124 {
125 public:
126     enum Mode { ALL, FROM, CUSTOM, PREVIEW };
127 
128 public:
129     AnimationSlideController( Reference< XIndexAccess > const & xSlides, Mode eMode );
130 
131     void setStartSlideNumber( sal_Int32 nSlideNumber ) { mnStartSlideNumber = nSlideNumber; }
132     sal_Int32 getStartSlideIndex() const;
133 
134     sal_Int32 getCurrentSlideNumber() const;
135     sal_Int32 getCurrentSlideIndex() const;
136 
137     sal_Int32 getSlideIndexCount() const { return maSlideNumbers.size(); }
138     sal_Int32 getSlideNumberCount() const { return mnSlideCount; }
139 
140     sal_Int32 getSlideNumber( sal_Int32 nSlideIndex ) const;
141 
142     void insertSlideNumber( sal_Int32 nSlideNumber, bool bVisible = true );
143     void setPreviewNode( const Reference< XAnimationNode >& xPreviewNode );
144 
145     bool jumpToSlideIndex( sal_Int32 nNewSlideIndex );
146     bool jumpToSlideNumber( sal_Int32 nNewSlideIndex );
147 
148     bool nextSlide();
149     bool previousSlide();
150 
151     void displayCurrentSlide( const Reference< XSlideShow >& xShow,
152                               const Reference< XDrawPagesSupplier>& xDrawPages,
153                               const bool bSkipAllMainSequenceEffects );
154 
155     sal_Int32 getNextSlideIndex() const;
156     sal_Int32 getPreviousSlideIndex() const;
157 
158     bool isVisibleSlideNumber( sal_Int32 nSlideNumber ) const;
159 
160     Reference< XDrawPage > getSlideByNumber( sal_Int32 nSlideNumber ) const;
161 
162     sal_Int32 getNextSlideNumber() const;
163 
164     bool hasSlides() const { return !maSlideNumbers.empty(); }
165 
166 private:
167     bool getSlideAPI( sal_Int32 nSlideNumber, Reference< XDrawPage >& xSlide, Reference< XAnimationNode >& xAnimNode );
168     sal_Int32 findSlideIndex( sal_Int32 nSlideNumber ) const;
169 
170     bool isValidIndex( sal_Int32 nIndex ) const { return (nIndex >= 0) && (o3tl::make_unsigned(nIndex) < maSlideNumbers.size()); }
171     bool isValidSlideNumber( sal_Int32 nSlideNumber ) const { return (nSlideNumber >= 0) && (nSlideNumber < mnSlideCount); }
172 
173 private:
174     Mode meMode;
175     sal_Int32 mnStartSlideNumber;
176     std::vector< sal_Int32 > maSlideNumbers;
177     std::vector< bool > maSlideVisible;
178     std::vector< bool > maSlideVisited;
179     Reference< XAnimationNode > mxPreviewNode;
180     sal_Int32 mnSlideCount;
181     sal_Int32 mnCurrentSlideIndex;
182     sal_Int32 mnHiddenSlideNumber;
183     Reference< XIndexAccess > mxSlides;
184 };
185 
186 Reference< XDrawPage > AnimationSlideController::getSlideByNumber( sal_Int32 nSlideNumber ) const
187 {
188     Reference< XDrawPage > xSlide;
189     if( mxSlides.is() && (nSlideNumber >= 0) && (nSlideNumber < mxSlides->getCount()) )
190         mxSlides->getByIndex( nSlideNumber ) >>= xSlide;
191     return xSlide;
192 }
193 
194 bool AnimationSlideController::isVisibleSlideNumber( sal_Int32 nSlideNumber ) const
195 {
196     sal_Int32 nIndex = findSlideIndex( nSlideNumber );
197 
198     if( nIndex != -1 )
199         return maSlideVisible[ nIndex ];
200     else
201         return false;
202 }
203 
204 void AnimationSlideController::setPreviewNode( const Reference< XAnimationNode >& xPreviewNode )
205 {
206     mxPreviewNode = xPreviewNode;
207 }
208 
209 AnimationSlideController::AnimationSlideController( Reference< XIndexAccess > const & xSlides, Mode eMode  )
210 :   meMode( eMode )
211 ,   mnStartSlideNumber(-1)
212 ,   mnSlideCount( 0 )
213 ,   mnCurrentSlideIndex(0)
214 ,   mnHiddenSlideNumber( -1 )
215 ,   mxSlides( xSlides )
216 {
217     if( mxSlides.is() )
218         mnSlideCount = xSlides->getCount();
219 }
220 
221 sal_Int32 AnimationSlideController::getStartSlideIndex() const
222 {
223     if( mnStartSlideNumber >= 0 )
224     {
225         sal_Int32 nIndex;
226         const sal_Int32 nCount = maSlideNumbers.size();
227 
228         for( nIndex = 0; nIndex < nCount; nIndex++ )
229         {
230             if( maSlideNumbers[nIndex] == mnStartSlideNumber )
231                 return nIndex;
232         }
233     }
234 
235     return 0;
236 }
237 
238 sal_Int32 AnimationSlideController::getCurrentSlideNumber() const
239 {
240     if( mnHiddenSlideNumber != -1 )
241         return mnHiddenSlideNumber;
242     else if( !maSlideNumbers.empty() )
243         return maSlideNumbers[mnCurrentSlideIndex];
244     else
245         return 0;
246 }
247 
248 sal_Int32 AnimationSlideController::getCurrentSlideIndex() const
249 {
250     if( mnHiddenSlideNumber != -1 )
251         return -1;
252     else
253         return mnCurrentSlideIndex;
254 }
255 
256 bool AnimationSlideController::jumpToSlideIndex( sal_Int32 nNewSlideIndex )
257 {
258     if( isValidIndex( nNewSlideIndex ) )
259     {
260         mnCurrentSlideIndex = nNewSlideIndex;
261         mnHiddenSlideNumber = -1;
262         maSlideVisited[mnCurrentSlideIndex] = true;
263         return true;
264     }
265     else
266     {
267         return false;
268     }
269 }
270 
271 bool AnimationSlideController::jumpToSlideNumber( sal_Int32 nNewSlideNumber )
272 {
273     sal_Int32 nIndex = findSlideIndex( nNewSlideNumber );
274     if( isValidIndex( nIndex ) )
275     {
276         return jumpToSlideIndex( nIndex );
277     }
278     else if( (nNewSlideNumber >= 0) && (nNewSlideNumber < mnSlideCount) )
279     {
280         // jump to a hidden slide
281         mnHiddenSlideNumber = nNewSlideNumber;
282         return true;
283     }
284     else
285     {
286         return false;
287     }
288 }
289 
290 sal_Int32 AnimationSlideController::getSlideNumber( sal_Int32 nSlideIndex ) const
291 {
292     if( isValidIndex( nSlideIndex ) )
293         return maSlideNumbers[nSlideIndex];
294     else
295         return -1;
296 }
297 
298 void AnimationSlideController::insertSlideNumber( sal_Int32 nSlideNumber, bool bVisible /* = true */ )
299 {
300     DBG_ASSERT( isValidSlideNumber( nSlideNumber ), "sd::AnimationSlideController::insertSlideNumber(), illegal index" );
301     if( isValidSlideNumber( nSlideNumber ) )
302     {
303         maSlideNumbers.push_back( nSlideNumber );
304         maSlideVisible.push_back( bVisible );
305         maSlideVisited.push_back( false );
306     }
307 }
308 
309 bool AnimationSlideController::getSlideAPI( sal_Int32 nSlideNumber, Reference< XDrawPage >& xSlide, Reference< XAnimationNode >& xAnimNode )
310 {
311     if( isValidSlideNumber( nSlideNumber ) ) try
312     {
313         xSlide.set( mxSlides->getByIndex(nSlideNumber), UNO_QUERY_THROW );
314 
315         if( meMode == PREVIEW )
316         {
317             xAnimNode = mxPreviewNode;
318         }
319         else
320         {
321             Reference< animations::XAnimationNodeSupplier > xAnimNodeSupplier( xSlide, UNO_QUERY_THROW );
322             xAnimNode = xAnimNodeSupplier->getAnimationNode();
323         }
324 
325         return true;
326     }
327     catch( Exception& )
328     {
329         TOOLS_WARN_EXCEPTION( "sd", "sd::AnimationSlideController::getSlideAPI()" );
330     }
331 
332     return false;
333 }
334 
335 sal_Int32 AnimationSlideController::findSlideIndex( sal_Int32 nSlideNumber ) const
336 {
337     sal_Int32 nIndex;
338     const sal_Int32 nCount = maSlideNumbers.size();
339 
340     for( nIndex = 0; nIndex < nCount; nIndex++ )
341     {
342         if( maSlideNumbers[nIndex] == nSlideNumber )
343             return nIndex;
344     }
345 
346     return -1;
347 }
348 
349 sal_Int32 AnimationSlideController::getNextSlideIndex() const
350 {
351     switch( meMode )
352     {
353     case ALL:
354         {
355             sal_Int32 nNewSlideIndex = mnCurrentSlideIndex + 1;
356             if( isValidIndex( nNewSlideIndex ) )
357             {
358                 // if the current slide is not excluded, make sure the
359                 // next slide is also not excluded.
360                 // if the current slide is excluded, we want to go
361                 // to the next slide, even if this is also excluded.
362                 if( maSlideVisible[mnCurrentSlideIndex] )
363                 {
364                     while( isValidIndex( nNewSlideIndex ) )
365                     {
366                         if( maSlideVisible[nNewSlideIndex] )
367                             break;
368 
369                         nNewSlideIndex++;
370                     }
371                 }
372             }
373             return isValidIndex( nNewSlideIndex ) ? nNewSlideIndex : -1;
374         }
375 
376     case FROM:
377     case CUSTOM:
378         return mnHiddenSlideNumber == -1 ? mnCurrentSlideIndex + 1 : mnCurrentSlideIndex;
379 
380     default:
381     case PREVIEW:
382         return -1;
383 
384     }
385 }
386 
387 sal_Int32 AnimationSlideController::getNextSlideNumber() const
388 {
389     sal_Int32 nNextSlideIndex = getNextSlideIndex();
390     if( isValidIndex( nNextSlideIndex ) )
391     {
392         return maSlideNumbers[nNextSlideIndex];
393     }
394     else
395     {
396         return -1;
397     }
398 }
399 
400 bool AnimationSlideController::nextSlide()
401 {
402     return jumpToSlideIndex( getNextSlideIndex() );
403 }
404 
405 sal_Int32 AnimationSlideController::getPreviousSlideIndex() const
406 {
407     sal_Int32 nNewSlideIndex = mnCurrentSlideIndex - 1;
408 
409     switch( meMode )
410     {
411         case ALL:
412         {
413             // make sure the previous slide is visible
414             // or was already visited
415             while( isValidIndex( nNewSlideIndex ) )
416             {
417                 if( maSlideVisible[nNewSlideIndex] || maSlideVisited[nNewSlideIndex] )
418                     break;
419 
420                 nNewSlideIndex--;
421             }
422 
423             break;
424         }
425 
426         case PREVIEW:
427             return -1;
428 
429         default:
430             break;
431     }
432 
433     return nNewSlideIndex;
434 }
435 
436 bool AnimationSlideController::previousSlide()
437 {
438     return jumpToSlideIndex( getPreviousSlideIndex() );
439 }
440 
441 void AnimationSlideController::displayCurrentSlide( const Reference< XSlideShow >& xShow,
442                                                     const Reference< XDrawPagesSupplier>& xDrawPages,
443                                                     const bool bSkipAllMainSequenceEffects )
444 {
445     const sal_Int32 nCurrentSlideNumber = getCurrentSlideNumber();
446 
447     if( !(xShow.is() && (nCurrentSlideNumber != -1 )) )
448         return;
449 
450     Reference< XDrawPage > xSlide;
451     Reference< XAnimationNode > xAnimNode;
452     ::std::vector<PropertyValue> aProperties;
453 
454     const sal_Int32 nNextSlideNumber = getNextSlideNumber();
455     if( getSlideAPI( nNextSlideNumber, xSlide, xAnimNode )  )
456     {
457         Sequence< Any > aValue{ Any(xSlide), Any(xAnimNode) };
458         aProperties.emplace_back( "Prefetch" ,
459                 -1,
460                 Any(aValue),
461                 PropertyState_DIRECT_VALUE);
462     }
463     if (bSkipAllMainSequenceEffects)
464     {
465         // Add one property that prevents the slide transition from being
466         // shown (to speed up the transition to the previous slide) and
467         // one to show all main sequence effects so that the user can
468         // continue to undo effects.
469         aProperties.emplace_back( "SkipAllMainSequenceEffects",
470                 -1,
471                 Any(true),
472                 PropertyState_DIRECT_VALUE);
473         aProperties.emplace_back("SkipSlideTransition",
474                 -1,
475                 Any(true),
476                 PropertyState_DIRECT_VALUE);
477     }
478 
479     if( getSlideAPI( nCurrentSlideNumber, xSlide, xAnimNode ) )
480         xShow->displaySlide( xSlide, xDrawPages, xAnimNode, comphelper::containerToSequence(aProperties) );
481 }
482 
483 constexpr OUStringLiteral gsOnClick( u"OnClick" );
484 constexpr OUStringLiteral gsBookmark( u"Bookmark" );
485 constexpr OUStringLiteral gsVerb( u"Verb" );
486 
487 SlideshowImpl::SlideshowImpl( const Reference< XPresentation2 >& xPresentation, ViewShell* pViewSh, ::sd::View* pView, SdDrawDocument* pDoc, vcl::Window* pParentWindow )
488 : mxModel(pDoc->getUnoModel(),UNO_QUERY_THROW)
489 , maUpdateTimer("SlideShowImpl maUpdateTimer")
490 , maInputFreezeTimer("SlideShowImpl maInputFreezeTimer")
491 , maDeactivateTimer("SlideShowImpl maDeactivateTimer")
492 , mpView(pView)
493 , mpViewShell(pViewSh)
494 , mpDocSh(pDoc->GetDocSh())
495 , mpDoc(pDoc)
496 , mpParentWindow(pParentWindow)
497 , mpShowWindow(nullptr)
498 , mnRestoreSlide(0)
499 , maPresSize( -1, -1 )
500 , meAnimationMode(ANIMATIONMODE_SHOW)
501 , mpOldActiveWindow(nullptr)
502 , mnChildMask( 0 )
503 , mbDisposed(false)
504 , mbAutoSaveWasOn(false)
505 , mbRehearseTimings(false)
506 , mbIsPaused(false)
507 , mbWasPaused(false)
508 , mbInputFreeze(false)
509 , mbActive(false)
510 , maPresSettings( pDoc->getPresentationSettings() )
511 , mnUserPaintColor( 0x80ff0000L )
512 , mbUsePen(false)
513 , mdUserPaintStrokeWidth ( 150.0 )
514 , mnEndShowEvent(nullptr)
515 , mnContextMenuEvent(nullptr)
516 , mxPresentation( xPresentation )
517 {
518     if( mpViewShell )
519         mpOldActiveWindow = mpViewShell->GetActiveWindow();
520 
521     maUpdateTimer.SetInvokeHandler(LINK(this, SlideshowImpl, updateHdl));
522     // Priority must not be too high or we'll starve input handling etc.
523     maUpdateTimer.SetPriority(TaskPriority::REPAINT);
524 
525     maDeactivateTimer.SetInvokeHandler(LINK(this, SlideshowImpl, deactivateHdl));
526     maDeactivateTimer.SetTimeout( 20 );
527 
528     maInputFreezeTimer.SetInvokeHandler( LINK( this, SlideshowImpl, ReadyForNextInputHdl ) );
529     maInputFreezeTimer.SetTimeout( 20 );
530 
531         // no autosave during show
532     if( officecfg::Office::Common::Save::Document::AutoSave::get() )
533         mbAutoSaveWasOn = true;
534 
535     Application::AddEventListener( LINK( this, SlideshowImpl, EventListenerHdl ) );
536 
537     mbUsePen = maPresSettings.mbMouseAsPen;
538 
539     SdOptions* pOptions = SD_MOD()->GetSdOptions(DocumentType::Impress);
540     if( pOptions )
541     {
542         mnUserPaintColor = pOptions->GetPresentationPenColor();
543         mdUserPaintStrokeWidth = pOptions->GetPresentationPenWidth();
544     }
545 }
546 
547 SlideshowImpl::~SlideshowImpl()
548 {
549     SdModule *pModule = SD_MOD();
550     //rhbz#806663 SlideshowImpl can outlive SdModule
551     SdOptions* pOptions = pModule ?
552         pModule->GetSdOptions(DocumentType::Impress) : nullptr;
553     if( pOptions )
554     {
555         pOptions->SetPresentationPenColor(mnUserPaintColor);
556         pOptions->SetPresentationPenWidth(mdUserPaintStrokeWidth);
557     }
558 
559     Application::RemoveEventListener( LINK( this, SlideshowImpl, EventListenerHdl ) );
560 
561     maDeactivateTimer.Stop();
562 
563     if( !mbDisposed )
564     {
565         OSL_FAIL("SlideshowImpl::~SlideshowImpl(), component was not disposed!");
566         std::unique_lock g(m_aMutex);
567         disposing(g);
568     }
569 }
570 
571 void SlideshowImpl::disposing(std::unique_lock<std::mutex>&)
572 {
573 #ifdef ENABLE_SDREMOTE
574     RemoteServer::presentationStopped();
575 #endif
576     if( mxShow.is() && mpDoc )
577         NotifyDocumentEvent(
578             *mpDoc,
579             "OnEndPresentation" );
580 
581     if( mbAutoSaveWasOn )
582         setAutoSaveState( true );
583 
584     if( mnEndShowEvent )
585         Application::RemoveUserEvent( mnEndShowEvent );
586     if( mnContextMenuEvent )
587         Application::RemoveUserEvent( mnContextMenuEvent );
588 
589     maInputFreezeTimer.Stop();
590 
591     SolarMutexGuard aSolarGuard;
592 
593     if( !mxShow.is() )
594         return;
595 
596     if( mxPresentation.is() )
597         mxPresentation->end();
598 
599     maUpdateTimer.Stop();
600 
601     removeShapeEvents();
602 
603     if( mxListenerProxy.is() )
604         mxListenerProxy->removeAsSlideShowListener();
605 
606     try
607     {
608         if( mxView.is() )
609             mxShow->removeView( mxView );
610 
611         Reference< XComponent > xComponent( mxShow, UNO_QUERY );
612         if( xComponent.is() )
613             xComponent->dispose();
614 
615         if( mxView.is() )
616             mxView->dispose();
617     }
618     catch( Exception& )
619     {
620         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stop()" );
621     }
622 
623     mxShow.clear();
624     mxView.clear();
625     mxListenerProxy.clear();
626     mpSlideController.reset();
627 
628     // take DrawView from presentation window, but give the old window back
629     if( mpShowWindow && mpView )
630         mpView->DeleteWindowFromPaintView( mpShowWindow->GetOutDev() );
631 
632     if( mpView )
633         mpView->SetAnimationPause( false );
634 
635     if( mpViewShell )
636     {
637         mpViewShell->SetActiveWindow(mpOldActiveWindow);
638         if (mpShowWindow)
639             mpShowWindow->SetViewShell( nullptr );
640     }
641 
642     if( mpView )
643         mpView->InvalidateAllWin();
644 
645     if( maPresSettings.mbFullScreen )
646     {
647 #if HAVE_FEATURE_SCRIPTING
648         // restore StarBASICErrorHdl
649         StarBASIC::SetGlobalErrorHdl(maStarBASICGlobalErrorHdl);
650         maStarBASICGlobalErrorHdl = Link<StarBASIC*,bool>();
651 #endif
652     }
653     else
654     {
655         if( mpShowWindow )
656             mpShowWindow->Hide();
657     }
658 
659     if( meAnimationMode == ANIMATIONMODE_SHOW )
660     {
661         mpDocSh->SetSlotFilter();
662         mpDocSh->ApplySlotFilter();
663 
664         Help::EnableContextHelp();
665         Help::EnableExtHelp();
666 
667         showChildWindows();
668         mnChildMask = 0;
669     }
670 
671     // show current window again
672     if( mpViewShell && dynamic_cast< PresentationViewShell *>( mpViewShell ) ==  nullptr)
673     {
674         if( meAnimationMode == ANIMATIONMODE_SHOW )
675         {
676             mpViewShell->GetViewShellBase().ShowUIControls (true);
677             mpPaneHider.reset();
678         }
679         else if( meAnimationMode == ANIMATIONMODE_PREVIEW )
680         {
681             mpViewShell->ShowUIControls(true);
682         }
683     }
684 
685     if( mpShowWindow )
686         mpShowWindow->Hide();
687     mpShowWindow.disposeAndClear();
688 
689     if ( mpViewShell )
690     {
691         if( meAnimationMode == ANIMATIONMODE_SHOW )
692         {
693             ::sd::Window* pActWin = mpViewShell->GetActiveWindow();
694 
695             if (pActWin)
696             {
697                 Size aVisSizePixel = pActWin->GetOutputSizePixel();
698                 ::tools::Rectangle aVisAreaWin = pActWin->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) );
699                 mpViewShell->VisAreaChanged(aVisAreaWin);
700                 if (mpView)
701                     mpView->VisAreaChanged(pActWin->GetOutDev());
702                 pActWin->GrabFocus();
703             }
704         }
705 
706         // restart the custom show dialog if he started us
707         if( mpViewShell->IsStartShowWithDialog() && getDispatcher() )
708         {
709             mpViewShell->SetStartShowWithDialog( false );
710             getDispatcher()->Execute( SID_CUSTOMSHOW_DLG, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
711         }
712 
713         mpViewShell->GetViewShellBase().UpdateBorder(true);
714     }
715 
716     if( mpShowWindow )
717     {
718         mpShowWindow.disposeAndClear();
719     }
720 
721     setActiveXToolbarsVisible( true );
722 
723     mbDisposed = true;
724 }
725 
726 bool SlideshowImpl::startPreview(
727         const Reference< XDrawPage >& xDrawPage,
728         const Reference< XAnimationNode >& xAnimationNode,
729         vcl::Window * pParent )
730 {
731     bool bRet = false;
732 
733     try
734     {
735         const Reference<lang::XServiceInfo> xServiceInfo( xDrawPage, UNO_QUERY );
736         if (xServiceInfo.is()) {
737             const Sequence<OUString> supportedServices(
738                 xServiceInfo->getSupportedServiceNames() );
739             if (comphelper::findValue(supportedServices, "com.sun.star.drawing.MasterPage") != -1) {
740                 OSL_FAIL("sd::SlideshowImpl::startPreview() "
741                           "not allowed on master page!");
742                 return false;
743             }
744         }
745 
746         mxPreviewDrawPage = xDrawPage;
747         mxPreviewAnimationNode = xAnimationNode;
748         meAnimationMode = ANIMATIONMODE_PREVIEW;
749 
750         maPresSettings.mbAll = false;
751         maPresSettings.mbEndless = false;
752         maPresSettings.mbCustomShow = false;
753         maPresSettings.mbManual = false;
754         maPresSettings.mbMouseVisible = false;
755         maPresSettings.mbMouseAsPen = false;
756         maPresSettings.mbLockedPages = false;
757         maPresSettings.mbAlwaysOnTop = false;
758         maPresSettings.mbFullScreen = false;
759         maPresSettings.mbAnimationAllowed = true;
760         maPresSettings.mnPauseTimeout = 0;
761         maPresSettings.mbShowPauseLogo = false;
762 
763         Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
764         Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
765         mpSlideController = std::make_shared<AnimationSlideController>( xSlides, AnimationSlideController::PREVIEW );
766 
767         sal_Int32 nSlideNumber = 0;
768         Reference< XPropertySet > xSet( mxPreviewDrawPage, UNO_QUERY_THROW );
769         xSet->getPropertyValue( "Number" ) >>= nSlideNumber;
770         mpSlideController->insertSlideNumber( nSlideNumber-1 );
771         mpSlideController->setPreviewNode( xAnimationNode );
772 
773         mpShowWindow = VclPtr<ShowWindow>::Create( this, ((pParent == nullptr) && mpViewShell) ?  mpParentWindow.get() : pParent );
774         if( mpViewShell )
775         {
776             mpViewShell->SetActiveWindow( mpShowWindow );
777             mpShowWindow->SetViewShell (mpViewShell);
778             mpViewShell->ShowUIControls (false);
779         }
780 
781         if( mpView )
782         {
783             mpView->AddWindowToPaintView( mpShowWindow->GetOutDev(), nullptr );
784             mpView->SetAnimationPause( true );
785         }
786 
787         // call resize handler
788         if( pParent )
789         {
790             maPresSize = pParent->GetSizePixel();
791         }
792         else if( mpViewShell )
793         {
794             ::tools::Rectangle aContentRect (mpViewShell->GetViewShellBase().getClientRectangle());
795             if (AllSettings::GetLayoutRTL())
796             {
797                 aContentRect.SetLeft( aContentRect.Right() );
798                 aContentRect.AdjustRight(aContentRect.Right() );
799             }
800             maPresSize = aContentRect.GetSize();
801             mpShowWindow->SetPosPixel( aContentRect.TopLeft() );
802         }
803         else
804         {
805             OSL_FAIL("sd::SlideshowImpl::startPreview(), I need either a parent window or a viewshell!");
806         }
807         resize( maPresSize );
808 
809         sal_Int32 nPropertyCount = 1;
810         if( mxPreviewAnimationNode.is() )
811             nPropertyCount++;
812 
813         Sequence< beans::PropertyValue > aProperties(nPropertyCount);
814         auto pProperties = aProperties.getArray();
815         pProperties[0].Name = "AutomaticAdvancement";
816         pProperties[0].Value <<= 1.0; // one second timeout
817 
818         if( mxPreviewAnimationNode.is() )
819         {
820             pProperties[1].Name = "NoSlideTransitions";
821             pProperties[1].Value <<= true;
822         }
823 
824         bRet = startShowImpl( aProperties );
825 
826         if( mpShowWindow != nullptr && meAnimationMode == ANIMATIONMODE_PREVIEW )
827             mpShowWindow->SetPreviewMode();
828 
829     }
830     catch( Exception& )
831     {
832         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startPreview()" );
833         bRet = false;
834     }
835 
836     return bRet;
837 }
838 
839 bool SlideshowImpl::startShow( PresentationSettingsEx const * pPresSettings )
840 {
841     const rtl::Reference<SlideshowImpl> xKeepAlive(this);
842 
843     DBG_ASSERT( !mxShow.is(), "sd::SlideshowImpl::startShow(), called twice!" );
844     if( mxShow.is() )
845         return true;
846     DBG_ASSERT( mpParentWindow!=nullptr, "sd::SlideshowImpl::startShow() called without parent window" );
847     if (mpParentWindow == nullptr)
848         return false;
849 
850     // Autoplay (pps/ppsx)
851     if (mpViewShell->GetDoc()->IsStartWithPresentation()){
852         mpViewShell->GetDoc()->SetExitAfterPresenting(true);
853     }
854 
855     bool bRet = false;
856 
857     try
858     {
859         if( pPresSettings )
860         {
861             maPresSettings = *pPresSettings;
862             mbRehearseTimings = pPresSettings->mbRehearseTimings;
863         }
864 
865         OUString  aPresSlide( maPresSettings.maPresPage );
866         SdPage* pStartPage = mpViewShell->GetActualPage();
867         bool    bStartWithActualSlide =  pStartPage;
868 
869         // times should be measured?
870         if( mbRehearseTimings )
871         {
872             maPresSettings.mbEndless = false;
873             maPresSettings.mbManual = true;
874             maPresSettings.mbMouseVisible = true;
875             maPresSettings.mbMouseAsPen = false;
876             maPresSettings.mnPauseTimeout = 0;
877             maPresSettings.mbShowPauseLogo = false;
878         }
879 
880         if( pStartPage )
881         {
882             if( pStartPage->GetPageKind() == PageKind::Notes )
883             {
884                 // we are in notes page mode, so get
885                 // the corresponding draw page
886                 const sal_uInt16 nPgNum = ( pStartPage->GetPageNum() - 2 ) >> 1;
887                 pStartPage = mpDoc->GetSdPage( nPgNum, PageKind::Standard );
888             }
889         }
890 
891         if( bStartWithActualSlide )
892         {
893             if ( aPresSlide.isEmpty())
894             {
895                 // no preset slide yet, so pick current on one
896                 aPresSlide = pStartPage->GetName();
897                 // if the starting slide is hidden, we can't set slide controller to ALL mode
898                 maPresSettings.mbAll = !pStartPage->IsExcluded();
899             }
900 
901             if( meAnimationMode != ANIMATIONMODE_SHOW )
902             {
903                 if( pStartPage->GetPageKind() == PageKind::Standard )
904                 {
905                     maPresSettings.mbAll = false;
906                 }
907             }
908         }
909 
910         // build page list
911         createSlideList( maPresSettings.mbAll, aPresSlide );
912 
913         // remember Slide number from where the show was started
914         if( pStartPage )
915             mnRestoreSlide = ( pStartPage->GetPageNum() - 1 ) / 2;
916 
917         if( mpSlideController->hasSlides() )
918         {
919             // hide child windows
920             hideChildWindows();
921 
922             mpShowWindow = VclPtr<ShowWindow>::Create( this, mpParentWindow );
923             mpShowWindow->SetMouseAutoHide( !maPresSettings.mbMouseVisible );
924             mpViewShell->SetActiveWindow( mpShowWindow );
925             mpShowWindow->SetViewShell (mpViewShell);
926             mpViewShell->GetViewShellBase().ShowUIControls (false);
927             // Hide the side panes for in-place presentations.
928             if ( ! maPresSettings.mbFullScreen)
929                 mpPaneHider.reset(new PaneHider(*mpViewShell,this));
930 
931             // these Slots are forbidden in other views for this document
932             if( mpDocSh )
933             {
934                 mpDocSh->SetSlotFilter( true, pAllowed );
935                 mpDocSh->ApplySlotFilter();
936             }
937 
938             Help::DisableContextHelp();
939             Help::DisableExtHelp();
940 
941             if( maPresSettings.mbFullScreen )
942             {
943 #if HAVE_FEATURE_SCRIPTING
944                 // disable basic ide error handling
945                 maStarBASICGlobalErrorHdl = StarBASIC::GetGlobalErrorHdl();
946                 StarBASIC::SetGlobalErrorHdl( Link<StarBASIC*,bool>() );
947 #endif
948             }
949 
950             // call resize handler
951             maPresSize = mpParentWindow->GetSizePixel();
952             if (!maPresSettings.mbFullScreen)
953             {
954                 const ::tools::Rectangle& aClientRect = mpViewShell->GetViewShellBase().getClientRectangle();
955                 maPresSize = aClientRect.GetSize();
956                 mpShowWindow->SetPosPixel( aClientRect.TopLeft() );
957                 resize( maPresSize );
958             }
959 
960             // #i41824#
961             // Note: In FullScreen Mode the OS (window manager) sends a resize to
962             // the WorkWindow once it actually resized it to full size.  The
963             // WorkWindow propagates the resize to the DrawViewShell which calls
964             // resize() at the SlideShow (this).  Calling resize here results in a
965             // temporary display of a black window in the window's default size
966 
967             if( mpView )
968             {
969                 mpView->AddWindowToPaintView( mpShowWindow->GetOutDev(), nullptr );
970                 mpView->SetAnimationPause( true );
971             }
972 
973             SfxBindings* pBindings = getBindings();
974             if( pBindings )
975             {
976                 pBindings->Invalidate( SID_PRESENTATION );
977                 pBindings->Invalidate( SID_REHEARSE_TIMINGS );
978             }
979 
980             // Defer the sd::ShowWindow's GrabFocus to SlideShow::activate. so that the accessible event can be fired correctly.
981             //mpShowWindow->GrabFocus();
982 
983             std::vector<beans::PropertyValue> aProperties;
984             aProperties.reserve( 4 );
985 
986             aProperties.emplace_back( "AdvanceOnClick" ,
987                     -1, Any( !maPresSettings.mbLockedPages ),
988                     beans::PropertyState_DIRECT_VALUE );
989 
990             aProperties.emplace_back( "ImageAnimationsAllowed" ,
991                     -1, Any( maPresSettings.mbAnimationAllowed ),
992                     beans::PropertyState_DIRECT_VALUE );
993 
994             const bool bZOrderEnabled(
995                 SD_MOD()->GetSdOptions( mpDoc->GetDocumentType() )->IsSlideshowRespectZOrder() );
996             aProperties.emplace_back( "DisableAnimationZOrder" ,
997                     -1, Any( !bZOrderEnabled ),
998                     beans::PropertyState_DIRECT_VALUE );
999 
1000             aProperties.emplace_back( "ForceManualAdvance" ,
1001                     -1, Any( maPresSettings.mbManual ),
1002                     beans::PropertyState_DIRECT_VALUE );
1003 
1004             if( mbUsePen )
1005             {
1006                 aProperties.emplace_back( "UserPaintColor" ,
1007                         // User paint color is black by default.
1008                         -1, Any( mnUserPaintColor ),
1009                         beans::PropertyState_DIRECT_VALUE );
1010 
1011                 aProperties.emplace_back( "UserPaintStrokeWidth" ,
1012                         // User paint color is black by default.
1013                         -1, Any( mdUserPaintStrokeWidth ),
1014                         beans::PropertyState_DIRECT_VALUE );
1015             }
1016 
1017             if (mbRehearseTimings) {
1018                 aProperties.emplace_back( "RehearseTimings" ,
1019                         -1, Any(true), beans::PropertyState_DIRECT_VALUE );
1020             }
1021 
1022             bRet = startShowImpl( Sequence<beans::PropertyValue>(
1023                                       aProperties.data(), aProperties.size() ) );
1024 
1025         }
1026 
1027         setActiveXToolbarsVisible( false );
1028     }
1029     catch (const Exception&)
1030     {
1031         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startShow()" );
1032         bRet = false;
1033     }
1034 
1035     return bRet;
1036 }
1037 
1038 bool SlideshowImpl::startShowImpl( const Sequence< beans::PropertyValue >& aProperties )
1039 {
1040     try
1041     {
1042         mxShow.set( createSlideShow(), UNO_SET_THROW );
1043 
1044         mxView = new SlideShowView(
1045                                              *mpShowWindow,
1046                                              mpDoc,
1047                                              meAnimationMode,
1048                                              this,
1049                                              maPresSettings.mbFullScreen);
1050 
1051         // try add wait symbol to properties:
1052         const Reference<rendering::XSpriteCanvas> xSpriteCanvas(
1053             mxView->getCanvas() );
1054         if (xSpriteCanvas.is())
1055         {
1056             BitmapEx waitSymbolBitmap(BMP_WAIT_ICON);
1057             const Reference<rendering::XBitmap> xBitmap(
1058                 vcl::unotools::xBitmapFromBitmapEx( waitSymbolBitmap ) );
1059             if (xBitmap.is())
1060             {
1061                 mxShow->setProperty(
1062                     beans::PropertyValue( "WaitSymbolBitmap" ,
1063                         -1,
1064                         Any( xBitmap ),
1065                         beans::PropertyState_DIRECT_VALUE ) );
1066             }
1067 
1068             BitmapEx pointerSymbolBitmap(BMP_POINTER_ICON);
1069             const Reference<rendering::XBitmap> xPointerBitmap(
1070                 vcl::unotools::xBitmapFromBitmapEx( pointerSymbolBitmap ) );
1071             if (xPointerBitmap.is())
1072             {
1073                 mxShow->setProperty(
1074                     beans::PropertyValue( "PointerSymbolBitmap" ,
1075                         -1,
1076                         Any( xPointerBitmap ),
1077                         beans::PropertyState_DIRECT_VALUE ) );
1078             }
1079         }
1080 
1081         for( const auto& rProp : aProperties )
1082             mxShow->setProperty( rProp );
1083 
1084         mxShow->addView( mxView );
1085 
1086         mxListenerProxy.set( new SlideShowListenerProxy( this, mxShow ) );
1087         mxListenerProxy->addAsSlideShowListener();
1088 
1089         NotifyDocumentEvent(
1090             *mpDoc,
1091             "OnStartPresentation");
1092         displaySlideIndex( mpSlideController->getStartSlideIndex() );
1093 
1094         return true;
1095     }
1096     catch( Exception& )
1097     {
1098         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startShowImpl()" );
1099         return false;
1100     }
1101 }
1102 
1103 /** called only by the slideshow view when the first paint event occurs.
1104     This actually starts the slideshow. */
1105 void SlideshowImpl::onFirstPaint()
1106 {
1107     if( mpShowWindow )
1108     {
1109         /*
1110         mpShowWindow->SetBackground( Wallpaper( COL_BLACK ) );
1111         mpShowWindow->Erase();
1112         mpShowWindow->SetBackground();
1113         */
1114     }
1115 
1116     SolarMutexGuard aSolarGuard;
1117     maUpdateTimer.SetTimeout( sal_uLong(100) );
1118     maUpdateTimer.Start();
1119 }
1120 
1121 void SlideshowImpl::paint()
1122 {
1123     if( mxView.is() ) try
1124     {
1125         awt::PaintEvent aEvt;
1126         // aEvt.UpdateRect = TODO
1127         mxView->paint( aEvt );
1128     }
1129     catch( Exception& )
1130     {
1131         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::paint()" );
1132     }
1133 }
1134 
1135 void SAL_CALL SlideshowImpl::addSlideShowListener( const Reference< XSlideShowListener >& xListener )
1136 {
1137     if( mxListenerProxy.is() )
1138         mxListenerProxy->addSlideShowListener( xListener );
1139 }
1140 
1141 void SAL_CALL SlideshowImpl::removeSlideShowListener( const Reference< XSlideShowListener >& xListener )
1142 {
1143     if( mxListenerProxy.is() )
1144         mxListenerProxy->removeSlideShowListener( xListener );
1145 }
1146 
1147 void SlideshowImpl::slideEnded(const bool bReverse)
1148 {
1149     if (bReverse)
1150         gotoPreviousSlide(true);
1151     else
1152         gotoNextSlide();
1153 }
1154 
1155 bool SlideshowImpl::swipe(const CommandSwipeData &rSwipeData)
1156 {
1157     if (mbUsePen || mnContextMenuEvent)
1158         return false;
1159     double nVelocityX = rSwipeData.getVelocityX();
1160     // tdf#108475 make it swipe only if some reasonable movement was involved
1161     if (fabs(nVelocityX) < 50)
1162         return false;
1163     if (nVelocityX > 0)
1164     {
1165         gotoPreviousSlide();
1166     }
1167     else
1168     {
1169         gotoNextEffect();
1170     }
1171     //a swipe is followed by a mouse up, tell the view to ignore that mouse up as we've reacted
1172     //to the swipe instead
1173     mxView->ignoreNextMouseReleased();
1174     return true;
1175 }
1176 
1177 bool SlideshowImpl::longpress(const CommandLongPressData &rLongPressData)
1178 {
1179     if (mnContextMenuEvent)
1180         return false;
1181 
1182     maPopupMousePos = Point(rLongPressData.getX(), rLongPressData.getY());
1183     mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
1184 
1185     return true;
1186 }
1187 
1188 void SlideshowImpl::removeShapeEvents()
1189 {
1190     if( !(mxShow.is() && mxListenerProxy.is()) )
1191         return;
1192 
1193     try
1194     {
1195         for( const auto& rEntry : maShapeEventMap )
1196         {
1197             mxListenerProxy->removeShapeEventListener( rEntry.first );
1198             mxShow->setShapeCursor( rEntry.first, awt::SystemPointer::ARROW );
1199         }
1200 
1201         maShapeEventMap.clear();
1202     }
1203     catch( Exception& )
1204     {
1205         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::removeShapeEvents()" );
1206     }
1207 }
1208 
1209 void SlideshowImpl::registerShapeEvents(sal_Int32 nSlideNumber)
1210 {
1211     if( nSlideNumber < 0 )
1212         return;
1213 
1214     try
1215     {
1216         Reference< XDrawPagesSupplier > xDrawPages( mxModel, UNO_QUERY_THROW );
1217         Reference< XIndexAccess > xPages( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
1218 
1219         Reference< XShapes > xDrawPage;
1220         xPages->getByIndex(nSlideNumber) >>= xDrawPage;
1221 
1222         if( xDrawPage.is() )
1223         {
1224             Reference< XMasterPageTarget > xMasterPageTarget( xDrawPage, UNO_QUERY );
1225             if( xMasterPageTarget.is() )
1226             {
1227                 Reference< XShapes > xMasterPage = xMasterPageTarget->getMasterPage();
1228                 if( xMasterPage.is() )
1229                     registerShapeEvents( xMasterPage );
1230             }
1231             registerShapeEvents( xDrawPage );
1232         }
1233     }
1234     catch( Exception& )
1235     {
1236         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::registerShapeEvents()" );
1237     }
1238 }
1239 
1240 void SlideshowImpl::registerShapeEvents( Reference< XShapes > const & xShapes )
1241 {
1242     try
1243     {
1244         const sal_Int32 nShapeCount = xShapes->getCount();
1245         sal_Int32 nShape;
1246         for( nShape = 0; nShape < nShapeCount; nShape++ )
1247         {
1248             Reference< XShape > xShape;
1249             xShapes->getByIndex( nShape ) >>= xShape;
1250 
1251             if( xShape.is() && xShape->getShapeType() == "com.sun.star.drawing.GroupShape" )
1252             {
1253                 Reference< XShapes > xSubShapes( xShape, UNO_QUERY );
1254                 if( xSubShapes.is() )
1255                     registerShapeEvents( xSubShapes );
1256             }
1257 
1258             Reference< XPropertySet > xSet( xShape, UNO_QUERY );
1259             if( !xSet.is() )
1260                 continue;
1261 
1262             Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
1263             if( !xSetInfo.is() || !xSetInfo->hasPropertyByName( gsOnClick ) )
1264                 continue;
1265 
1266             WrappedShapeEventImplPtr pEvent = std::make_shared<WrappedShapeEventImpl>();
1267             xSet->getPropertyValue( gsOnClick ) >>= pEvent->meClickAction;
1268 
1269             switch( pEvent->meClickAction )
1270             {
1271             case ClickAction_PREVPAGE:
1272             case ClickAction_NEXTPAGE:
1273             case ClickAction_FIRSTPAGE:
1274             case ClickAction_LASTPAGE:
1275             case ClickAction_STOPPRESENTATION:
1276                 break;
1277             case ClickAction_BOOKMARK:
1278                 if( xSetInfo->hasPropertyByName( gsBookmark ) )
1279                     xSet->getPropertyValue( gsBookmark ) >>= pEvent->maStrBookmark;
1280                 if( getSlideNumberForBookmark( pEvent->maStrBookmark ) == -1 )
1281                     continue;
1282                 break;
1283             case ClickAction_DOCUMENT:
1284             case ClickAction_SOUND:
1285             case ClickAction_PROGRAM:
1286             case ClickAction_MACRO:
1287                 if( xSetInfo->hasPropertyByName( gsBookmark ) )
1288                     xSet->getPropertyValue( gsBookmark ) >>= pEvent->maStrBookmark;
1289                 break;
1290             case ClickAction_VERB:
1291                 if( xSetInfo->hasPropertyByName( gsVerb ) )
1292                     xSet->getPropertyValue( gsVerb ) >>= pEvent->mnVerb;
1293                 break;
1294             default:
1295                 continue; // skip all others
1296             }
1297 
1298             maShapeEventMap[ xShape ] = pEvent;
1299 
1300             if( mxListenerProxy.is() )
1301                 mxListenerProxy->addShapeEventListener( xShape );
1302             mxShow->setShapeCursor( xShape, awt::SystemPointer::REFHAND );
1303         }
1304     }
1305     catch( Exception& )
1306     {
1307         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::registerShapeEvents()" );
1308     }
1309 }
1310 
1311 void SlideshowImpl::displayCurrentSlide (const bool bSkipAllMainSequenceEffects)
1312 {
1313     stopSound();
1314     removeShapeEvents();
1315 
1316     if( mpSlideController && mxShow.is() )
1317     {
1318         Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(),
1319                                                     UNO_QUERY_THROW );
1320         mpSlideController->displayCurrentSlide( mxShow, xDrawPages, bSkipAllMainSequenceEffects );
1321         registerShapeEvents(mpSlideController->getCurrentSlideNumber());
1322         update();
1323 
1324     }
1325     // send out page change event and notify to update all acc info for current page
1326     if (mpViewShell)
1327     {
1328         sal_Int32 currentPageIndex = getCurrentSlideIndex();
1329         mpViewShell->fireSwitchCurrentPage(currentPageIndex);
1330         mpViewShell->NotifyAccUpdate();
1331     }
1332 }
1333 
1334 void SlideshowImpl::endPresentation()
1335 {
1336     if( maPresSettings.mbMouseAsPen)
1337     {
1338         Reference< XMultiServiceFactory > xDocFactory(mpDoc->getUnoModel(), UNO_QUERY );
1339         if( xDocFactory.is() )
1340             mxShow->registerUserPaintPolygons(xDocFactory);
1341     }
1342 
1343     if( !mnEndShowEvent )
1344         mnEndShowEvent = Application::PostUserEvent( LINK(this, SlideshowImpl, endPresentationHdl) );
1345 }
1346 
1347 IMPL_LINK_NOARG(SlideshowImpl, endPresentationHdl, void*, void)
1348 {
1349     mnEndShowEvent = nullptr;
1350 
1351     stopSound();
1352 
1353     if( mxPresentation.is() )
1354         mxPresentation->end();
1355 }
1356 
1357 void SAL_CALL SlideshowImpl::pause()
1358 {
1359     SolarMutexGuard aSolarGuard;
1360 
1361     if( mbIsPaused )
1362         return;
1363 
1364     try
1365     {
1366         mbIsPaused = true;
1367         if( mxShow.is() )
1368         {
1369             mxShow->pause(true);
1370 
1371             if( mxListenerProxy.is() )
1372                 mxListenerProxy->paused();
1373         }
1374     }
1375     catch( Exception& )
1376     {
1377         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::pause()" );
1378     }
1379 }
1380 
1381 void SAL_CALL SlideshowImpl::resume()
1382 {
1383     SolarMutexGuard aSolarGuard;
1384 
1385     if( mbIsPaused ) try
1386     {
1387         if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK || mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
1388         {
1389             mpShowWindow->RestartShow();
1390         }
1391         else
1392         {
1393             mbIsPaused = false;
1394             if( mxShow.is() )
1395             {
1396                 mxShow->pause(false);
1397                 update();
1398 
1399                 if( mxListenerProxy.is() )
1400                     mxListenerProxy->resumed();
1401             }
1402         }
1403     }
1404     catch( Exception& )
1405     {
1406         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::resume()" );
1407     }
1408 #ifdef ENABLE_SDREMOTE
1409     RemoteServer::presentationStarted( this );
1410 #endif
1411 }
1412 
1413 sal_Bool SAL_CALL SlideshowImpl::isPaused()
1414 {
1415     SolarMutexGuard aSolarGuard;
1416     return mbIsPaused;
1417 }
1418 
1419 void SAL_CALL SlideshowImpl::blankScreen( sal_Int32 nColor )
1420 {
1421     SolarMutexGuard aSolarGuard;
1422 
1423     if( mpShowWindow && mpSlideController )
1424     {
1425         if( mpShowWindow->SetBlankMode( mpSlideController->getCurrentSlideIndex(), Color(ColorTransparency, nColor) ) )
1426         {
1427             pause();
1428         }
1429     }
1430 }
1431 
1432 // XShapeEventListener
1433 
1434 void SlideshowImpl::click( const Reference< XShape >& xShape )
1435 {
1436     SolarMutexGuard aSolarGuard;
1437 
1438     WrappedShapeEventImplPtr pEvent = maShapeEventMap[xShape];
1439     if( !pEvent )
1440         return;
1441 
1442     switch( pEvent->meClickAction )
1443     {
1444     case ClickAction_PREVPAGE:          gotoPreviousSlide();        break;
1445     case ClickAction_NEXTPAGE:          gotoNextSlide();            break;
1446     case ClickAction_FIRSTPAGE:         gotoFirstSlide();           break;
1447     case ClickAction_LASTPAGE:          gotoLastSlide();            break;
1448     case ClickAction_STOPPRESENTATION:  endPresentation();          break;
1449     case ClickAction_BOOKMARK:
1450     {
1451         gotoBookmark( pEvent->maStrBookmark );
1452     }
1453     break;
1454     case ClickAction_SOUND:
1455     {
1456 #if HAVE_FEATURE_AVMEDIA
1457         try
1458         {
1459             mxPlayer.set(avmedia::MediaWindow::createPlayer(pEvent->maStrBookmark, ""/*TODO?*/), uno::UNO_SET_THROW );
1460             mxPlayer->start();
1461         }
1462         catch( uno::Exception& )
1463         {
1464             TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::click()" );
1465         }
1466 #endif
1467     }
1468     break;
1469 
1470     case ClickAction_DOCUMENT:
1471     {
1472         OUString aBookmark( pEvent->maStrBookmark );
1473 
1474         sal_Int32 nPos = aBookmark.indexOf( '#' );
1475         if( nPos >= 0 )
1476         {
1477             OUString aURL( aBookmark.copy( 0, nPos+1 ) );
1478             OUString aName( aBookmark.copy( nPos+1 ) );
1479             aURL += getUiNameFromPageApiNameImpl( aName );
1480             aBookmark = aURL;
1481         }
1482 
1483         mpDocSh->OpenBookmark( aBookmark );
1484     }
1485     break;
1486 
1487     case ClickAction_PROGRAM:
1488     {
1489         INetURLObject aURL(
1490             ::URIHelper::SmartRel2Abs(
1491                 INetURLObject(mpDocSh->GetMedium()->GetBaseURL()),
1492                 pEvent->maStrBookmark, ::URIHelper::GetMaybeFileHdl(), true,
1493                 false, INetURLObject::EncodeMechanism::WasEncoded,
1494                 INetURLObject::DecodeMechanism::Unambiguous ) );
1495 
1496         if( INetProtocol::File == aURL.GetProtocol() )
1497         {
1498             SfxStringItem aUrl( SID_FILE_NAME, aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1499             SfxBoolItem aBrowsing( SID_BROWSE, true );
1500 
1501             SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1502             if (pViewFrm)
1503             {
1504                 SfxUnoFrameItem aDocFrame(SID_FILLFRAME, pViewFrm->GetFrame().GetFrameInterface());
1505                 pViewFrm->GetDispatcher()->ExecuteList( SID_OPENDOC,
1506                     SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
1507                     { &aUrl, &aBrowsing }, { &aDocFrame } );
1508             }
1509         }
1510     }
1511     break;
1512 
1513 #if HAVE_FEATURE_SCRIPTING
1514     case presentation::ClickAction_MACRO:
1515     {
1516         const OUString aMacro( pEvent->maStrBookmark );
1517 
1518         if ( SfxApplication::IsXScriptURL( aMacro ) )
1519         {
1520             Any aRet;
1521             Sequence< sal_Int16 > aOutArgsIndex;
1522             Sequence< Any > aOutArgs;
1523             Sequence< Any >* pInArgs = new Sequence< Any >(0);
1524             mpDocSh->CallXScript( aMacro, *pInArgs, aRet, aOutArgsIndex, aOutArgs);
1525         }
1526         else
1527         {
1528             // aMacro has the following syntax:
1529             // "Macroname.Modulname.Libname.Documentname" or
1530             // "Macroname.Modulname.Libname.Applicationname"
1531             sal_Int32 nIdx{ 0 };
1532             const std::u16string_view aMacroName = o3tl::getToken(aMacro, 0, '.', nIdx);
1533             const std::u16string_view aModulName = o3tl::getToken(aMacro, 0, '.', nIdx);
1534 
1535             // todo: is the limitation still given that only
1536             // Modulname+Macroname can be used here?
1537             OUString aExecMacro = OUString::Concat(aModulName) + "." + aMacroName;
1538             mpDocSh->GetBasic()->Call(aExecMacro);
1539         }
1540     }
1541     break;
1542 #endif
1543 
1544     case ClickAction_VERB:
1545     {
1546         // todo, better do it async?
1547         SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
1548         SdrOle2Obj* pOleObject = dynamic_cast< SdrOle2Obj* >(pObj);
1549         if (pOleObject && mpViewShell )
1550             mpViewShell->ActivateObject(pOleObject, pEvent->mnVerb);
1551     }
1552     break;
1553     default:
1554         break;
1555     }
1556 }
1557 
1558 sal_Int32 SlideshowImpl::getSlideNumberForBookmark( const OUString& rStrBookmark )
1559 {
1560     bool bIsMasterPage;
1561     OUString aBookmark = getUiNameFromPageApiNameImpl( rStrBookmark );
1562     sal_uInt16 nPgNum = mpDoc->GetPageByName( aBookmark, bIsMasterPage );
1563 
1564     if( nPgNum == SDRPAGE_NOTFOUND )
1565     {
1566         // Is the bookmark an object?
1567         SdrObject* pObj = mpDoc->GetObj( aBookmark );
1568 
1569         if( pObj )
1570         {
1571             nPgNum = pObj->getSdrPageFromSdrObject()->GetPageNum();
1572             bIsMasterPage = pObj->getSdrPageFromSdrObject()->IsMasterPage();
1573         }
1574     }
1575 
1576     if( (nPgNum == SDRPAGE_NOTFOUND) || bIsMasterPage || static_cast<SdPage*>(mpDoc->GetPage(nPgNum))->GetPageKind() != PageKind::Standard )
1577         return -1;
1578 
1579     return ( nPgNum - 1) >> 1;
1580 }
1581 
1582 void SlideshowImpl::hyperLinkClicked( OUString const& aHyperLink )
1583 {
1584     OUString aBookmark( aHyperLink );
1585 
1586     sal_Int32 nPos = aBookmark.indexOf( '#' );
1587     if( nPos >= 0 )
1588     {
1589         OUString aURL( aBookmark.copy( 0, nPos+1 ) );
1590         OUString aName( aBookmark.copy( nPos+1 ) );
1591         aURL += getUiNameFromPageApiNameImpl( aName );
1592         aBookmark = aURL;
1593     }
1594 
1595     mpDocSh->OpenBookmark( aBookmark );
1596 }
1597 
1598 void SlideshowImpl::displaySlideNumber( sal_Int32 nSlideNumber )
1599 {
1600     if( mpSlideController )
1601     {
1602         if( mpSlideController->jumpToSlideNumber( nSlideNumber ) )
1603         {
1604             displayCurrentSlide();
1605         }
1606     }
1607 }
1608 
1609 /** nSlideIndex == -1 displays current slide again */
1610 void SlideshowImpl::displaySlideIndex( sal_Int32 nSlideIndex )
1611 {
1612     if( mpSlideController )
1613     {
1614         if( (nSlideIndex == -1) || mpSlideController->jumpToSlideIndex( nSlideIndex ) )
1615         {
1616             displayCurrentSlide();
1617         }
1618     }
1619 }
1620 
1621 void SlideshowImpl::jumpToBookmark( const OUString& sBookmark )
1622 {
1623     sal_Int32 nSlideNumber = getSlideNumberForBookmark( sBookmark );
1624     if( nSlideNumber != -1 )
1625         displaySlideNumber( nSlideNumber );
1626 }
1627 
1628 sal_Int32 SlideshowImpl::getCurrentSlideNumber() const
1629 {
1630     return mpSlideController ? mpSlideController->getCurrentSlideNumber() : -1;
1631 }
1632 
1633 sal_Bool SAL_CALL SlideshowImpl::isEndless()
1634 {
1635     SolarMutexGuard aSolarGuard;
1636     return maPresSettings.mbEndless;
1637 }
1638 
1639 void SlideshowImpl::update()
1640 {
1641     startUpdateTimer();
1642 }
1643 
1644 void SlideshowImpl::startUpdateTimer()
1645 {
1646     SolarMutexGuard aSolarGuard;
1647     maUpdateTimer.SetTimeout( 0 );
1648     maUpdateTimer.Start();
1649 }
1650 
1651 /** this timer is called 20ms after a new slide was displayed.
1652     This is used to unfreeze user input that was disabled after
1653     slide change to skip input that was buffered during slide
1654     transition preparation */
1655 IMPL_LINK_NOARG(SlideshowImpl, ReadyForNextInputHdl, Timer *, void)
1656 {
1657     mbInputFreeze = false;
1658 }
1659 
1660 /** if I catch someone someday who calls this method by hand
1661     and not by using the timer, I will personally punish this
1662     person seriously, even if this person is me.
1663 */
1664 IMPL_LINK_NOARG(SlideshowImpl, updateHdl, Timer *, void)
1665 {
1666     updateSlideShow();
1667 }
1668 
1669 void SlideshowImpl::updateSlideShow()
1670 {
1671     // prevent me from deletion when recursing (App::EnableYieldMode does)
1672     const rtl::Reference<SlideshowImpl> xKeepAlive(this);
1673 
1674     Reference< XSlideShow > xShow( mxShow );
1675     if ( ! xShow.is())
1676         return;
1677 
1678     try
1679     {
1680         double fUpdate = 0.0;
1681         if( !xShow->update(fUpdate) )
1682             fUpdate = -1.0;
1683 
1684         if (mxShow.is() && (fUpdate >= 0.0))
1685         {
1686             if (::basegfx::fTools::equalZero(fUpdate))
1687             {
1688                 // Make sure idle tasks don't starve when we don't have to wait.
1689                 // Don't process any events generated after invoking the function.
1690                 Application::Reschedule(/*bHandleAllCurrentEvents=*/true);
1691             }
1692             else
1693             {
1694                 // Avoid busy loop when the previous call to update()
1695                 // returns a small positive number but not 0 (which is
1696                 // handled above).  Also, make sure that calls to update()
1697                 // have a minimum frequency.
1698                 // => Allow up to 60 frames per second.  Call at least once
1699                 // every 4 seconds.
1700                 const static sal_Int32 nMaximumFrameCount (60);
1701                 const static double nMinimumTimeout (1.0 / nMaximumFrameCount);
1702                 const static double nMaximumTimeout (4.0);
1703                 fUpdate = std::clamp(fUpdate, nMinimumTimeout, nMaximumTimeout);
1704 
1705                 // Make sure that the maximum frame count has not been set
1706                 // too high (only then conversion to milliseconds and long
1707                 // integer may lead to zero value.)
1708                 OSL_ASSERT(static_cast<sal_uLong>(fUpdate * 1000.0) > 0);
1709             }
1710 
1711             // Use our high resolution timers for the asynchronous callback.
1712             maUpdateTimer.SetTimeout(static_cast<sal_uLong>(fUpdate * 1000.0));
1713             maUpdateTimer.Start();
1714         }
1715     }
1716     catch( Exception& )
1717     {
1718         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::updateSlideShow()" );
1719     }
1720 }
1721 
1722 bool SlideshowImpl::keyInput(const KeyEvent& rKEvt)
1723 {
1724     if( !mxShow.is() || mbInputFreeze )
1725         return false;
1726 
1727     bool bRet = true;
1728 
1729     try
1730     {
1731         const int nKeyCode = rKEvt.GetKeyCode().GetCode();
1732         switch( nKeyCode )
1733         {
1734             case awt::Key::CONTEXTMENU:
1735                 if( !mnContextMenuEvent )
1736                 {
1737                     if( mpShowWindow )
1738                         maPopupMousePos = mpShowWindow->GetPointerState().maPos;
1739                     mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
1740                 }
1741                 break;
1742 
1743             // cancel show
1744             case KEY_ESCAPE:
1745             case KEY_SUBTRACT:
1746                 // in case the user cancels the presentation, switch to current slide
1747                 // in edit mode
1748                 if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
1749                 {
1750                     if( mpSlideController->getCurrentSlideNumber() != -1 )
1751                         mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
1752                 }
1753                 endPresentation();
1754                 break;
1755 
1756             // advance show
1757             case KEY_PAGEDOWN:
1758                 if(rKEvt.GetKeyCode().IsMod2())
1759                 {
1760                     gotoNextSlide();
1761                     break;
1762                 }
1763                 [[fallthrough]];
1764             case KEY_SPACE:
1765             case KEY_RIGHT:
1766             case KEY_DOWN:
1767                 gotoNextEffect();
1768                 break;
1769 
1770             case KEY_RETURN:
1771             {
1772                 if( !maCharBuffer.isEmpty() )
1773                 {
1774                     if( mpSlideController )
1775                     {
1776                         if( mpSlideController->jumpToSlideNumber( maCharBuffer.toInt32() - 1 ) )
1777                             displayCurrentSlide();
1778                     }
1779                     maCharBuffer.clear();
1780                 }
1781                 else
1782                 {
1783                     gotoNextEffect();
1784                 }
1785             }
1786             break;
1787 
1788             // numeric: add to buffer
1789             case KEY_0:
1790             case KEY_1:
1791             case KEY_2:
1792             case KEY_3:
1793             case KEY_4:
1794             case KEY_5:
1795             case KEY_6:
1796             case KEY_7:
1797             case KEY_8:
1798             case KEY_9:
1799                 maCharBuffer += OUStringChar( rKEvt.GetCharCode() );
1800                 break;
1801 
1802             case KEY_PAGEUP:
1803                 if(rKEvt.GetKeyCode().IsMod2())
1804                 {
1805                     gotoPreviousSlide();
1806                     break;
1807                 }
1808                 [[fallthrough]];
1809             case KEY_LEFT:
1810             case KEY_UP:
1811             case KEY_BACKSPACE:
1812                 gotoPreviousEffect();
1813                 break;
1814 
1815             case KEY_P:
1816                 setUsePen( !mbUsePen );
1817                 break;
1818 
1819             case KEY_E:
1820                 setEraseAllInk( true );
1821                 updateSlideShow();
1822                 break;
1823 
1824             case KEY_HOME:
1825                 gotoFirstSlide();
1826                 break;
1827 
1828             case KEY_END:
1829                 gotoLastSlide();
1830                 break;
1831 
1832             case KEY_B:
1833             case KEY_W:
1834             case KEY_POINT:
1835             case KEY_COMMA:
1836             {
1837                 blankScreen( ((nKeyCode == KEY_W ) || (nKeyCode == KEY_COMMA)) ? 0x00ffffff : 0x00000000 );
1838             }
1839             break;
1840 
1841             default:
1842                 bRet = false;
1843             break;
1844         }
1845     }
1846     catch( Exception& )
1847     {
1848         bRet = false;
1849         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::keyInput()" );
1850     }
1851 
1852     return bRet;
1853 }
1854 
1855 IMPL_LINK( SlideshowImpl, EventListenerHdl, VclSimpleEvent&, rSimpleEvent, void )
1856 {
1857     if( !mxShow.is() || mbInputFreeze )
1858         return;
1859 
1860     if( !((rSimpleEvent.GetId() == VclEventId::WindowCommand) && static_cast<VclWindowEvent*>(&rSimpleEvent)->GetData()) )
1861         return;
1862 
1863     const CommandEvent& rEvent = *static_cast<const CommandEvent*>(static_cast<VclWindowEvent*>(&rSimpleEvent)->GetData());
1864 
1865     if( rEvent.GetCommand() != CommandEventId::Media )
1866         return;
1867 
1868     CommandMediaData* pMediaData = rEvent.GetMediaData();
1869     pMediaData->SetPassThroughToOS(false);
1870     switch (pMediaData->GetMediaId())
1871     {
1872 #if defined( MACOSX )
1873     case MediaCommand::Menu:
1874         if( !mnContextMenuEvent )
1875         {
1876             if( mpShowWindow )
1877                 maPopupMousePos = mpShowWindow->GetPointerState().maPos;
1878             mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
1879         }
1880         break;
1881     case MediaCommand::VolumeDown:
1882         gotoPreviousSlide();
1883         break;
1884     case MediaCommand::VolumeUp:
1885         gotoNextEffect();
1886         break;
1887 #endif
1888     case MediaCommand::NextTrack:
1889         gotoNextEffect();
1890         break;
1891     case MediaCommand::Pause:
1892         if( !mbIsPaused )
1893             blankScreen(0);
1894         break;
1895     case MediaCommand::Play:
1896         if( mbIsPaused )
1897             resume();
1898         break;
1899 
1900     case MediaCommand::PlayPause:
1901         if( mbIsPaused )
1902             resume();
1903         else
1904             blankScreen(0);
1905         break;
1906     case MediaCommand::PreviousTrack:
1907         gotoPreviousSlide();
1908         break;
1909     case MediaCommand::NextTrackHold:
1910         gotoLastSlide();
1911         break;
1912 
1913     case MediaCommand::Rewind:
1914         gotoFirstSlide();
1915         break;
1916     case MediaCommand::Stop:
1917         // in case the user cancels the presentation, switch to current slide
1918         // in edit mode
1919         if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
1920         {
1921             if( mpSlideController->getCurrentSlideNumber() != -1 )
1922                 mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
1923         }
1924         endPresentation();
1925         break;
1926     default:
1927         pMediaData->SetPassThroughToOS(true);
1928         break;
1929     }
1930 }
1931 
1932 void SlideshowImpl::mouseButtonUp(const MouseEvent& rMEvt)
1933 {
1934     if( rMEvt.IsRight() && !mnContextMenuEvent )
1935     {
1936         maPopupMousePos = rMEvt.GetPosPixel();
1937         mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
1938     }
1939 }
1940 
1941 IMPL_LINK_NOARG(SlideshowImpl, ContextMenuHdl, void*, void)
1942 {
1943     mnContextMenuEvent = nullptr;
1944 
1945     if (mpSlideController == nullptr)
1946         return;
1947 
1948     mbWasPaused = mbIsPaused;
1949     if( !mbWasPaused )
1950         pause();
1951 
1952     std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/simpress/ui/slidecontextmenu.ui"));
1953     std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
1954     OUString sNextImage(BMP_MENU_NEXT), sPrevImage(BMP_MENU_PREV);
1955     xMenu->insert(0, "next", SdResId(RID_SVXSTR_MENU_NEXT), &sNextImage, nullptr, nullptr, TRISTATE_INDET);
1956     xMenu->insert(1, "prev", SdResId(RID_SVXSTR_MENU_PREV), &sPrevImage, nullptr, nullptr, TRISTATE_INDET);
1957 
1958     // Adding button to display if in Pen  mode
1959     xMenu->set_active("pen", mbUsePen);
1960 
1961     const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
1962     xMenu->set_visible("next", mpSlideController->getNextSlideIndex() != -1);
1963     xMenu->set_visible("prev", (mpSlideController->getPreviousSlideIndex() != -1 ) || (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK));
1964     xMenu->set_visible("edit", mpViewShell->GetDoc()->IsStartWithPresentation());
1965 
1966     std::unique_ptr<weld::Menu> xPageMenu(xBuilder->weld_menu("gotomenu"));
1967     OUString sFirstImage(BMP_MENU_FIRST), sLastImage(BMP_MENU_LAST);
1968     xPageMenu->insert(0, "first", SdResId(RID_SVXSTR_MENU_FIRST), &sFirstImage, nullptr, nullptr, TRISTATE_INDET);
1969     xPageMenu->insert(1, "last", SdResId(RID_SVXSTR_MENU_LAST), &sLastImage, nullptr, nullptr, TRISTATE_INDET);
1970 
1971     // populate slide goto list
1972     const sal_Int32 nPageNumberCount = mpSlideController->getSlideNumberCount();
1973     if( nPageNumberCount <= 1 )
1974     {
1975         xMenu->set_visible("goto", false);
1976     }
1977     else
1978     {
1979         sal_Int32 nCurrentSlideNumber = mpSlideController->getCurrentSlideNumber();
1980         if( (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
1981             nCurrentSlideNumber = -1;
1982 
1983         xPageMenu->set_visible("first", mpSlideController->getSlideNumber(0) != nCurrentSlideNumber);
1984         xPageMenu->set_visible("last", mpSlideController->getSlideNumber(mpSlideController->getSlideIndexCount() - 1) != nCurrentSlideNumber);
1985 
1986         sal_Int32 nPageNumber;
1987 
1988         for( nPageNumber = 0; nPageNumber < nPageNumberCount; nPageNumber++ )
1989         {
1990             if( mpSlideController->isVisibleSlideNumber( nPageNumber ) )
1991             {
1992                 SdPage* pPage = mpDoc->GetSdPage(static_cast<sal_uInt16>(nPageNumber), PageKind::Standard);
1993                 if (pPage)
1994                 {
1995                     OUString sId(OUString::number(CM_SLIDES + nPageNumber));
1996                     xPageMenu->append_check(sId, pPage->GetName());
1997                     if (nPageNumber == nCurrentSlideNumber)
1998                         xPageMenu->set_active(sId.toUtf8(), true);
1999                 }
2000             }
2001         }
2002     }
2003 
2004     std::unique_ptr<weld::Menu> xBlankMenu(xBuilder->weld_menu("screenmenu"));
2005 
2006     if (mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK)
2007     {
2008         xBlankMenu->set_active((mpShowWindow->GetBlankColor() == COL_WHITE) ? "white" : "black", true);
2009     }
2010 
2011     std::unique_ptr<weld::Menu> xWidthMenu(xBuilder->weld_menu("widthmenu"));
2012 
2013     // populate color width list
2014     sal_Int32 nIterator;
2015     double nWidth;
2016 
2017     nWidth = 4.0;
2018     for( nIterator = 1; nIterator < 6; nIterator++)
2019     {
2020         switch(nIterator)
2021         {
2022             case 1:
2023                 nWidth = 4.0;
2024                 break;
2025             case 2:
2026                 nWidth = 100.0;
2027                 break;
2028             case 3:
2029                 nWidth = 150.0;
2030                 break;
2031             case 4:
2032                 nWidth = 200.0;
2033                 break;
2034             case 5:
2035                 nWidth = 400.0;
2036                 break;
2037             default:
2038                 break;
2039         }
2040 
2041         if (nWidth == mdUserPaintStrokeWidth)
2042             xWidthMenu->set_active(OString::number(nWidth), true);
2043     }
2044 
2045     ::tools::Rectangle aRect(maPopupMousePos, Size(1,1));
2046     weld::Window* pParent = weld::GetPopupParent(*mpShowWindow, aRect);
2047     ContextMenuSelectHdl(xMenu->popup_at_rect(pParent, aRect));
2048 
2049     if( mxView.is() )
2050         mxView->ignoreNextMouseReleased();
2051 
2052     if( !mbWasPaused )
2053         resume();
2054 }
2055 
2056 void SlideshowImpl::ContextMenuSelectHdl(std::string_view rMenuId)
2057 {
2058     if (rMenuId == "prev")
2059     {
2060         gotoPreviousSlide();
2061         mbWasPaused = false;
2062     }
2063     else if(rMenuId == "next")
2064     {
2065         gotoNextSlide();
2066         mbWasPaused = false;
2067     }
2068     else if (rMenuId == "first")
2069     {
2070         gotoFirstSlide();
2071         mbWasPaused = false;
2072     }
2073     else if (rMenuId == "last")
2074     {
2075         gotoLastSlide();
2076         mbWasPaused = false;
2077     }
2078     else if (rMenuId == "black" || rMenuId == "white")
2079     {
2080         const Color aBlankColor(rMenuId == "white" ? COL_WHITE : COL_BLACK);
2081         if( mbWasPaused )
2082         {
2083             if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK )
2084             {
2085                 if( mpShowWindow->GetBlankColor() == aBlankColor )
2086                 {
2087                     mbWasPaused = false;
2088                     mpShowWindow->RestartShow();
2089                     return;
2090                 }
2091             }
2092             mpShowWindow->RestartShow();
2093         }
2094         if( mpShowWindow->SetBlankMode( mpSlideController->getCurrentSlideIndex(), aBlankColor ) )
2095         {
2096             pause();
2097             mbWasPaused = true;
2098         }
2099     }
2100     else if (rMenuId == "color")
2101     {
2102         //Open a color picker based on SvColorDialog
2103         ::Color aColor( ColorTransparency, mnUserPaintColor );
2104         SvColorDialog aColorDlg;
2105         aColorDlg.SetColor( aColor );
2106 
2107         if (aColorDlg.Execute(mpShowWindow->GetFrameWeld()))
2108         {
2109             aColor = aColorDlg.GetColor();
2110             setPenColor(sal_Int32(aColor));
2111         }
2112         mbWasPaused = false;
2113     }
2114     else if (rMenuId == "4")
2115     {
2116         setPenWidth(4.0);
2117         mbWasPaused = false;
2118     }
2119     else if (rMenuId == "100")
2120     {
2121         setPenWidth(100.0);
2122         mbWasPaused = false;
2123     }
2124     else if (rMenuId == "150")
2125     {
2126         setPenWidth(150.0);
2127         mbWasPaused = false;
2128     }
2129     else if (rMenuId == "200")
2130     {
2131         setPenWidth(200.0);
2132         mbWasPaused = false;
2133     }
2134     else if (rMenuId == "400")
2135     {
2136         setPenWidth(400.0);
2137         mbWasPaused = false;
2138     }
2139     else if (rMenuId == "erase")
2140     {
2141         setEraseAllInk(true);
2142         mbWasPaused = false;
2143     }
2144     else if (rMenuId == "pen")
2145     {
2146         setUsePen(!mbUsePen);
2147         mbWasPaused = false;
2148     }
2149     else if (rMenuId == "edit")
2150     {
2151         // When in autoplay mode (pps/ppsx), offer editing of the presentation
2152         // Turn autostart off, else Impress will close when exiting the Presentation
2153         mpViewShell->GetDoc()->SetExitAfterPresenting(false);
2154         if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
2155         {
2156             if( mpSlideController->getCurrentSlideNumber() != -1 )
2157             {
2158                 mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
2159             }
2160         }
2161         endPresentation();
2162     }
2163     else if (rMenuId == "end")
2164     {
2165         // in case the user cancels the presentation, switch to current slide
2166         // in edit mode
2167         if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
2168         {
2169             if( mpSlideController->getCurrentSlideNumber() != -1 )
2170             {
2171                 mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
2172             }
2173         }
2174         endPresentation();
2175     }
2176     else if (!rMenuId.empty())
2177     {
2178         sal_Int32 nPageNumber = o3tl::toInt32(rMenuId) - CM_SLIDES;
2179         const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
2180         if( (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
2181         {
2182             mpShowWindow->RestartShow( nPageNumber );
2183         }
2184         else if( nPageNumber != mpSlideController->getCurrentSlideNumber() )
2185         {
2186             displaySlideNumber( nPageNumber );
2187         }
2188         mbWasPaused = false;
2189     }
2190 }
2191 
2192 Reference< XSlideShow > SlideshowImpl::createSlideShow()
2193 {
2194     Reference< XSlideShow > xShow;
2195 
2196     try
2197     {
2198         Reference< uno::XComponentContext > xContext =
2199             ::comphelper::getProcessComponentContext();
2200 
2201         xShow.set( presentation::SlideShow::create(xContext), UNO_SET_THROW );
2202     }
2203     catch( uno::Exception& )
2204     {
2205         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::createSlideShow()" );
2206     }
2207 
2208     return xShow;
2209 }
2210 
2211 void SlideshowImpl::createSlideList( bool bAll, std::u16string_view rPresSlide )
2212 {
2213     const sal_uInt16 nSlideCount = mpDoc->GetSdPageCount( PageKind::Standard );
2214 
2215     if( !nSlideCount )
2216         return;
2217 
2218     SdCustomShow*   pCustomShow;
2219 
2220     if( mpDoc->GetCustomShowList() && maPresSettings.mbCustomShow )
2221         pCustomShow = mpDoc->GetCustomShowList()->GetCurObject();
2222     else
2223         pCustomShow = nullptr;
2224 
2225     // create animation slide controller
2226     AnimationSlideController::Mode eMode =
2227         ( pCustomShow && !pCustomShow->PagesVector().empty() ) ? AnimationSlideController::CUSTOM :
2228             (bAll ? AnimationSlideController::ALL : AnimationSlideController::FROM);
2229 
2230     Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
2231     Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
2232     mpSlideController = std::make_shared<AnimationSlideController>( xSlides, eMode );
2233 
2234     if( eMode != AnimationSlideController::CUSTOM )
2235     {
2236         sal_Int32 nFirstVisibleSlide = 0;
2237 
2238         // normal presentation
2239         if( !rPresSlide.empty() )
2240         {
2241             sal_Int32 nSlide;
2242             bool bTakeNextAvailable = false;
2243 
2244             for( nSlide = 0, nFirstVisibleSlide = -1;
2245                 ( nSlide < nSlideCount ) && ( -1 == nFirstVisibleSlide ); nSlide++ )
2246             {
2247                 SdPage* pTestSlide = mpDoc->GetSdPage( static_cast<sal_uInt16>(nSlide), PageKind::Standard );
2248 
2249                 if( pTestSlide->GetName() == rPresSlide )
2250                 {
2251                     if( pTestSlide->IsExcluded() )
2252                         bTakeNextAvailable = true;
2253                     else
2254                         nFirstVisibleSlide = nSlide;
2255                 }
2256                 else if( bTakeNextAvailable && !pTestSlide->IsExcluded() )
2257                     nFirstVisibleSlide = nSlide;
2258             }
2259 
2260             if( -1 == nFirstVisibleSlide )
2261                 nFirstVisibleSlide = 0;
2262         }
2263 
2264         for( sal_Int32 i = 0; i < nSlideCount; i++ )
2265         {
2266             bool bVisible = ! mpDoc->GetSdPage( static_cast<sal_uInt16>(i), PageKind::Standard )->IsExcluded();
2267             if( bVisible || (eMode == AnimationSlideController::ALL) )
2268                 mpSlideController->insertSlideNumber( i, bVisible );
2269         }
2270 
2271         mpSlideController->setStartSlideNumber( nFirstVisibleSlide );
2272     }
2273     else
2274     {
2275         if( meAnimationMode != ANIMATIONMODE_SHOW && !rPresSlide.empty() )
2276         {
2277             sal_Int32 nSlide;
2278             for( nSlide = 0; nSlide < nSlideCount; nSlide++ )
2279                 if( rPresSlide == mpDoc->GetSdPage( static_cast<sal_uInt16>(nSlide), PageKind::Standard )->GetName() )
2280                     break;
2281 
2282             if( nSlide < nSlideCount )
2283                 mpSlideController->insertSlideNumber( static_cast<sal_uInt16>(nSlide) );
2284         }
2285 
2286         for( const auto& rpPage : pCustomShow->PagesVector() )
2287         {
2288             const sal_uInt16 nSdSlide = ( rpPage->GetPageNum() - 1 ) / 2;
2289 
2290             if( ! mpDoc->GetSdPage( nSdSlide, PageKind::Standard )->IsExcluded())
2291                 mpSlideController->insertSlideNumber( nSdSlide );
2292         }
2293     }
2294 }
2295 
2296 typedef sal_uInt16 (*FncGetChildWindowId)();
2297 
2298 const FncGetChildWindowId aShowChildren[] =
2299 {
2300     &AnimationChildWindow::GetChildWindowId,
2301     &Svx3DChildWindow::GetChildWindowId,
2302     &SvxFontWorkChildWindow::GetChildWindowId,
2303     &SvxColorChildWindow::GetChildWindowId,
2304     &SvxSearchDialogWrapper::GetChildWindowId,
2305     &SvxBmpMaskChildWindow::GetChildWindowId,
2306     &SvxIMapDlgChildWindow::GetChildWindowId,
2307     &SvxHlinkDlgWrapper::GetChildWindowId,
2308     &SfxInfoBarContainerChild::GetChildWindowId
2309 };
2310 
2311 void SlideshowImpl::hideChildWindows()
2312 {
2313     mnChildMask = 0;
2314 
2315     if( ANIMATIONMODE_SHOW != meAnimationMode )
2316         return;
2317 
2318     SfxViewFrame* pViewFrame = getViewFrame();
2319 
2320     if( !pViewFrame )
2321         return;
2322 
2323     for( sal_uLong i = 0; i < SAL_N_ELEMENTS( aShowChildren ); i++ )
2324     {
2325         const sal_uInt16 nId = ( *aShowChildren[ i ] )();
2326 
2327         if( pViewFrame->GetChildWindow( nId ) )
2328         {
2329             pViewFrame->SetChildWindow( nId, false );
2330             mnChildMask |= ::tools::ULong(1) << i;
2331         }
2332     }
2333 }
2334 
2335 void SlideshowImpl::showChildWindows()
2336 {
2337     if( ANIMATIONMODE_SHOW == meAnimationMode )
2338     {
2339         SfxViewFrame* pViewFrame = getViewFrame();
2340         if( pViewFrame )
2341         {
2342             for( sal_uLong i = 0; i < SAL_N_ELEMENTS(aShowChildren); i++ )
2343             {
2344                 if( mnChildMask & ( ::tools::ULong(1) << i ) )
2345                     pViewFrame->SetChildWindow( ( *aShowChildren[ i ] )(), true );
2346             }
2347         }
2348     }
2349 }
2350 
2351 SfxViewFrame* SlideshowImpl::getViewFrame() const
2352 {
2353     return mpViewShell ? mpViewShell->GetViewFrame() : nullptr;
2354 }
2355 
2356 SfxDispatcher* SlideshowImpl::getDispatcher() const
2357 {
2358     return (mpViewShell && mpViewShell->GetViewFrame()) ? mpViewShell->GetViewFrame()->GetDispatcher() : nullptr;
2359 }
2360 
2361 SfxBindings* SlideshowImpl::getBindings() const
2362 {
2363     return (mpViewShell && mpViewShell->GetViewFrame()) ? &mpViewShell->GetViewFrame()->GetBindings() : nullptr;
2364 }
2365 
2366 void SlideshowImpl::resize( const Size& rSize )
2367 {
2368     maPresSize = rSize;
2369 
2370     if(mpShowWindow)
2371     {
2372         mpShowWindow->SetSizePixel( maPresSize );
2373         mpShowWindow->Show();
2374     }
2375 
2376     if( mxView.is() ) try
2377     {
2378         awt::WindowEvent aEvt;
2379         mxView->windowResized(aEvt);
2380     }
2381     catch( Exception& )
2382     {
2383         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::resize()" );
2384     }
2385 }
2386 
2387 void SlideshowImpl::setActiveXToolbarsVisible( bool bVisible )
2388 {
2389     // in case of ActiveX control the toolbars should not be visible if slide show runs in window mode
2390     // actually it runs always in window mode in case of ActiveX control
2391     if ( !(!maPresSettings.mbFullScreen && mpDocSh && mpDocSh->GetMedium()) )
2392         return;
2393 
2394     const SfxBoolItem* pItem = SfxItemSet::GetItem<SfxBoolItem>(mpDocSh->GetMedium()->GetItemSet(), SID_VIEWONLY, false);
2395     if ( !(pItem && pItem->GetValue()) )
2396         return;
2397 
2398     // this is a plugin/activex mode, no toolbars should be visible during slide show
2399     // after the end of slide show they should be visible again
2400     SfxViewFrame* pViewFrame = getViewFrame();
2401     if( !pViewFrame )
2402         return;
2403 
2404     try
2405     {
2406         Reference< frame::XLayoutManager > xLayoutManager;
2407         Reference< beans::XPropertySet > xFrameProps( pViewFrame->GetFrame().GetFrameInterface(), UNO_QUERY_THROW );
2408         if ( ( xFrameProps->getPropertyValue( "LayoutManager" )
2409                     >>= xLayoutManager )
2410           && xLayoutManager.is() )
2411         {
2412             xLayoutManager->setVisible( bVisible );
2413         }
2414     }
2415     catch( uno::Exception& )
2416     {}
2417 }
2418 
2419 void SAL_CALL SlideshowImpl::activate()
2420 {
2421     SolarMutexGuard aSolarGuard;
2422 
2423     maDeactivateTimer.Stop();
2424 
2425     if( mbActive || !mxShow.is() )
2426         return;
2427 
2428     mbActive = true;
2429 
2430     if( ANIMATIONMODE_SHOW == meAnimationMode )
2431     {
2432         if( mbAutoSaveWasOn )
2433             setAutoSaveState( false );
2434 
2435         if( mpShowWindow )
2436         {
2437             SfxViewFrame* pViewFrame = getViewFrame();
2438             SfxDispatcher* pDispatcher = pViewFrame ? pViewFrame->GetDispatcher() : nullptr;
2439 
2440             hideChildWindows();
2441 
2442             if( pDispatcher )
2443             {
2444                 // filter all forbidden slots
2445                 pDispatcher->SetSlotFilter( SfxSlotFilterState::ENABLED, pAllowed );
2446             }
2447 
2448             if( getBindings() )
2449                 getBindings()->InvalidateAll(true);
2450 
2451             mpShowWindow->GrabFocus();
2452         }
2453     }
2454 
2455     resume();
2456 }
2457 
2458 void SAL_CALL SlideshowImpl::deactivate()
2459 {
2460     SolarMutexGuard aSolarGuard;
2461 
2462     if( mbActive && mxShow.is() )
2463     {
2464         maDeactivateTimer.Start();
2465     }
2466 }
2467 
2468 IMPL_LINK_NOARG(SlideshowImpl, deactivateHdl, Timer *, void)
2469 {
2470     if( !(mbActive && mxShow.is()) )
2471         return;
2472 
2473     mbActive = false;
2474 
2475     pause();
2476 
2477     if( ANIMATIONMODE_SHOW == meAnimationMode )
2478     {
2479         if( mbAutoSaveWasOn )
2480             setAutoSaveState( true );
2481 
2482         if( mpShowWindow )
2483         {
2484             showChildWindows();
2485         }
2486     }
2487 }
2488 
2489 sal_Bool SAL_CALL SlideshowImpl::isActive()
2490 {
2491     SolarMutexGuard aSolarGuard;
2492     return mbActive;
2493 }
2494 
2495 void SlideshowImpl::setAutoSaveState( bool bOn)
2496 {
2497     try
2498     {
2499         uno::Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
2500 
2501         uno::Reference< util::XURLTransformer > xParser(util::URLTransformer::create(xContext));
2502         util::URL aURL;
2503         aURL.Complete = "vnd.sun.star.autorecovery:/setAutoSaveState";
2504         xParser->parseStrict(aURL);
2505 
2506         Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue("AutoSaveState", bOn) };
2507 
2508         uno::Reference< frame::XDispatch > xAutoSave = frame::theAutoRecovery::get(xContext);
2509         xAutoSave->dispatch(aURL, aArgs);
2510     }
2511     catch( Exception& )
2512     {
2513         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::setAutoSaveState()");
2514     }
2515 }
2516 
2517 Reference< XDrawPage > SAL_CALL SlideshowImpl::getCurrentSlide()
2518 {
2519     SolarMutexGuard aSolarGuard;
2520 
2521     Reference< XDrawPage > xSlide;
2522     if( mxShow.is() && mpSlideController )
2523     {
2524         sal_Int32 nSlide = getCurrentSlideNumber();
2525         if( (nSlide >= 0) && (nSlide < mpSlideController->getSlideNumberCount() ) )
2526             xSlide = mpSlideController->getSlideByNumber( nSlide );
2527     }
2528 
2529     return xSlide;
2530 }
2531 
2532 sal_Int32 SAL_CALL SlideshowImpl::getNextSlideIndex()
2533 {
2534     SolarMutexGuard aSolarGuard;
2535 
2536     if( mxShow.is() )
2537     {
2538         return mpSlideController->getNextSlideIndex();
2539     }
2540     else
2541     {
2542         return -1;
2543     }
2544 }
2545 
2546 sal_Int32 SAL_CALL SlideshowImpl::getCurrentSlideIndex()
2547 {
2548     return mpSlideController ? mpSlideController->getCurrentSlideIndex() : -1;
2549 }
2550 
2551 // css::presentation::XSlideShowController:
2552 
2553 ::sal_Int32 SAL_CALL SlideshowImpl::getSlideCount()
2554 {
2555     return mpSlideController ? mpSlideController->getSlideIndexCount() : 0;
2556 }
2557 
2558 Reference< XDrawPage > SAL_CALL SlideshowImpl::getSlideByIndex(::sal_Int32 Index)
2559 {
2560     if ((mpSlideController == nullptr) || (Index < 0)
2561         || (Index >= mpSlideController->getSlideIndexCount()))
2562         throw IndexOutOfBoundsException();
2563 
2564     return mpSlideController->getSlideByNumber( mpSlideController->getSlideNumber( Index ) );
2565 }
2566 
2567 sal_Bool SAL_CALL SlideshowImpl::getAlwaysOnTop()
2568 {
2569     SolarMutexGuard aSolarGuard;
2570     return maPresSettings.mbAlwaysOnTop;
2571 }
2572 
2573 void SAL_CALL SlideshowImpl::setAlwaysOnTop( sal_Bool bAlways )
2574 {
2575     SolarMutexGuard aSolarGuard;
2576     if( maPresSettings.mbAlwaysOnTop != bool(bAlways) )
2577     {
2578         maPresSettings.mbAlwaysOnTop = bAlways;
2579         // todo, can this be changed while running?
2580     }
2581 }
2582 
2583 sal_Bool SAL_CALL SlideshowImpl::isFullScreen()
2584 {
2585     SolarMutexGuard aSolarGuard;
2586     return maPresSettings.mbFullScreen;
2587 }
2588 
2589 sal_Bool SAL_CALL SlideshowImpl::getMouseVisible()
2590 {
2591     SolarMutexGuard aSolarGuard;
2592     return maPresSettings.mbMouseVisible;
2593 }
2594 
2595 void SAL_CALL SlideshowImpl::setMouseVisible( sal_Bool bVisible )
2596 {
2597     SolarMutexGuard aSolarGuard;
2598     if( maPresSettings.mbMouseVisible != bool(bVisible) )
2599     {
2600         maPresSettings.mbMouseVisible = bVisible;
2601         if( mpShowWindow )
2602             mpShowWindow->SetMouseAutoHide( !maPresSettings.mbMouseVisible );
2603     }
2604 }
2605 
2606 sal_Bool SAL_CALL SlideshowImpl::getUsePen()
2607 {
2608     SolarMutexGuard aSolarGuard;
2609     return mbUsePen;
2610 }
2611 
2612 void SAL_CALL SlideshowImpl::setUsePen( sal_Bool bMouseAsPen )
2613 {
2614     SolarMutexGuard aSolarGuard;
2615     mbUsePen = bMouseAsPen;
2616     if( !mxShow.is() )
2617         return;
2618 
2619     try
2620     {
2621         // For Pencolor;
2622         Any aValue;
2623         if( mbUsePen )
2624             aValue <<= mnUserPaintColor;
2625         beans::PropertyValue aPenProp;
2626         aPenProp.Name = "UserPaintColor";
2627         aPenProp.Value = aValue;
2628         mxShow->setProperty( aPenProp );
2629 
2630         //for StrokeWidth :
2631         if( mbUsePen )
2632         {
2633             beans::PropertyValue aPenPropWidth;
2634             aPenPropWidth.Name = "UserPaintStrokeWidth";
2635             aPenPropWidth.Value <<= mdUserPaintStrokeWidth;
2636             mxShow->setProperty( aPenPropWidth );
2637 
2638             // for Pen Mode
2639             beans::PropertyValue aPenPropSwitchPenMode;
2640             aPenPropSwitchPenMode.Name = "SwitchPenMode";
2641             aPenPropSwitchPenMode.Value <<= true;
2642             mxShow->setProperty( aPenPropSwitchPenMode );
2643         }
2644     }
2645     catch( Exception& )
2646     {
2647         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::setUsePen()" );
2648     }
2649 }
2650 
2651 double SAL_CALL SlideshowImpl::getPenWidth()
2652 {
2653     SolarMutexGuard aSolarGuard;
2654     return mdUserPaintStrokeWidth;
2655 }
2656 
2657 void SAL_CALL SlideshowImpl::setPenWidth( double dStrokeWidth )
2658 {
2659     SolarMutexGuard aSolarGuard;
2660     mdUserPaintStrokeWidth = dStrokeWidth;
2661     setUsePen( true ); // enable pen mode, update color and width
2662 }
2663 
2664 sal_Int32 SAL_CALL SlideshowImpl::getPenColor()
2665 {
2666     SolarMutexGuard aSolarGuard;
2667     return mnUserPaintColor;
2668 }
2669 
2670 void SAL_CALL SlideshowImpl::setPenColor( sal_Int32 nColor )
2671 {
2672     SolarMutexGuard aSolarGuard;
2673     mnUserPaintColor = nColor;
2674     setUsePen( true ); // enable pen mode, update color
2675 }
2676 
2677 void SAL_CALL SlideshowImpl::setEraseAllInk(sal_Bool bEraseAllInk)
2678 {
2679     if( !bEraseAllInk )
2680         return;
2681 
2682     SolarMutexGuard aSolarGuard;
2683     if( !mxShow.is() )
2684         return;
2685 
2686     try
2687     {
2688         beans::PropertyValue aPenPropEraseAllInk;
2689         aPenPropEraseAllInk.Name = "EraseAllInk";
2690         aPenPropEraseAllInk.Value <<= bEraseAllInk;
2691         mxShow->setProperty( aPenPropEraseAllInk );
2692     }
2693     catch( Exception& )
2694     {
2695         TOOLS_WARN_EXCEPTION( "sd.slideshow", "sd::SlideshowImpl::setEraseAllInk()" );
2696     }
2697 }
2698 
2699 // XSlideShowController Methods
2700 sal_Bool SAL_CALL SlideshowImpl::isRunning(  )
2701 {
2702     SolarMutexGuard aSolarGuard;
2703     return mxShow.is();
2704 }
2705 
2706 void SAL_CALL SlideshowImpl::gotoNextEffect(  )
2707 {
2708     SolarMutexGuard aSolarGuard;
2709 
2710     if( !(mxShow.is() && mpSlideController && mpShowWindow) )
2711         return;
2712 
2713     if( mbIsPaused )
2714         resume();
2715 
2716     const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
2717     if( eMode == SHOWWINDOWMODE_END )
2718     {
2719         endPresentation();
2720     }
2721     else if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
2722     {
2723         mpShowWindow->RestartShow();
2724     }
2725     else
2726     {
2727         mxShow->nextEffect();
2728         update();
2729     }
2730 }
2731 
2732 void SAL_CALL SlideshowImpl::gotoPreviousEffect(  )
2733 {
2734     SolarMutexGuard aSolarGuard;
2735 
2736     if( !(mxShow.is() && mpSlideController && mpShowWindow) )
2737         return;
2738 
2739     if( mbIsPaused )
2740         resume();
2741 
2742     const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
2743     if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
2744     {
2745         mpShowWindow->RestartShow();
2746     }
2747     else
2748     {
2749         mxShow->previousEffect();
2750         update();
2751     }
2752 }
2753 
2754 void SAL_CALL SlideshowImpl::gotoFirstSlide(  )
2755 {
2756     SolarMutexGuard aSolarGuard;
2757 
2758     if( !(mpShowWindow && mpSlideController) )
2759         return;
2760 
2761     if( mbIsPaused )
2762         resume();
2763 
2764     if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
2765     {
2766         if( mpSlideController->getSlideIndexCount() )
2767             mpShowWindow->RestartShow( 0);
2768     }
2769     else
2770     {
2771         displaySlideIndex( 0 );
2772     }
2773 }
2774 
2775 void SAL_CALL SlideshowImpl::gotoNextSlide(  )
2776 {
2777     SolarMutexGuard aSolarGuard;
2778 
2779     if( mbIsPaused )
2780         resume();
2781 
2782     const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
2783     if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
2784     {
2785         mpShowWindow->RestartShow();
2786     }
2787     else
2788     {
2789         // if this is a show, ignore user inputs and
2790         // start 20ms timer to reenable inputs to filter
2791         // buffered inputs during slide transition
2792         if( meAnimationMode == ANIMATIONMODE_SHOW )
2793         {
2794             mbInputFreeze = true;
2795             maInputFreezeTimer.Start();
2796         }
2797 
2798         if( mpSlideController )
2799         {
2800             if( mpSlideController->nextSlide() )
2801             {
2802                 displayCurrentSlide();
2803             }
2804             else
2805             {
2806                 stopSound();
2807 
2808                 if( meAnimationMode == ANIMATIONMODE_PREVIEW )
2809                 {
2810                     endPresentation();
2811                 }
2812                 else if( maPresSettings.mbEndless )
2813                 {
2814                     if( maPresSettings.mnPauseTimeout )
2815                     {
2816                         if( mpShowWindow )
2817                         {
2818                             if ( maPresSettings.mbShowPauseLogo )
2819                             {
2820                                 Graphic aGraphic(SfxApplication::GetApplicationLogo(360));
2821                                 mpShowWindow->SetPauseMode( maPresSettings.mnPauseTimeout, &aGraphic );
2822                             }
2823                             else
2824                                 mpShowWindow->SetPauseMode( maPresSettings.mnPauseTimeout );
2825                         }
2826                     }
2827                     else
2828                     {
2829                         displaySlideIndex( 0 );
2830                     }
2831                 }
2832                 else
2833                 {
2834                     if( mpShowWindow )
2835                     {
2836                         mpShowWindow->SetEndMode();
2837                         if( !mpViewShell->GetDoc()->IsStartWithPresentation() )
2838                             pause();
2839                     }
2840                 }
2841             }
2842         }
2843     }
2844 }
2845 
2846 void SAL_CALL SlideshowImpl::gotoPreviousSlide(  )
2847 {
2848     gotoPreviousSlide(false);
2849 }
2850 
2851 void SlideshowImpl::gotoPreviousSlide (const bool bSkipAllMainSequenceEffects)
2852 {
2853     SolarMutexGuard aSolarGuard;
2854 
2855     if( !(mxShow.is() && mpSlideController) )
2856         return;
2857 
2858     try
2859     {
2860         if( mbIsPaused )
2861             resume();
2862 
2863         const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
2864         if( eMode == SHOWWINDOWMODE_END )
2865         {
2866             mpShowWindow->RestartShow( mpSlideController->getCurrentSlideIndex() );
2867         }
2868         else if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
2869         {
2870             mpShowWindow->RestartShow();
2871         }
2872         else
2873         {
2874             if( mpSlideController->previousSlide())
2875                 displayCurrentSlide(bSkipAllMainSequenceEffects);
2876             else if (bSkipAllMainSequenceEffects)
2877             {
2878                 // We could not go to the previous slide (probably because
2879                 // the current slide is already the first one).  We still
2880                 // have to call displayCurrentSlide because the calling
2881                 // slideshow can not determine whether there is a previous
2882                 // slide or not and has already prepared for a slide change.
2883                 // This slide change has to be completed now, even when
2884                 // changing to the same slide.
2885                 // Note that in this special case we do NOT pass
2886                 // bSkipAllMainSequenceEffects because we display the same
2887                 // slide as before and do not want to show all its effects.
2888                 displayCurrentSlide();
2889             }
2890         }
2891     }
2892     catch( Exception& )
2893     {
2894         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::gotoPreviousSlide()" );
2895     }
2896 }
2897 
2898 void SAL_CALL SlideshowImpl::gotoLastSlide()
2899 {
2900     SolarMutexGuard aSolarGuard;
2901 
2902     if( !mpSlideController )
2903         return;
2904 
2905     if( mbIsPaused )
2906         resume();
2907 
2908     const sal_Int32 nLastSlideIndex = mpSlideController->getSlideIndexCount() - 1;
2909     if( nLastSlideIndex >= 0 )
2910     {
2911         if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
2912         {
2913             mpShowWindow->RestartShow( nLastSlideIndex );
2914         }
2915         else
2916         {
2917             displaySlideIndex( nLastSlideIndex );
2918         }
2919     }
2920 }
2921 
2922 void SAL_CALL SlideshowImpl::gotoBookmark( const OUString& rBookmark )
2923 {
2924     SolarMutexGuard aSolarGuard;
2925 
2926     if( mbIsPaused )
2927         resume();
2928 
2929     sal_Int32 nSlideNumber = getSlideNumberForBookmark( rBookmark );
2930     if( nSlideNumber != -1 )
2931         displaySlideNumber( nSlideNumber );
2932 }
2933 
2934 void SAL_CALL SlideshowImpl::gotoSlide( const Reference< XDrawPage >& xSlide )
2935 {
2936     SolarMutexGuard aSolarGuard;
2937 
2938     if( !(mpSlideController && xSlide.is()) )
2939         return;
2940 
2941     if( mbIsPaused )
2942         resume();
2943 
2944     const sal_Int32 nSlideCount = mpSlideController->getSlideNumberCount();
2945     for( sal_Int32 nSlide = 0; nSlide < nSlideCount; nSlide++ )
2946     {
2947         if( mpSlideController->getSlideByNumber( nSlide ) == xSlide )
2948         {
2949             displaySlideNumber( nSlide );
2950         }
2951     }
2952 }
2953 
2954 void SAL_CALL SlideshowImpl::gotoSlideIndex( sal_Int32 nIndex )
2955 {
2956     SolarMutexGuard aSolarGuard;
2957 
2958     if( mbIsPaused )
2959         resume();
2960 
2961     displaySlideIndex( nIndex );
2962 }
2963 
2964 void SAL_CALL SlideshowImpl::stopSound(  )
2965 {
2966     SolarMutexGuard aSolarGuard;
2967 
2968     try
2969     {
2970         if( mxPlayer.is() )
2971         {
2972             mxPlayer->stop();
2973             mxPlayer.clear();
2974         }
2975     }
2976     catch( Exception& )
2977     {
2978         TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stopSound()" );
2979     }
2980 }
2981 
2982 // XIndexAccess
2983 
2984 ::sal_Int32 SAL_CALL SlideshowImpl::getCount(  )
2985 {
2986     return getSlideCount();
2987 }
2988 
2989 css::uno::Any SAL_CALL SlideshowImpl::getByIndex( ::sal_Int32 Index )
2990 {
2991     return Any( getSlideByIndex( Index ) );
2992 }
2993 
2994 css::uno::Type SAL_CALL SlideshowImpl::getElementType(  )
2995 {
2996     return cppu::UnoType<XDrawPage>::get();
2997 }
2998 
2999 sal_Bool SAL_CALL SlideshowImpl::hasElements(  )
3000 {
3001     return getSlideCount() != 0;
3002 }
3003 
3004 Reference< XSlideShow > SAL_CALL SlideshowImpl::getSlideShow()
3005 {
3006     return mxShow;
3007 }
3008 
3009 PresentationSettingsEx::PresentationSettingsEx( const PresentationSettingsEx& r )
3010 : PresentationSettings( r )
3011 , mbRehearseTimings(r.mbRehearseTimings)
3012 , mbPreview(r.mbPreview)
3013 , mpParentWindow( nullptr )
3014 {
3015 }
3016 
3017 PresentationSettingsEx::PresentationSettingsEx( PresentationSettings const & r )
3018 : PresentationSettings( r )
3019 , mbRehearseTimings(false)
3020 , mbPreview(false)
3021 , mpParentWindow(nullptr)
3022 {
3023 }
3024 
3025 void PresentationSettingsEx::SetArguments( const Sequence< PropertyValue >& rArguments )
3026 {
3027     for( const PropertyValue& rValue : rArguments )
3028     {
3029         SetPropertyValue( rValue.Name, rValue.Value );
3030     }
3031 }
3032 
3033 void PresentationSettingsEx::SetPropertyValue( std::u16string_view rProperty, const Any& rValue )
3034 {
3035     if ( rProperty == u"RehearseTimings" )
3036     {
3037         if( rValue >>= mbRehearseTimings )
3038             return;
3039     }
3040     else if ( rProperty == u"Preview" )
3041     {
3042         if( rValue >>= mbPreview )
3043             return;
3044     }
3045     else if ( rProperty == u"AnimationNode" )
3046     {
3047         if( rValue >>= mxAnimationNode )
3048             return;
3049     }
3050     else if ( rProperty == u"ParentWindow" )
3051     {
3052         Reference< XWindow > xWindow;
3053         if( rValue >>= xWindow )
3054         {
3055             mpParentWindow = xWindow.is() ? VCLUnoHelper::GetWindow( xWindow )
3056                                           : nullptr;
3057             return;
3058         }
3059     }
3060     else if ( rProperty == u"AllowAnimations" )
3061     {
3062         if( rValue >>= mbAnimationAllowed )
3063             return;
3064     }
3065     else if ( rProperty == u"FirstPage" )
3066     {
3067         OUString aPresPage;
3068         if( rValue >>= aPresPage )
3069         {
3070             maPresPage = getUiNameFromPageApiNameImpl(aPresPage);
3071             mbCustomShow = false;
3072             mbAll = false;
3073             return;
3074         }
3075         else
3076         {
3077             if( rValue >>= mxStartPage )
3078                 return;
3079         }
3080     }
3081     else if ( rProperty == u"IsAlwaysOnTop" )
3082     {
3083         if( rValue >>= mbAlwaysOnTop )
3084             return;
3085     }
3086     else if ( rProperty == u"IsAutomatic" )
3087     {
3088         if( rValue >>= mbManual )
3089             return;
3090     }
3091     else if ( rProperty == u"IsEndless" )
3092     {
3093         if( rValue >>= mbEndless )
3094             return;
3095     }
3096     else if ( rProperty == u"IsFullScreen" )
3097     {
3098         if( rValue >>= mbFullScreen )
3099             return;
3100     }
3101     else if ( rProperty == u"IsMouseVisible" )
3102     {
3103         if( rValue >>= mbMouseVisible )
3104             return;
3105     }
3106     else if ( rProperty == u"Pause" )
3107     {
3108         sal_Int32 nPause = -1;
3109         if( (rValue >>= nPause) && (nPause >= 0) )
3110         {
3111             mnPauseTimeout = nPause;
3112             return;
3113         }
3114     }
3115     else if ( rProperty == u"UsePen" )
3116     {
3117         if( rValue >>= mbMouseAsPen )
3118             return;
3119     }
3120     throw IllegalArgumentException();
3121 }
3122 
3123 // XAnimationListener
3124 
3125 SlideShowListenerProxy::SlideShowListenerProxy( const rtl::Reference< SlideshowImpl >& xController, const css::uno::Reference< css::presentation::XSlideShow >& xSlideShow )
3126 : maListeners( m_aMutex )
3127 , mxController( xController )
3128 , mxSlideShow( xSlideShow )
3129 {
3130 }
3131 
3132 SlideShowListenerProxy::~SlideShowListenerProxy()
3133 {
3134 }
3135 
3136 void SlideShowListenerProxy::addAsSlideShowListener()
3137 {
3138     if( mxSlideShow.is() )
3139     {
3140         Reference< XSlideShowListener > xSlideShowListener( this );
3141         mxSlideShow->addSlideShowListener( xSlideShowListener );
3142     }
3143 }
3144 
3145 void SlideShowListenerProxy::removeAsSlideShowListener()
3146 {
3147     if( mxSlideShow.is() )
3148     {
3149         Reference< XSlideShowListener > xSlideShowListener( this );
3150         mxSlideShow->removeSlideShowListener( xSlideShowListener );
3151     }
3152 }
3153 
3154 void SlideShowListenerProxy::addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape )
3155 {
3156     if( mxSlideShow.is() )
3157     {
3158         Reference< XShapeEventListener > xListener( this );
3159         mxSlideShow->addShapeEventListener( xListener, xShape );
3160     }
3161 }
3162 
3163 void SlideShowListenerProxy::removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape )
3164 {
3165     if( mxSlideShow.is() )
3166     {
3167         Reference< XShapeEventListener > xListener( this );
3168         mxSlideShow->removeShapeEventListener( xListener, xShape );
3169     }
3170 }
3171 
3172 void SlideShowListenerProxy::addSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& xListener )
3173 {
3174     maListeners.addInterface(xListener);
3175 }
3176 
3177 void SlideShowListenerProxy::removeSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& xListener )
3178 {
3179     maListeners.removeInterface(xListener);
3180 }
3181 
3182 void SAL_CALL SlideShowListenerProxy::beginEvent( const Reference< XAnimationNode >& xNode )
3183 {
3184     ::osl::MutexGuard aGuard( m_aMutex );
3185 
3186     if( maListeners.getLength() >= 0 )
3187     {
3188         maListeners.forEach(
3189             [&] (Reference<XAnimationListener> const& xListener) {
3190                 return xListener->beginEvent(xNode);
3191             } );
3192     }
3193 }
3194 
3195 void SAL_CALL SlideShowListenerProxy::endEvent( const Reference< XAnimationNode >& xNode )
3196 {
3197     ::osl::MutexGuard aGuard( m_aMutex );
3198 
3199     if( maListeners.getLength() >= 0 )
3200     {
3201         maListeners.forEach(
3202             [&] (Reference<XAnimationListener> const& xListener) {
3203                 return xListener->endEvent(xNode);
3204             } );
3205     }
3206 }
3207 
3208 void SAL_CALL SlideShowListenerProxy::repeat( const Reference< XAnimationNode >& xNode, ::sal_Int32 nRepeat )
3209 {
3210     ::osl::MutexGuard aGuard( m_aMutex );
3211 
3212     if( maListeners.getLength() >= 0 )
3213     {
3214         maListeners.forEach(
3215             [&] (Reference<XAnimationListener> const& xListener) {
3216                 return xListener->repeat(xNode, nRepeat);
3217             } );
3218     }
3219 }
3220 
3221 // css::presentation::XSlideShowListener:
3222 
3223 void SAL_CALL SlideShowListenerProxy::paused(  )
3224 {
3225     ::osl::MutexGuard aGuard( m_aMutex );
3226 
3227     maListeners.forEach(
3228         [](uno::Reference<presentation::XSlideShowListener> const& xListener)
3229         {
3230             xListener->paused();
3231         });
3232 }
3233 
3234 void SAL_CALL SlideShowListenerProxy::resumed(  )
3235 {
3236     ::osl::MutexGuard aGuard( m_aMutex );
3237 
3238     maListeners.forEach(
3239         [](uno::Reference<presentation::XSlideShowListener> const& xListener)
3240         {
3241             xListener->resumed();
3242         });
3243 }
3244 
3245 void SAL_CALL SlideShowListenerProxy::slideTransitionStarted( )
3246 {
3247     ::osl::MutexGuard aGuard( m_aMutex );
3248 
3249     maListeners.forEach(
3250         [](uno::Reference<presentation::XSlideShowListener> const& xListener)
3251         {
3252             xListener->slideTransitionStarted();
3253         });
3254 }
3255 
3256 void SAL_CALL SlideShowListenerProxy::slideTransitionEnded( )
3257 {
3258     ::osl::MutexGuard aGuard( m_aMutex );
3259 
3260     maListeners.forEach(
3261         [](uno::Reference<presentation::XSlideShowListener> const& xListener)
3262         {
3263             xListener->slideTransitionEnded ();
3264         });
3265 }
3266 
3267 void SAL_CALL SlideShowListenerProxy::slideAnimationsEnded(  )
3268 {
3269     ::osl::MutexGuard aGuard( m_aMutex );
3270 
3271     maListeners.forEach(
3272         [](uno::Reference<presentation::XSlideShowListener> const& xListener)
3273         {
3274             xListener->slideAnimationsEnded ();
3275         });
3276 }
3277 
3278 void SlideShowListenerProxy::slideEnded(sal_Bool bReverse)
3279 {
3280     {
3281         ::osl::MutexGuard aGuard( m_aMutex );
3282 
3283         if( maListeners.getLength() >= 0 )
3284         {
3285             maListeners.forEach(
3286                 [&] (Reference<XSlideShowListener> const& xListener) {
3287                     return xListener->slideEnded(bReverse);
3288                 } );
3289         }
3290     }
3291 
3292     {
3293         SolarMutexGuard aSolarGuard;
3294         if( mxController.is() )
3295             mxController->slideEnded(bReverse);
3296     }
3297 }
3298 
3299 void SlideShowListenerProxy::hyperLinkClicked( OUString const& aHyperLink )
3300 {
3301     {
3302         ::osl::MutexGuard aGuard( m_aMutex );
3303 
3304         if( maListeners.getLength() >= 0 )
3305         {
3306             maListeners.forEach(
3307                 [&] (Reference<XSlideShowListener> const& xListener) {
3308                     return xListener->hyperLinkClicked(aHyperLink);
3309                 } );
3310         }
3311     }
3312 
3313     {
3314         SolarMutexGuard aSolarGuard;
3315         if( mxController.is() )
3316             mxController->hyperLinkClicked(aHyperLink);
3317     }
3318 }
3319 
3320 // XEventListener
3321 
3322 void SAL_CALL SlideShowListenerProxy::disposing( const css::lang::EventObject& aDisposeEvent )
3323 {
3324     maListeners.disposeAndClear( aDisposeEvent );
3325     mxController.clear();
3326     mxSlideShow.clear();
3327 }
3328 
3329 // XShapeEventListener
3330 
3331 void SAL_CALL SlideShowListenerProxy::click( const Reference< XShape >& xShape, const css::awt::MouseEvent& /*aOriginalEvent*/ )
3332 {
3333     SolarMutexGuard aSolarGuard;
3334     if( mxController.is() )
3335         mxController->click(xShape );
3336 }
3337 
3338 } // namespace ::sd
3339 
3340 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3341