xref: /aoo42x/main/sfx2/source/appl/shutdownicon.cxx (revision 910823ae)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sfx2.hxx"
26 
27 #include <shutdownicon.hxx>
28 #include <app.hrc>
29 #include <sfx2/app.hxx>
30 #include <vos/mutex.hxx>
31 #include <svtools/imagemgr.hxx>
32 #include <svtools/miscopt.hxx>
33 // #include <cmdlineargs.hxx>
34 #include <com/sun/star/task/XInteractionHandler.hpp>
35 #include <com/sun/star/frame/XDispatchResultListener.hpp>
36 #include <com/sun/star/frame/XNotifyingDispatch.hpp>
37 #include <com/sun/star/frame/XFramesSupplier.hpp>
38 #include <com/sun/star/frame/XComponentLoader.hpp>
39 #include <com/sun/star/frame/XFrame.hpp>
40 #include <com/sun/star/util/XURLTransformer.hpp>
41 #include <com/sun/star/frame/XFramesSupplier.hpp>
42 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
43 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
44 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
45 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
46 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
47 #include <com/sun/star/document/MacroExecMode.hpp>
48 #include <com/sun/star/document/UpdateDocMode.hpp>
49 #include <sfx2/filedlghelper.hxx>
50 #include <sfx2/fcontnr.hxx>
51 #ifndef _UNOTOOLS_PROCESSFACTORY_HXX
52 #include <comphelper/processfactory.hxx>
53 #endif
54 #include <cppuhelper/compbase1.hxx>
55 #include <sfx2/dispatch.hxx>
56 #include <comphelper/extract.hxx>
57 #include <tools/urlobj.hxx>
58 #include <osl/security.hxx>
59 #include <osl/file.hxx>
60 #include <rtl/bootstrap.hxx>
61 #include <rtl/ustrbuf.hxx>
62 #include <tools/link.hxx>
63 #ifdef UNX // need symlink
64 #include <unistd.h>
65 #include <errno.h>
66 #endif
67 #include <vcl/timer.hxx>
68 
69 #include "sfx2/sfxresid.hxx"
70 
71 using namespace ::com::sun::star::uno;
72 using namespace ::com::sun::star::frame;
73 using namespace ::com::sun::star::container;
74 using namespace ::com::sun::star::io;
75 using namespace ::com::sun::star::lang;
76 using namespace ::com::sun::star::beans;
77 using namespace ::com::sun::star::util;
78 using namespace ::com::sun::star::ui::dialogs;
79 using namespace ::vos;
80 #ifdef WNT
81 using ::rtl::OUString;
82 #else
83 using namespace ::rtl;
84 #endif
85 using namespace ::sfx2;
86 
87 #ifdef ENABLE_QUICKSTART_APPLET
88 # if !defined(WIN32) && !defined(QUARTZ)
89 extern "C" { static void SAL_CALL thisModule() {} }
90 # endif
91 #endif
92 
93 #if defined(UNX) && defined(ENABLE_SYSTRAY_GTK)
94 #define PLUGIN_NAME libqstart_gtk.so
95 #endif
96 
97 class SfxNotificationListener_Impl : public cppu::WeakImplHelper1< XDispatchResultListener >
98 {
99 public:
100     virtual void SAL_CALL dispatchFinished( const DispatchResultEvent& aEvent ) throw( RuntimeException );
101     virtual void SAL_CALL disposing( const EventObject& aEvent ) throw( RuntimeException );
102 };
103 
104 void SAL_CALL SfxNotificationListener_Impl::dispatchFinished( const DispatchResultEvent& ) throw( RuntimeException )
105 {
106 	ShutdownIcon::LeaveModalMode();
107 }
108 
109 void SAL_CALL SfxNotificationListener_Impl::disposing( const EventObject& ) throw( RuntimeException )
110 {
111 }
112 
113 SFX_IMPL_XSERVICEINFO( ShutdownIcon, "com.sun.star.office.Quickstart", "com.sun.star.comp.desktop.QuickstartWrapper" )	\
114 SFX_IMPL_ONEINSTANCEFACTORY( ShutdownIcon );
115 
116 bool ShutdownIcon::bModalMode = false;
117 ShutdownIcon* ShutdownIcon::pShutdownIcon = NULL;
118 
119 // To remove conditionals
120 extern "C" {
121 	static void disabled_initSystray() { }
122 	static void disabled_deInitSystray() { }
123 }
124 #define DOSTRING( x )			   			#x
125 #define STRING( x )				   			DOSTRING( x )
126 
127 bool ShutdownIcon::LoadModule( osl::Module **pModule,
128 							   oslGenericFunction *pInit,
129 							   oslGenericFunction *pDeInit )
130 {
131 	if ( pModule )
132 	{
133 		OSL_ASSERT ( pInit && pDeInit );
134 		*pInit = *pDeInit = NULL;
135 		*pModule = NULL;
136 	}
137 
138 #ifdef ENABLE_QUICKSTART_APPLET
139 #  ifdef WIN32
140 	if ( pModule )
141 	{
142 		*pInit = win32_init_sys_tray;
143 		*pDeInit = win32_shutdown_sys_tray;
144 	}
145 	return true;
146 #  elif defined QUARTZ
147     *pInit = aqua_init_systray;
148     *pDeInit = aqua_shutdown_systray;
149     return true;
150 #  else // UNX
151 	osl::Module *pPlugin;
152 	pPlugin = new osl::Module();
153 
154 	oslGenericFunction pTmpInit = NULL;
155 	oslGenericFunction pTmpDeInit = NULL;
156 	if ( pPlugin->loadRelative( &thisModule, OUString( RTL_CONSTASCII_USTRINGPARAM( STRING( PLUGIN_NAME ) ) ) ) )
157 	{
158 		pTmpInit = pPlugin->getFunctionSymbol(
159 			OUString( RTL_CONSTASCII_USTRINGPARAM( "plugin_init_sys_tray" ) ) );
160 		pTmpDeInit = pPlugin->getFunctionSymbol(
161 			OUString( RTL_CONSTASCII_USTRINGPARAM( "plugin_shutdown_sys_tray" ) ) );
162 	}
163 	if ( !pTmpInit || !pTmpDeInit )
164 	{
165 		delete pPlugin;
166 		pPlugin = NULL;
167 	}
168 	if ( pModule )
169 	{
170 		*pModule = pPlugin;
171 		*pInit = pTmpInit;
172 		*pDeInit = pTmpDeInit;
173 	}
174 	else
175 	{
176 		bool bRet = pPlugin != NULL;
177 		delete pPlugin;
178 		return bRet;
179 	}
180 #  endif // UNX
181 #endif // ENABLE_QUICKSTART_APPLET
182 	if ( pModule )
183 	{
184 		if ( !*pInit )
185 			*pInit = disabled_initSystray;
186 		if ( !*pDeInit )
187 			*pDeInit = disabled_deInitSystray;
188 	}
189 
190 	return true;
191 }
192 
193 
194 struct AsyncDesktopTerminationData
195 {
196     Reference< XDesktop > mxDesktop;
197     AsyncDesktopTerminationData( const Reference< XDesktop > &xDesktop )
198     : mxDesktop( xDesktop ) {}
199 };
200 
201 
202 class IdleUnloader : Timer
203 {
204     ::osl::Module *m_pModule;
205 public:
206     IdleUnloader (::osl::Module **pModule) :
207         m_pModule (*pModule)
208     {
209         *pModule = NULL;
210         Start();
211     }
212     virtual void Timeout()
213     {
214         delete m_pModule;
215         delete this;
216     }
217 };
218 
219 void ShutdownIcon::initSystray()
220 {
221 	if (m_bInitialized)
222 		return;
223 	m_bInitialized = true;
224 
225 	(void) LoadModule( &m_pPlugin, &m_pInitSystray, &m_pDeInitSystray );
226 	m_bVeto = true;
227 	m_pInitSystray();
228 }
229 
230 void ShutdownIcon::deInitSystray()
231 {
232 	if (!m_bInitialized)
233 		return;
234 
235     if (m_pDeInitSystray)
236 		m_pDeInitSystray();
237 
238 	m_bVeto = false;
239 	m_pInitSystray = 0;
240 	m_pDeInitSystray = 0;
241     new IdleUnloader (&m_pPlugin);
242 
243     delete m_pFileDlg;
244 	m_pFileDlg = NULL;
245 	m_bInitialized = false;
246 }
247 
248 
249 ShutdownIcon::ShutdownIcon( Reference< XMultiServiceFactory > aSMgr ) :
250 	ShutdownIconServiceBase( m_aMutex ),
251 	m_bVeto ( false ),
252     m_bListenForTermination ( false ),
253     m_bSystemDialogs( false ),
254 	m_pResMgr( NULL ),
255     m_pFileDlg( NULL ),
256 	m_xServiceManager( aSMgr ),
257 	m_pInitSystray( 0 ),
258 	m_pDeInitSystray( 0 ),
259 	m_pPlugin( 0 ),
260 	m_bInitialized( false )
261 {
262     m_bSystemDialogs = SvtMiscOptions().UseSystemFileDialog();
263 }
264 
265 ShutdownIcon::~ShutdownIcon()
266 {
267 	deInitSystray();
268     new IdleUnloader (&m_pPlugin);
269 }
270 
271 // ---------------------------------------------------------------------------
272 
273 void ShutdownIcon::OpenURL( const ::rtl::OUString& aURL, const ::rtl::OUString& rTarget, const Sequence< PropertyValue >& aArgs )
274 {
275     if ( getInstance() && getInstance()->m_xDesktop.is() )
276     {
277         Reference < XDispatchProvider > xDispatchProvider( getInstance()->m_xDesktop, UNO_QUERY );
278         if ( xDispatchProvider.is() )
279         {
280             com::sun::star::util::URL aDispatchURL;
281             aDispatchURL.Complete = aURL;
282 
283             Reference < com::sun::star::util::XURLTransformer > xURLTransformer(
284                 ::comphelper::getProcessServiceFactory()->createInstance( OUString::createFromAscii("com.sun.star.util.URLTransformer") ),
285                 com::sun::star::uno::UNO_QUERY );
286             if ( xURLTransformer.is() )
287             {
288                 try
289                 {
290                     Reference< com::sun::star::frame::XDispatch > xDispatch;
291 
292                     xURLTransformer->parseStrict( aDispatchURL );
293                     xDispatch = xDispatchProvider->queryDispatch( aDispatchURL, rTarget, 0 );
294                     if ( xDispatch.is() )
295                         xDispatch->dispatch( aDispatchURL, aArgs );
296                 }
297                 catch ( com::sun::star::uno::RuntimeException& )
298                 {
299                     throw;
300                 }
301                 catch ( com::sun::star::uno::Exception& )
302                 {
303                 }
304             }
305         }
306     }
307 }
308 
309 // ---------------------------------------------------------------------------
310 
311 void ShutdownIcon::FileOpen()
312 {
313     if ( getInstance() && getInstance()->m_xDesktop.is() )
314     {
315         ::vos::OGuard aGuard( Application::GetSolarMutex() );
316 		EnterModalMode();
317         getInstance()->StartFileDialog();
318     }
319 }
320 
321 // ---------------------------------------------------------------------------
322 
323 void ShutdownIcon::FromTemplate()
324 {
325     if ( getInstance() && getInstance()->m_xDesktop.is() )
326     {
327         Reference < ::com::sun::star::frame::XFramesSupplier > xDesktop ( getInstance()->m_xDesktop, UNO_QUERY);
328         Reference < ::com::sun::star::frame::XFrame > xFrame( xDesktop->getActiveFrame() );
329         if ( !xFrame.is() )
330             xFrame = Reference < ::com::sun::star::frame::XFrame >( xDesktop, UNO_QUERY );
331 
332         URL aTargetURL;
333         aTargetURL.Complete = OUString( RTL_CONSTASCII_USTRINGPARAM( "slot:5500" ) );
334         Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY );
335         xTrans->parseStrict( aTargetURL );
336 
337         Reference < ::com::sun::star::frame::XDispatchProvider > xProv( xFrame, UNO_QUERY );
338         Reference < ::com::sun::star::frame::XDispatch > xDisp;
339 	    if ( xProv.is() )
340 	    {
341             if ( aTargetURL.Protocol.compareToAscii("slot:") == COMPARE_EQUAL )
342                 xDisp = xProv->queryDispatch( aTargetURL, ::rtl::OUString(), 0 );
343             else
344                 xDisp = xProv->queryDispatch( aTargetURL, ::rtl::OUString::createFromAscii("_blank"), 0 );
345 	    }
346         if ( xDisp.is() )
347 	    {
348 		    Sequence<PropertyValue> aArgs(1);
349 		    PropertyValue* pArg = aArgs.getArray();
350 		    pArg[0].Name = rtl::OUString::createFromAscii("Referer");
351             pArg[0].Value <<= ::rtl::OUString::createFromAscii("private:user");
352             Reference< ::com::sun::star::frame::XNotifyingDispatch > xNotifyer( xDisp, UNO_QUERY );
353             if ( xNotifyer.is() )
354 			{
355 				EnterModalMode();
356                 xNotifyer->dispatchWithNotification( aTargetURL, aArgs, new SfxNotificationListener_Impl() );
357 			}
358             else
359                 xDisp->dispatch( aTargetURL, aArgs );
360 	    }
361     }
362 }
363 
364 // ---------------------------------------------------------------------------
365 #include <tools/rcid.h>
366 OUString ShutdownIcon::GetResString( int id )
367 {
368     ::vos::OGuard aGuard( Application::GetSolarMutex() );
369 
370     if( ! m_pResMgr )
371         m_pResMgr = SfxResId::GetResMgr();
372 	ResId aResId( id, *m_pResMgr );
373 	aResId.SetRT( RSC_STRING );
374 	if( !m_pResMgr || !m_pResMgr->IsAvailable( aResId ) )
375         return OUString();
376 
377     UniString aRes( ResId(id, *m_pResMgr) );
378     return OUString( aRes );
379 }
380 
381 // ---------------------------------------------------------------------------
382 
383 OUString ShutdownIcon::GetUrlDescription( const OUString& aUrl )
384 {
385     ::vos::OGuard aGuard( Application::GetSolarMutex() );
386 
387     return OUString( SvFileInformationManager::GetDescription( INetURLObject( aUrl ) ) );
388 }
389 
390 // ---------------------------------------------------------------------------
391 
392 void ShutdownIcon::StartFileDialog()
393 {
394     ::vos::OGuard aGuard( Application::GetSolarMutex() );
395 
396     bool bDirty = ( m_bSystemDialogs != static_cast<bool>(SvtMiscOptions().UseSystemFileDialog()) );
397 
398     if ( m_pFileDlg && bDirty )
399     {
400         // Destroy instance as changing the system file dialog setting
401         // forces us to create a new FileDialogHelper instance!
402         delete m_pFileDlg;
403         m_pFileDlg = NULL;
404     }
405 
406     if ( !m_pFileDlg )
407         m_pFileDlg = new FileDialogHelper( WB_OPEN | SFXWB_MULTISELECTION, String() );
408     m_pFileDlg->StartExecuteModal( STATIC_LINK( this, ShutdownIcon, DialogClosedHdl_Impl ) );
409 }
410 
411 // ---------------------------------------------------------------------------
412 
413 IMPL_STATIC_LINK( ShutdownIcon, DialogClosedHdl_Impl, FileDialogHelper*, EMPTYARG )
414 {
415     DBG_ASSERT( pThis->m_pFileDlg, "ShutdownIcon, DialogClosedHdl_Impl(): no file dialog" );
416 
417     // use ctor for filling up filters automatically! #89169#
418     if ( ERRCODE_NONE == pThis->m_pFileDlg->GetError() )
419     {
420         Reference< XFilePicker >    xPicker = pThis->m_pFileDlg->GetFilePicker();
421 
422         try
423         {
424 
425             if ( xPicker.is() )
426             {
427 
428                 Reference < XFilePickerControlAccess > xPickerControls ( xPicker, UNO_QUERY );
429                 Reference < XFilterManager > xFilterManager ( xPicker, UNO_QUERY );
430 
431                 Sequence< OUString >        sFiles = xPicker->getFiles();
432                 int                         nFiles = sFiles.getLength();
433 
434                 int                         nArgs=3;
435                 Sequence< PropertyValue >   aArgs(3);
436 
437                 Reference < com::sun::star::task::XInteractionHandler > xInteraction(
438                     ::comphelper::getProcessServiceFactory()->createInstance( OUString::createFromAscii("com.sun.star.task.InteractionHandler") ),
439                     com::sun::star::uno::UNO_QUERY );
440 
441                 aArgs[0].Name = OUString::createFromAscii( "InteractionHandler" );
442                 aArgs[0].Value <<= xInteraction;
443 
444                 sal_Int16 nMacroExecMode = ::com::sun::star::document::MacroExecMode::USE_CONFIG;
445                 aArgs[1].Name = OUString::createFromAscii( "MacroExecutionMode" );
446                 aArgs[1].Value <<= nMacroExecMode;
447 
448                 sal_Int16 nUpdateDoc = ::com::sun::star::document::UpdateDocMode::ACCORDING_TO_CONFIG;
449                 aArgs[2].Name = OUString::createFromAscii( "UpdateDocMode" );
450                 aArgs[2].Value <<= nUpdateDoc;
451 
452                 // pb: #102643# use the filedlghelper to get the current filter name,
453                 // because it removes the extensions before you get the filter name.
454                 OUString aFilterName( pThis->m_pFileDlg->GetCurrentFilter() );
455 
456                 if ( xPickerControls.is() )
457                 {
458 
459                     // Set readonly flag
460 
461                     sal_Bool    bReadOnly = sal_False;
462 
463 
464                     xPickerControls->getValue( ExtendedFilePickerElementIds::CHECKBOX_READONLY, 0 ) >>= bReadOnly;
465 
466                     // #95239#: Only set porperty if readonly is set to TRUE
467 
468                     if ( bReadOnly )
469                     {
470                         aArgs.realloc( ++nArgs );
471                         aArgs[nArgs-1].Name  = OUString::createFromAscii( "ReadOnly" );
472                         aArgs[nArgs-1].Value <<= bReadOnly;
473                     }
474 
475                     // Get version string
476 
477                     sal_Int32   iVersion = -1;
478 
479                     xPickerControls->getValue( ExtendedFilePickerElementIds::LISTBOX_VERSION, ControlActions::GET_SELECTED_ITEM_INDEX ) >>= iVersion;
480 
481                     if ( iVersion >= 0 )
482                     {
483                         sal_Int16   uVersion = (sal_Int16)iVersion;
484 
485                         aArgs.realloc( ++nArgs );
486                         aArgs[nArgs-1].Name  = OUString::createFromAscii( "Version" );
487                         aArgs[nArgs-1].Value <<= uVersion;
488                     }
489 
490                     // Retrieve the current filter
491 
492                     if ( !aFilterName.getLength() )
493                         xPickerControls->getValue( CommonFilePickerElementIds::LISTBOX_FILTER, ControlActions::GET_SELECTED_ITEM ) >>= aFilterName;
494 
495                 }
496 
497 
498                 // Convert UI filter name to internal filter name
499 
500                 if ( aFilterName.getLength() )
501                 {
502                     const SfxFilter* pFilter = SFX_APP()->GetFilterMatcher().GetFilter4UIName( aFilterName, 0, SFX_FILTER_NOTINFILEDLG );
503 
504                     if ( pFilter )
505                     {
506                         aFilterName = pFilter->GetFilterName();
507 
508                         if ( aFilterName.getLength() )
509                         {
510                             aArgs.realloc( ++nArgs );
511                             aArgs[nArgs-1].Name  = OUString::createFromAscii( "FilterName" );
512                             aArgs[nArgs-1].Value <<= aFilterName;
513                         }
514                     }
515                 }
516 
517                 if ( 1 == nFiles )
518                     OpenURL( sFiles[0], OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ), aArgs );
519                 else
520                 {
521                     OUString    aBaseDirURL = sFiles[0];
522                     if ( aBaseDirURL.getLength() > 0 && aBaseDirURL[aBaseDirURL.getLength()-1] != '/' )
523                         aBaseDirURL += OUString::createFromAscii("/");
524 
525                     int iFiles;
526                     for ( iFiles = 1; iFiles < nFiles; iFiles++ )
527                     {
528                         OUString    aURL = aBaseDirURL;
529                         aURL += sFiles[iFiles];
530                         OpenURL( aURL, OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ), aArgs );
531                     }
532                 }
533             }
534         }
535         catch ( ... )
536         {
537         }
538     }
539 
540 #ifdef WNT
541     // #103346 Destroy dialog to prevent problems with custom controls
542     // This fix is dependent on the dialog settings. Destroying the dialog here will
543     // crash the non-native dialog implementation! Therefore make this dependent on
544     // the settings.
545     if ( SvtMiscOptions().UseSystemFileDialog() )
546     {
547         delete pThis->m_pFileDlg;
548         pThis->m_pFileDlg = NULL;
549     }
550 #endif
551 
552     LeaveModalMode();
553     return 0;
554 }
555 
556 // ---------------------------------------------------------------------------
557 
558 void ShutdownIcon::addTerminateListener()
559 {
560     ShutdownIcon* pInst = getInstance();
561     if ( ! pInst)
562         return;
563 
564     if (pInst->m_bListenForTermination)
565         return;
566 
567     Reference< XDesktop > xDesktop = pInst->m_xDesktop;
568     if ( ! xDesktop.is())
569         return;
570 
571 	xDesktop->addTerminateListener( pInst );
572     pInst->m_bListenForTermination = true;
573 }
574 
575 // ---------------------------------------------------------------------------
576 
577 void ShutdownIcon::terminateDesktop()
578 {
579     ShutdownIcon* pInst = getInstance();
580     if ( ! pInst)
581         return;
582 
583     Reference< XDesktop > xDesktop = pInst->m_xDesktop;
584     if ( ! xDesktop.is())
585         return;
586 
587     // always remove ourselves as listener
588     pInst->m_bListenForTermination = true;
589     xDesktop->removeTerminateListener( pInst );
590 
591     // terminate desktop only if no tasks exist
592     Reference< XFramesSupplier > xSupplier( xDesktop, UNO_QUERY );
593     if ( xSupplier.is() )
594     {
595         Reference< XIndexAccess > xTasks ( xSupplier->getFrames(), UNO_QUERY );
596         if( xTasks.is() && xTasks->getCount() < 1 )
597         {
598             AsyncDesktopTerminationData * pData = new AsyncDesktopTerminationData( xDesktop );
599             if ( !Application::PostUserEvent( STATIC_LINK( 0, ShutdownIcon, AsyncDesktopTermination ), pData ) )
600                 delete pData;
601         }
602     }
603 
604     // remove the instance pointer
605     ShutdownIcon::pShutdownIcon = 0;
606 }
607 
608 
609 IMPL_STATIC_LINK_NOINSTANCE( ShutdownIcon, AsyncDesktopTermination, AsyncDesktopTerminationData*, pData )
610 {
611     if ( pData && pData->mxDesktop.is() )
612         pData->mxDesktop->terminate();
613     delete pData;
614     return 0;
615 }
616 
617 
618 
619 // ---------------------------------------------------------------------------
620 
621 ShutdownIcon* ShutdownIcon::getInstance()
622 {
623 	OSL_ASSERT( pShutdownIcon );
624 	return pShutdownIcon;
625 }
626 
627 // ---------------------------------------------------------------------------
628 
629 ShutdownIcon* ShutdownIcon::createInstance()
630 {
631 	if (pShutdownIcon)
632         return pShutdownIcon;
633 
634 	ShutdownIcon *pIcon = NULL;
635 	try {
636 		Reference< XMultiServiceFactory > xSMgr( comphelper::getProcessServiceFactory() );
637 		pIcon = new ShutdownIcon( xSMgr );
638 		pIcon->init ();
639 		pShutdownIcon = pIcon;
640 	} catch (...) {
641 		delete pIcon;
642 	}
643 
644 	return pShutdownIcon;
645 }
646 
647 void ShutdownIcon::init() throw( ::com::sun::star::uno::Exception )
648 {
649 	// access resource system and sfx only protected by solarmutex
650 	vos::OGuard aSolarGuard( Application::GetSolarMutex() );
651 	ResMgr *pResMgr = SfxResId::GetResMgr();
652 
653 	::osl::ResettableMutexGuard	aGuard(	m_aMutex );
654 	m_pResMgr = pResMgr;
655 	aGuard.clear();
656 	Reference < XDesktop > xDesktop( m_xServiceManager->createInstance(
657 											 DEFINE_CONST_UNICODE( "com.sun.star.frame.Desktop" )),
658 									 UNO_QUERY );
659 	aGuard.reset();
660 	m_xDesktop = xDesktop;
661 }
662 
663 // ---------------------------------------------------------------------------
664 
665 void SAL_CALL ShutdownIcon::disposing()
666 {
667 	m_xServiceManager = Reference< XMultiServiceFactory >();
668 	m_xDesktop = Reference< XDesktop >();
669 }
670 
671 // ---------------------------------------------------------------------------
672 
673 // XEventListener
674 void SAL_CALL ShutdownIcon::disposing( const ::com::sun::star::lang::EventObject& )
675 	throw(::com::sun::star::uno::RuntimeException)
676 {
677 }
678 
679 // ---------------------------------------------------------------------------
680 
681 // XTerminateListener
682 void SAL_CALL ShutdownIcon::queryTermination( const ::com::sun::star::lang::EventObject& )
683 throw(::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException)
684 {
685 	::osl::ClearableMutexGuard	aGuard(	m_aMutex );
686 
687 	if ( m_bVeto )
688 		throw ::com::sun::star::frame::TerminationVetoException();
689 }
690 
691 
692 // ---------------------------------------------------------------------------
693 
694 void SAL_CALL ShutdownIcon::notifyTermination( const ::com::sun::star::lang::EventObject& )
695 throw(::com::sun::star::uno::RuntimeException)
696 {
697 }
698 
699 
700 // ---------------------------------------------------------------------------
701 
702 void SAL_CALL ShutdownIcon::initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any>& aArguments )
703 	throw( ::com::sun::star::uno::Exception )
704 {
705 	::osl::ResettableMutexGuard	aGuard(	m_aMutex );
706 
707     // third argument only sets veto, everything else will be ignored!
708     if (aArguments.getLength() > 2)
709     {
710         sal_Bool bVeto = sal_True;
711         bVeto = ::cppu::any2bool(aArguments[2]);
712         m_bVeto = bVeto;
713         return;
714     }
715 
716 	if ( aArguments.getLength() > 0 )
717 	{
718 		if ( !ShutdownIcon::pShutdownIcon )
719 		{
720 			try
721 			{
722 				sal_Bool bQuickstart = sal_False;
723 				bQuickstart = ::cppu::any2bool( aArguments[0] );
724 				if( !bQuickstart && !GetAutostart() )
725 					return;
726                 aGuard.clear();
727 				init ();
728                 aGuard.reset();
729 				if ( !m_xDesktop.is() )
730 					return;
731 
732 				/* Create a sub-classed instance - foo */
733 				ShutdownIcon::pShutdownIcon = this;
734 				initSystray();
735 #ifdef OS2
736 				// above win32 starts the quickstart thread, but we have
737 				// quickstart running only when -quickstart is specified
738 				// on command line (next boot).
739 				// so if -quickstart was not specified, we cannot issue
740 				// quickstart veto on shutdown.
741 				if (bQuickstart)
742 				{
743 					// disable shutdown
744 					ShutdownIcon::getInstance()->SetVeto( true );
745 					ShutdownIcon::getInstance()->addTerminateListener();
746 				}
747 #endif
748 			}
749 			catch(const ::com::sun::star::lang::IllegalArgumentException&)
750 			{
751 			}
752 		}
753 	}
754     if ( aArguments.getLength() > 1 )
755     {
756 			sal_Bool bAutostart = sal_False;
757 			bAutostart = ::cppu::any2bool( aArguments[1] );
758             if (bAutostart && !GetAutostart())
759                 SetAutostart( sal_True );
760             if (!bAutostart && GetAutostart())
761                 SetAutostart( sal_False );
762     }
763 
764 }
765 
766 // -------------------------------
767 
768 void ShutdownIcon::EnterModalMode()
769 {
770 	bModalMode = sal_True;
771 }
772 
773 // -------------------------------
774 
775 void ShutdownIcon::LeaveModalMode()
776 {
777 	bModalMode = sal_False;
778 }
779 
780 #ifdef WNT
781 // defined in shutdowniconw32.cxx
782 #elif defined(OS2)
783 // defined in shutdowniconOs2.cxx
784 #elif defined QUARTZ
785 // defined in shutdowniconaqua.cxx
786 #else
787 bool ShutdownIcon::IsQuickstarterInstalled()
788 {
789 #ifndef ENABLE_QUICKSTART_APPLET
790 	return false;
791 #else // !ENABLE_QUICKSTART_APPLET
792 #ifdef UNX
793 	return LoadModule( NULL, NULL, NULL);
794 #endif // UNX
795 #endif // !ENABLE_QUICKSTART_APPLET
796 }
797 #endif // !WNT
798 
799 // ---------------------------------------------------------------------------
800 
801 #if defined (ENABLE_QUICKSTART_APPLET) && defined (UNX)
802 static OUString getDotAutostart( bool bCreate = false )
803 {
804 	OUString aShortcut;
805 	const char *pConfigHome;
806 	if( (pConfigHome = getenv("XDG_CONFIG_HOME") ) )
807 		aShortcut = OStringToOUString( OString( pConfigHome ), RTL_TEXTENCODING_UTF8 );
808 	else
809 	{
810 		OUString aHomeURL;
811 		osl::Security().getHomeDir( aHomeURL );
812 		::osl::File::getSystemPathFromFileURL( aHomeURL, aShortcut );
813 		aShortcut += OUString( RTL_CONSTASCII_USTRINGPARAM( "/.config" ) );
814 	}
815 	aShortcut += OUString( RTL_CONSTASCII_USTRINGPARAM( "/autostart" ) );
816 	if (bCreate)
817 	{
818 		OUString aShortcutUrl;
819 		osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
820 		osl::Directory::createPath( aShortcutUrl );
821 	}
822 	return aShortcut;
823 }
824 #endif
825 
826 rtl::OUString ShutdownIcon::getShortcutName()
827 {
828 #ifndef ENABLE_QUICKSTART_APPLET
829 	return OUString();
830 #else
831 
832     OUString aShortcutName( RTL_CONSTASCII_USTRINGPARAM( "StarOffice 6.0" ) );
833 	ResMgr* pMgr = SfxResId::GetResMgr();
834     if( pMgr )
835     {
836         ::vos::OGuard aGuard( Application::GetSolarMutex() );
837         UniString aRes( SfxResId( STR_QUICKSTART_LNKNAME ) );
838         aShortcutName = OUString( aRes );
839     }
840 #ifdef WNT
841     aShortcutName += OUString( RTL_CONSTASCII_USTRINGPARAM( ".lnk" ) );
842 
843 	OUString aShortcut(GetAutostartFolderNameW32());
844 	aShortcut += OUString( RTL_CONSTASCII_USTRINGPARAM( "\\" ) );
845 	aShortcut += aShortcutName;
846 #else // UNX
847     OUStringBuffer aStrBuff( getDotAutostart() );
848     aStrBuff.appendAscii( RTL_CONSTASCII_STRINGPARAM( "/" ) );
849     if ( sal_Int32 len = aShortcutName.getLength() )
850         aStrBuff.append( aShortcutName.getStr(), len );
851     else
852         aStrBuff.appendAscii( RTL_CONSTASCII_STRINGPARAM( "qstart" ) );
853     aStrBuff.appendAscii( RTL_CONSTASCII_STRINGPARAM( ".desktop" ) );
854 
855     OUString aShortcut( aStrBuff.makeStringAndClear() );
856 #endif // UNX
857 	return aShortcut;
858 #endif // ENABLE_QUICKSTART_APPLET
859 }
860 
861 bool ShutdownIcon::GetAutostart( )
862 {
863 #if defined(OS2)
864     return GetAutostartOs2( );
865 #elif defined QUARTZ
866     return true;
867 #else
868 	bool bRet = false;
869 #ifdef ENABLE_QUICKSTART_APPLET
870 	OUString aShortcut( getShortcutName() );
871 	OUString aShortcutUrl;
872 	osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
873 	osl::File f( aShortcutUrl );
874 	osl::File::RC error = f.open( OpenFlag_Read );
875 	if( error == osl::File::E_None )
876 	{
877 		f.close();
878 		bRet = true;
879 	}
880 #endif // ENABLE_QUICKSTART_APPLET
881     return bRet;
882 #endif
883 }
884 
885 void ShutdownIcon::SetAutostart( bool bActivate )
886 {
887 #ifdef ENABLE_QUICKSTART_APPLET
888 	OUString aShortcut( getShortcutName() );
889 
890     if( bActivate && IsQuickstarterInstalled() )
891     {
892 #ifdef WNT
893 		EnableAutostartW32( aShortcut );
894 #else // UNX
895 		getDotAutostart( true );
896 
897 		OUString aPath( RTL_CONSTASCII_USTRINGPARAM("${OOO_BASE_DIR}/share/xdg/qstart.desktop" ) );
898 		Bootstrap::expandMacros( aPath );
899 
900 		OUString aDesktopFile;
901 		::osl::File::getSystemPathFromFileURL( aPath, aDesktopFile );
902 
903 		OString aDesktopFileUnx = OUStringToOString( aDesktopFile,
904 													 osl_getThreadTextEncoding() );
905 		OString aShortcutUnx = OUStringToOString( aShortcut,
906 												  osl_getThreadTextEncoding() );
907 		if ((0 != symlink(aDesktopFileUnx, aShortcutUnx)) && (errno == EEXIST))
908 		{
909 		unlink(aShortcutUnx);
910 		symlink(aDesktopFileUnx, aShortcutUnx);
911 		}
912 
913 		ShutdownIcon *pIcon = ShutdownIcon::createInstance();
914 		if( pIcon )
915 			pIcon->initSystray();
916 #endif // UNX
917     }
918     else
919     {
920         OUString aShortcutUrl;
921         ::osl::File::getFileURLFromSystemPath( aShortcut, aShortcutUrl );
922         ::osl::File::remove( aShortcutUrl );
923 #ifdef UNX
924 		if (pShutdownIcon)
925 		{
926 		    ShutdownIcon *pIcon = getInstance();
927 			pIcon->deInitSystray();
928 		}
929 #endif
930     }
931 #elif defined OS2
932     SetAutostartOs2( bActivate );
933 #else
934     (void)bActivate; // unused variable
935 #endif // ENABLE_QUICKSTART_APPLET
936 }
937 
938 static const ::sal_Int32 PROPHANDLE_TERMINATEVETOSTATE = 0;
939 
940 // XFastPropertySet
941 void SAL_CALL ShutdownIcon::setFastPropertyValue(       ::sal_Int32                  nHandle,
942                                                   const ::com::sun::star::uno::Any& aValue )
943     throw (::com::sun::star::beans::UnknownPropertyException,
944             ::com::sun::star::beans::PropertyVetoException,
945             ::com::sun::star::lang::IllegalArgumentException,
946             ::com::sun::star::lang::WrappedTargetException,
947             ::com::sun::star::uno::RuntimeException)
948 {
949     switch(nHandle)
950     {
951         case PROPHANDLE_TERMINATEVETOSTATE :
952              {
953                 // use new value in case it's a valid information only
954                 ::sal_Bool bState( sal_False );
955                 if (! (aValue >>= bState))
956                     return;
957 
958                 m_bVeto = bState;
959                 if (m_bVeto && ! m_bListenForTermination)
960                     addTerminateListener();
961              }
962              break;
963 
964         default :
965             throw ::com::sun::star::beans::UnknownPropertyException();
966     }
967 }
968 
969 // XFastPropertySet
970 ::com::sun::star::uno::Any SAL_CALL ShutdownIcon::getFastPropertyValue( ::sal_Int32 nHandle )
971     throw (::com::sun::star::beans::UnknownPropertyException,
972             ::com::sun::star::lang::WrappedTargetException,
973             ::com::sun::star::uno::RuntimeException)
974 {
975     ::com::sun::star::uno::Any aValue;
976     switch(nHandle)
977     {
978         case PROPHANDLE_TERMINATEVETOSTATE :
979              {
980                 bool bState   = (m_bListenForTermination && m_bVeto);
981                      aValue <<= bState;
982              }
983              break;
984 
985         default :
986             throw ::com::sun::star::beans::UnknownPropertyException();
987     }
988 
989     return aValue;
990 }
991