xref: /core/sfx2/source/appl/shutdownicon.cxx (revision 6efdd1444810e132ba37379dd39afa6a3220f541)
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 #include <sal/log.hxx>
22 
23 #include <shutdownicon.hxx>
24 #include <sfx2/strings.hrc>
25 #include <sfx2/app.hxx>
26 #include <svtools/imagemgr.hxx>
27 #include <com/sun/star/task/InteractionHandler.hpp>
28 #include <com/sun/star/frame/Desktop.hpp>
29 #include <com/sun/star/frame/TerminationVetoException.hpp>
30 #include <com/sun/star/frame/XDispatchResultListener.hpp>
31 #include <com/sun/star/frame/XNotifyingDispatch.hpp>
32 #include <com/sun/star/frame/XFramesSupplier.hpp>
33 #include <com/sun/star/frame/XFrame.hpp>
34 #include <com/sun/star/util/URLTransformer.hpp>
35 #include <com/sun/star/util/XURLTransformer.hpp>
36 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
37 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
38 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
39 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
40 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
41 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
42 #include <com/sun/star/document/MacroExecMode.hpp>
43 #include <com/sun/star/document/UpdateDocMode.hpp>
44 #include <sfx2/filedlghelper.hxx>
45 #include <sfx2/docfilt.hxx>
46 #include <sfx2/fcontnr.hxx>
47 #include <comphelper/processfactory.hxx>
48 #include <comphelper/propertyvalue.hxx>
49 #include <cppuhelper/implbase.hxx>
50 #include <cppuhelper/supportsservice.hxx>
51 #include <comphelper/extract.hxx>
52 #include <officecfg/Office/Common.hxx>
53 #include <tools/urlobj.hxx>
54 #include <tools/debug.hxx>
55 #include <osl/diagnose.h>
56 #include <osl/file.hxx>
57 #include <osl/module.hxx>
58 #include <rtl/ref.hxx>
59 #include <utility>
60 #include <vcl/svapp.hxx>
61 
62 #include <sfx2/sfxresid.hxx>
63 
64 using namespace ::com::sun::star;
65 using namespace ::com::sun::star::uno;
66 using namespace ::com::sun::star::frame;
67 using namespace ::com::sun::star::container;
68 using namespace ::com::sun::star::lang;
69 using namespace ::com::sun::star::beans;
70 using namespace ::com::sun::star::util;
71 using namespace ::com::sun::star::ui::dialogs;
72 using namespace ::sfx2;
73 
74 class SfxNotificationListener_Impl : public cppu::WeakImplHelper< XDispatchResultListener >
75 {
76 public:
77     virtual void SAL_CALL dispatchFinished( const DispatchResultEvent& aEvent ) override;
78     virtual void SAL_CALL disposing( const EventObject& aEvent ) override;
79 };
80 
dispatchFinished(const DispatchResultEvent &)81 void SAL_CALL SfxNotificationListener_Impl::dispatchFinished( const DispatchResultEvent& )
82 {
83     ShutdownIcon::LeaveModalMode();
84 }
85 
disposing(const EventObject &)86 void SAL_CALL SfxNotificationListener_Impl::disposing( const EventObject& )
87 {
88 }
89 
getImplementationName()90 OUString SAL_CALL ShutdownIcon::getImplementationName()
91 {
92     return u"com.sun.star.comp.desktop.QuickstartWrapper"_ustr;
93 }
94 
supportsService(OUString const & ServiceName)95 sal_Bool SAL_CALL ShutdownIcon::supportsService(OUString const & ServiceName)
96 {
97     return cppu::supportsService(this, ServiceName);
98 }
99 
getSupportedServiceNames()100 css::uno::Sequence<OUString> SAL_CALL ShutdownIcon::getSupportedServiceNames()
101 {
102     return { u"com.sun.star.office.Quickstart"_ustr };
103 }
104 
105 bool ShutdownIcon::bModalMode = false;
106 rtl::Reference<ShutdownIcon> ShutdownIcon::pShutdownIcon;
107 
initSystray()108 void ShutdownIcon::initSystray()
109 {
110     if (m_bInitialized)
111         return;
112     m_bInitialized = true;
113 
114 #ifdef ENABLE_QUICKSTART_APPLET
115 #  ifdef _WIN32
116     win32_init_sys_tray();
117 #  elif defined MACOSX
118     aqua_init_systray();
119 #  endif // MACOSX
120 #endif // ENABLE_QUICKSTART_APPLET
121 }
122 
deInitSystray()123 void ShutdownIcon::deInitSystray()
124 {
125     if (!m_bInitialized)
126         return;
127 
128 #ifdef ENABLE_QUICKSTART_APPLET
129 #  ifdef _WIN32
130     win32_shutdown_sys_tray();
131 #  elif defined MACOSX
132     aqua_shutdown_systray();
133 #  endif // MACOSX
134 #endif // ENABLE_QUICKSTART_APPLET
135 
136     m_bVeto = false;
137 
138     m_pFileDlg.reset();
139     m_bInitialized = false;
140 }
141 
UseSystemFileDialog()142 static bool UseSystemFileDialog()
143 {
144     return !Application::IsHeadlessModeEnabled() && officecfg::Office::Common::Misc::UseSystemFileDialog::get();
145 }
146 
ShutdownIcon(css::uno::Reference<XComponentContext> xContext)147 ShutdownIcon::ShutdownIcon( css::uno::Reference< XComponentContext > xContext ) :
148     m_bVeto ( false ),
149     m_bListenForTermination ( false ),
150     m_bSystemDialogs(UseSystemFileDialog()),
151     m_xContext(std::move( xContext )),
152     m_bInitialized( false )
153 {
154 }
155 
~ShutdownIcon()156 ShutdownIcon::~ShutdownIcon()
157 {
158     deInitSystray();
159 }
160 
161 
OpenURL(const OUString & aURL,const OUString & rTarget,const Sequence<PropertyValue> & aArgs)162 void ShutdownIcon::OpenURL( const OUString& aURL, const OUString& rTarget, const Sequence< PropertyValue >& aArgs )
163 {
164     if ( !getInstance() || !getInstance()->m_xDesktop.is() )
165         return;
166 
167     css::uno::Reference < XDispatchProvider > xDispatchProvider = getInstance()->m_xDesktop;
168     if ( !xDispatchProvider.is() )
169         return;
170 
171     css::util::URL aDispatchURL;
172     aDispatchURL.Complete = aURL;
173 
174     css::uno::Reference< util::XURLTransformer > xURLTransformer( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
175     try
176     {
177         css::uno::Reference< css::frame::XDispatch > xDispatch;
178 
179         xURLTransformer->parseStrict( aDispatchURL );
180         xDispatch = xDispatchProvider->queryDispatch( aDispatchURL, rTarget, 0 );
181         if ( xDispatch.is() )
182             xDispatch->dispatch( aDispatchURL, aArgs );
183     }
184     catch ( css::uno::RuntimeException& )
185     {
186         throw;
187     }
188     catch ( css::uno::Exception& )
189     {
190     }
191 }
192 
193 
FileOpen()194 void ShutdownIcon::FileOpen()
195 {
196     if ( getInstance() && getInstance()->m_xDesktop.is() )
197     {
198         ::SolarMutexGuard aGuard;
199         EnterModalMode();
200         getInstance()->StartFileDialog();
201     }
202 }
203 
204 
FromTemplate()205 void ShutdownIcon::FromTemplate()
206 {
207     ShutdownIcon::FromCommand( ".uno:NewDoc" );
208 }
209 
FromCommand(const OUString & rCommand)210 void ShutdownIcon::FromCommand( const OUString& rCommand )
211 {
212     if ( !getInstance() || !getInstance()->m_xDesktop.is() )
213         return;
214 
215     css::uno::Reference < css::frame::XFramesSupplier > xDesktop = getInstance()->m_xDesktop;
216     css::uno::Reference < css::frame::XFrame > xFrame( xDesktop->getActiveFrame() );
217     if ( !xFrame.is() )
218         xFrame = xDesktop;
219 
220     URL aTargetURL;
221     aTargetURL.Complete = rCommand;
222     css::uno::Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
223     xTrans->parseStrict( aTargetURL );
224 
225     css::uno::Reference < css::frame::XDispatchProvider > xProv( xFrame, UNO_QUERY );
226     css::uno::Reference < css::frame::XDispatch > xDisp;
227     if ( xProv.is() )
228     {
229         xDisp = xProv->queryDispatch( aTargetURL, u"_self"_ustr, 0 );
230     }
231     if ( !xDisp.is() )
232         return;
233 
234     Sequence<PropertyValue> aArgs { comphelper::makePropertyValue(u"Referer"_ustr, u"private:user"_ustr) };
235     css::uno::Reference< css::frame::XNotifyingDispatch > xNotifier(xDisp, UNO_QUERY);
236     if (xNotifier.is())
237     {
238         EnterModalMode();
239         xNotifier->dispatchWithNotification(aTargetURL, aArgs, new SfxNotificationListener_Impl);
240     }
241     else
242         xDisp->dispatch( aTargetURL, aArgs );
243 }
244 
GetUrlDescription(std::u16string_view aUrl)245 OUString ShutdownIcon::GetUrlDescription( std::u16string_view aUrl )
246 {
247     return SvFileInformationManager::GetDescription( INetURLObject( aUrl ) );
248 }
249 
StartFileDialog()250 void ShutdownIcon::StartFileDialog()
251 {
252     ::SolarMutexGuard aGuard;
253 
254     bool bDirty = m_bSystemDialogs != UseSystemFileDialog();
255 
256     if ( m_pFileDlg && bDirty )
257     {
258         // Destroy instance as changing the system file dialog setting
259         // forces us to create a new FileDialogHelper instance!
260         m_pFileDlg.reset();
261     }
262 
263     if ( !m_pFileDlg )
264         m_pFileDlg.reset( new FileDialogHelper(
265                 ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION,
266                 FileDialogFlags::MultiSelection, OUString(), SfxFilterFlags::NONE, SfxFilterFlags::NONE, nullptr ) );
267     m_pFileDlg->StartExecuteModal( LINK( this, ShutdownIcon, DialogClosedHdl_Impl ) );
268 }
269 
270 IMPL_LINK( ShutdownIcon, DialogClosedHdl_Impl, FileDialogHelper*, /*unused*/, void )
271 {
272     DBG_ASSERT( m_pFileDlg, "ShutdownIcon, DialogClosedHdl_Impl(): no file dialog" );
273 
274     // use constructor for filling up filters automatically!
275     if ( ERRCODE_NONE == m_pFileDlg->GetError() )
276     {
277         css::uno::Reference< XFilePicker3 >    xPicker = m_pFileDlg->GetFilePicker();
278 
279         try
280         {
281 
282             if ( xPicker.is() )
283             {
284 
285                 css::uno::Reference < XFilePickerControlAccess > xPickerControls ( xPicker, UNO_QUERY );
286 
287                 Sequence< OUString >        sFiles = xPicker->getSelectedFiles();
288                 int                         nFiles = sFiles.getLength();
289 
290                 css::uno::Reference < css::task::XInteractionHandler2 > xInteraction(
291                     task::InteractionHandler::createWithParent(::comphelper::getProcessComponentContext(), nullptr) );
292 
293                 int                         nArgs=3;
294                 Sequence< PropertyValue >   aArgs{
295                     comphelper::makePropertyValue(u"InteractionHandler"_ustr, xInteraction),
296                     comphelper::makePropertyValue(u"MacroExecutionMode"_ustr, sal_Int16(css::document::MacroExecMode::USE_CONFIG)),
297                     comphelper::makePropertyValue(u"UpdateDocMode"_ustr, sal_Int16(css::document::UpdateDocMode::ACCORDING_TO_CONFIG))
298                 };
299 
300                 // use the filedlghelper to get the current filter name,
301                 // because it removes the extensions before you get the filter name.
302                 OUString aFilterName( m_pFileDlg->GetCurrentFilter() );
303 
304                 if ( xPickerControls.is() )
305                 {
306 
307                     // Set readonly flag
308 
309                     bool    bReadOnly = false;
310 
311 
312                     xPickerControls->getValue( ExtendedFilePickerElementIds::CHECKBOX_READONLY, 0 ) >>= bReadOnly;
313 
314                     // Only set property if readonly is set to TRUE
315 
316                     if ( bReadOnly )
317                     {
318                         aArgs.realloc( ++nArgs );
319                         auto pArgs = aArgs.getArray();
320                         pArgs[nArgs-1].Name  = "ReadOnly";
321                         pArgs[nArgs-1].Value <<= bReadOnly;
322                     }
323 
324                     // Get version string
325 
326                     sal_Int32   iVersion = -1;
327 
328                     xPickerControls->getValue( ExtendedFilePickerElementIds::LISTBOX_VERSION, ControlActions::GET_SELECTED_ITEM_INDEX ) >>= iVersion;
329 
330                     if ( iVersion >= 0 )
331                     {
332                         sal_Int16   uVersion = static_cast<sal_Int16>(iVersion);
333 
334                         aArgs.realloc( ++nArgs );
335                         auto pArgs = aArgs.getArray();
336                         pArgs[nArgs-1].Name  = "Version";
337                         pArgs[nArgs-1].Value <<= uVersion;
338                     }
339 
340                     // Retrieve the current filter
341 
342                     if ( aFilterName.isEmpty() )
343                         xPickerControls->getValue( CommonFilePickerElementIds::LISTBOX_FILTER, ControlActions::GET_SELECTED_ITEM ) >>= aFilterName;
344 
345                 }
346 
347 
348                 // Convert UI filter name to internal filter name
349 
350                 if ( !aFilterName.isEmpty() )
351                 {
352                     std::shared_ptr<const SfxFilter> pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4UIName( aFilterName, SfxFilterFlags::NONE, SfxFilterFlags::NOTINFILEDLG );
353 
354                     if ( pFilter )
355                     {
356                         aFilterName = pFilter->GetFilterName();
357 
358                         if ( !aFilterName.isEmpty() )
359                         {
360                             aArgs.realloc( ++nArgs );
361                             auto pArgs = aArgs.getArray();
362                             pArgs[nArgs-1].Name  = "FilterName";
363                             pArgs[nArgs-1].Value <<= aFilterName;
364                         }
365                     }
366                 }
367 
368                 if ( 1 == nFiles )
369                     OpenURL( sFiles[0], u"_default"_ustr, aArgs );
370                 else
371                 {
372                     OUString    aBaseDirURL = sFiles[0];
373                     if ( !aBaseDirURL.isEmpty() && !aBaseDirURL.endsWith("/") )
374                         aBaseDirURL += "/";
375 
376                     int iFiles;
377                     for ( iFiles = 1; iFiles < nFiles; iFiles++ )
378                     {
379                         OUString aURL = aBaseDirURL + sFiles[iFiles];
380                         OpenURL( aURL, u"_default"_ustr, aArgs );
381                     }
382                 }
383             }
384         }
385         catch ( ... )
386         {
387         }
388     }
389 
390 #ifdef _WIN32
391     // Destroy dialog to prevent problems with custom controls
392     // This fix is dependent on the dialog settings. Destroying the dialog here will
393     // crash the non-native dialog implementation! Therefore make this dependent on
394     // the settings.
395     if (UseSystemFileDialog())
396     {
397         m_pFileDlg.reset();
398     }
399 #endif
400 
401     LeaveModalMode();
402 }
403 
404 
addTerminateListener()405 void ShutdownIcon::addTerminateListener()
406 {
407     ShutdownIcon* pInst = getInstance();
408     if ( ! pInst)
409         return;
410 
411     if (pInst->m_bListenForTermination)
412         return;
413 
414     css::uno::Reference< XDesktop2 > xDesktop = pInst->m_xDesktop;
415     if ( ! xDesktop.is())
416         return;
417 
418     xDesktop->addTerminateListener( pInst );
419     pInst->m_bListenForTermination = true;
420 }
421 
422 
terminateDesktop()423 void ShutdownIcon::terminateDesktop()
424 {
425     ShutdownIcon* pInst = getInstance();
426     if ( ! pInst)
427         return;
428 
429     css::uno::Reference< XDesktop2 > xDesktop = pInst->m_xDesktop;
430     if ( ! xDesktop.is())
431         return;
432 
433     // always remove ourselves as listener
434     pInst->m_bListenForTermination = true;
435     xDesktop->removeTerminateListener( pInst );
436 
437     // terminate desktop only if no tasks exist
438     css::uno::Reference< XIndexAccess > xTasks = xDesktop->getFrames();
439     if( xTasks.is() && xTasks->getCount() < 1 )
440         Application::Quit();
441 
442     // remove the instance pointer
443     ShutdownIcon::pShutdownIcon = nullptr;
444 }
445 
446 
getInstance()447 ShutdownIcon* ShutdownIcon::getInstance()
448 {
449     OSL_ASSERT( pShutdownIcon );
450     return pShutdownIcon.get();
451 }
452 
453 
createInstance()454 ShutdownIcon* ShutdownIcon::createInstance()
455 {
456     if (pShutdownIcon)
457         return pShutdownIcon.get();
458 
459     try {
460         rtl::Reference<ShutdownIcon> pIcon(new ShutdownIcon( comphelper::getProcessComponentContext() ));
461         pIcon->init ();
462         pShutdownIcon = std::move(pIcon);
463     } catch (...) {
464     }
465 
466     return pShutdownIcon.get();
467 }
468 
init()469 void ShutdownIcon::init()
470 {
471     css::uno::Reference < XDesktop2 > xDesktop = Desktop::create( m_xContext );
472     std::unique_lock aGuard(m_aMutex);
473     m_xDesktop = std::move(xDesktop);
474 }
475 
disposing(std::unique_lock<std::mutex> &)476 void ShutdownIcon::disposing(std::unique_lock<std::mutex>&)
477 {
478     m_xContext.clear();
479     m_xDesktop.clear();
480 
481     deInitSystray();
482 }
483 
484 // XEventListener
disposing(const css::lang::EventObject &)485 void SAL_CALL ShutdownIcon::disposing( const css::lang::EventObject& )
486 {
487 }
488 
489 // XTerminateListener
queryTermination(const css::lang::EventObject &)490 void SAL_CALL ShutdownIcon::queryTermination( const css::lang::EventObject& )
491 {
492     SAL_INFO("sfx.appl", "ShutdownIcon::queryTermination: veto is " << m_bVeto);
493     std::unique_lock  aGuard( m_aMutex );
494 
495     if ( m_bVeto )
496         throw css::frame::TerminationVetoException();
497 }
498 
499 
notifyTermination(const css::lang::EventObject &)500 void SAL_CALL ShutdownIcon::notifyTermination( const css::lang::EventObject& )
501 {
502 }
503 
504 
initialize(const css::uno::Sequence<css::uno::Any> & aArguments)505 void SAL_CALL ShutdownIcon::initialize( const css::uno::Sequence< css::uno::Any>& aArguments )
506 {
507     std::unique_lock aGuard( m_aMutex );
508 
509     // third argument only sets veto, everything else will be ignored!
510     if (aArguments.getLength() > 2)
511     {
512         bool bVeto = ::cppu::any2bool(aArguments[2]);
513         m_bVeto = bVeto;
514         return;
515     }
516 
517     if ( aArguments.getLength() > 0 )
518     {
519         if ( !ShutdownIcon::pShutdownIcon )
520         {
521             try
522             {
523                 bool bQuickstart = ::cppu::any2bool( aArguments[0] );
524                 if( !bQuickstart && !GetAutostart() )
525                     return;
526                 aGuard.unlock();
527                 init ();
528                 aGuard.lock();
529                 if ( !m_xDesktop.is() )
530                     return;
531 
532                 /* Create a sub-classed instance - foo */
533                 ShutdownIcon::pShutdownIcon = this;
534                 initSystray();
535             }
536             catch(const css::lang::IllegalArgumentException&)
537             {
538             }
539         }
540     }
541     if ( aArguments.getLength() > 1 )
542     {
543             bool bAutostart = ::cppu::any2bool( aArguments[1] );
544             if (bAutostart && !GetAutostart())
545                 SetAutostart( true );
546             if (!bAutostart && GetAutostart())
547                 SetAutostart( false );
548     }
549 
550 }
551 
552 
EnterModalMode()553 void ShutdownIcon::EnterModalMode()
554 {
555     bModalMode = true;
556 }
557 
558 
LeaveModalMode()559 void ShutdownIcon::LeaveModalMode()
560 {
561     bModalMode = false;
562 }
563 
564 #ifdef _WIN32
565 // defined in shutdowniconw32.cxx
566 #elif defined MACOSX
567 // defined in shutdowniconaqua.cxx
568 #else
IsQuickstarterInstalled()569 bool ShutdownIcon::IsQuickstarterInstalled()
570 {
571     return false;
572 }
573 #endif
574 
575 
576 #ifdef ENABLE_QUICKSTART_APPLET
577 #ifdef _WIN32
getShortcutName()578 OUString ShutdownIcon::getShortcutName()
579 {
580     return GetAutostartFolderNameW32() + "\\" + SfxResId(STR_QUICKSTART_LNKNAME) + ".lnk";
581 }
582 #endif // _WIN32
583 #endif
584 
GetAutostart()585 bool ShutdownIcon::GetAutostart( )
586 {
587 #if defined MACOSX
588     return true;
589 #elif defined ENABLE_QUICKSTART_APPLET
590     bool bRet = false;
591     OUString aShortcut( getShortcutName() );
592     OUString aShortcutUrl;
593     osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
594     osl::File f( aShortcutUrl );
595     osl::File::RC error = f.open( osl_File_OpenFlag_Read );
596     if( error == osl::File::E_None )
597     {
598         f.close();
599         bRet = true;
600     }
601     return bRet;
602 #else // ENABLE_QUICKSTART_APPLET
603     return false;
604 #endif
605 }
606 
SetAutostart(bool bActivate)607 void ShutdownIcon::SetAutostart( bool bActivate )
608 {
609 #ifdef ENABLE_QUICKSTART_APPLET
610 #ifndef MACOSX
611     OUString aShortcut( getShortcutName() );
612 #endif
613 
614     if( bActivate && IsQuickstarterInstalled() )
615     {
616 #ifdef _WIN32
617         EnableAutostartW32( aShortcut );
618 #endif
619     }
620     else
621     {
622 #ifndef MACOSX
623         OUString aShortcutUrl;
624         ::osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
625         ::osl::File::remove( aShortcutUrl );
626 #endif
627     }
628 #else
629     (void)bActivate; // unused variable
630 #endif // ENABLE_QUICKSTART_APPLET
631 }
632 
633 const ::sal_Int32 PROPHANDLE_TERMINATEVETOSTATE = 0;
634 
635 // XFastPropertySet
setFastPropertyValue(::sal_Int32 nHandle,const css::uno::Any & aValue)636 void SAL_CALL ShutdownIcon::setFastPropertyValue(       ::sal_Int32                  nHandle,
637                                                   const css::uno::Any& aValue )
638 {
639     switch(nHandle)
640     {
641         case PROPHANDLE_TERMINATEVETOSTATE :
642              {
643                 // use new value in case it's a valid information only
644                 bool bState( false );
645                 if (! (aValue >>= bState))
646                     return;
647 
648                 m_bVeto = bState;
649                 if (m_bVeto && ! m_bListenForTermination)
650                     addTerminateListener();
651              }
652              break;
653 
654         default :
655             throw css::beans::UnknownPropertyException(OUString::number(nHandle));
656     }
657 }
658 
659 // XFastPropertySet
getFastPropertyValue(::sal_Int32 nHandle)660 css::uno::Any SAL_CALL ShutdownIcon::getFastPropertyValue( ::sal_Int32 nHandle )
661 {
662     css::uno::Any aValue;
663     switch(nHandle)
664     {
665         case PROPHANDLE_TERMINATEVETOSTATE :
666              {
667                 bool bState   = (m_bListenForTermination && m_bVeto);
668                 aValue <<= bState;
669              }
670              break;
671 
672         default :
673             throw css::beans::UnknownPropertyException(OUString::number(nHandle));
674     }
675 
676     return aValue;
677 }
678 
679 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_desktop_QuickstartWrapper_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const &)680 com_sun_star_comp_desktop_QuickstartWrapper_get_implementation(
681     css::uno::XComponentContext *context,
682     css::uno::Sequence<css::uno::Any> const &)
683 {
684     return cppu::acquire(new ShutdownIcon(context));
685 }
686 
687 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
688