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