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