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