1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_framework.hxx"
26 
27 //_______________________________________________
28 // my own includes
29 #include <dispatch/closedispatcher.hxx>
30 #include <pattern/frame.hxx>
31 #include <threadhelp/readguard.hxx>
32 #include <threadhelp/writeguard.hxx>
33 #include <framework/framelistanalyzer.hxx>
34 #include <services.h>
35 #include <general.h>
36 
37 //_______________________________________________
38 // interface includes
39 #include <com/sun/star/frame/XDesktop.hpp>
40 #include <com/sun/star/frame/XController.hpp>
41 #include <com/sun/star/frame/CommandGroup.hpp>
42 #include <com/sun/star/lang/DisposedException.hpp>
43 #include <com/sun/star/awt/XTopWindow.hpp>
44 #include <com/sun/star/document/XActionLockable.hpp>
45 #include "com/sun/star/beans/XFastPropertySet.hpp"
46 #include <toolkit/helper/vclunohelper.hxx>
47 
48 //_______________________________________________
49 // includes of other projects
50 
51 #include <vcl/window.hxx>
52 #include <vcl/svapp.hxx>
53 #include <vos/mutex.hxx>
54 #include <unotools/moduleoptions.hxx>
55 
56 //_______________________________________________
57 // namespace
58 
59 namespace framework{
60 
61 #ifdef fpf
62     #error "Who uses \"fpf\" as define. It will overwrite my namespace alias ..."
63 #endif
64 namespace fpf = ::framework::pattern::frame;
65 
66 //_______________________________________________
67 // non exported const
68 
69 static ::rtl::OUString URL_CLOSEDOC    = DECLARE_ASCII(".uno:CloseDoc"  );
70 static ::rtl::OUString URL_CLOSEWIN    = DECLARE_ASCII(".uno:CloseWin"  );
71 static ::rtl::OUString URL_CLOSEFRAME  = DECLARE_ASCII(".uno:CloseFrame");
72 
73 //_______________________________________________
74 // declarations
75 
DEFINE_XINTERFACE_4(CloseDispatcher,OWeakObject,DIRECT_INTERFACE (css::lang::XTypeProvider),DIRECT_INTERFACE (css::frame::XNotifyingDispatch),DIRECT_INTERFACE (css::frame::XDispatch),DIRECT_INTERFACE (css::frame::XDispatchInformationProvider))76 DEFINE_XINTERFACE_4(CloseDispatcher                                           ,
77                     OWeakObject                                               ,
78                     DIRECT_INTERFACE(css::lang::XTypeProvider                ),
79                     DIRECT_INTERFACE(css::frame::XNotifyingDispatch          ),
80                     DIRECT_INTERFACE(css::frame::XDispatch                   ),
81                     DIRECT_INTERFACE(css::frame::XDispatchInformationProvider))
82 
83 // Note: XStatusListener is an implementation detail. Hide it for scripting!
84 DEFINE_XTYPEPROVIDER_4(CloseDispatcher                         ,
85                        css::lang::XTypeProvider                ,
86                        css::frame::XDispatchInformationProvider,
87                        css::frame::XNotifyingDispatch          ,
88                        css::frame::XDispatch                   )
89 
90 //-----------------------------------------------
91 CloseDispatcher::CloseDispatcher(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR  ,
92                                  const css::uno::Reference< css::frame::XFrame >&              xFrame ,
93                                  const ::rtl::OUString&                                        sTarget)
94     : ThreadHelpBase     (&Application::GetSolarMutex()                   )
95     , ::cppu::OWeakObject(                                                )
96     , m_xSMGR            (xSMGR                                           )
97     , m_aAsyncCallback   (LINK( this, CloseDispatcher, impl_asyncCallback))
98     , m_lStatusListener  (m_aLock.getShareableOslMutex()                  )
99 {
100     m_xCloseFrame = CloseDispatcher::static_impl_searchRightTargetFrame(xFrame, sTarget);
101 }
102 
103 //-----------------------------------------------
~CloseDispatcher()104 CloseDispatcher::~CloseDispatcher()
105 {
106 }
107 
108 //-----------------------------------------------
dispatch(const css::util::URL & aURL,const css::uno::Sequence<css::beans::PropertyValue> & lArguments)109 void SAL_CALL CloseDispatcher::dispatch(const css::util::URL&                                  aURL      ,
110                                         const css::uno::Sequence< css::beans::PropertyValue >& lArguments)
111     throw(css::uno::RuntimeException)
112 {
113     dispatchWithNotification(aURL, lArguments, css::uno::Reference< css::frame::XDispatchResultListener >());
114 }
115 
116 //-----------------------------------------------
getSupportedCommandGroups()117 css::uno::Sequence< sal_Int16 > SAL_CALL CloseDispatcher::getSupportedCommandGroups()
118     throw(css::uno::RuntimeException)
119 {
120     css::uno::Sequence< sal_Int16 > lGroups(2);
121     lGroups[0] = css::frame::CommandGroup::VIEW;
122     lGroups[1] = css::frame::CommandGroup::DOCUMENT;
123     return lGroups;
124 }
125 
126 //-----------------------------------------------
getConfigurableDispatchInformation(sal_Int16 nCommandGroup)127 css::uno::Sequence< css::frame::DispatchInformation > SAL_CALL CloseDispatcher::getConfigurableDispatchInformation(sal_Int16 nCommandGroup)
128     throw(css::uno::RuntimeException)
129 {
130     if (nCommandGroup == css::frame::CommandGroup::VIEW)
131     {
132         /* Attention: Don't add .uno:CloseFrame here. Because it's not really
133                       a configurable feature ... and further it does not have
134                       a valid UIName entry inside the GenericCommands.xcu ... */
135         css::uno::Sequence< css::frame::DispatchInformation > lViewInfos(1);
136         lViewInfos[0].Command = URL_CLOSEWIN;
137         lViewInfos[0].GroupId = css::frame::CommandGroup::VIEW;
138         return lViewInfos;
139     }
140     else
141     if (nCommandGroup == css::frame::CommandGroup::DOCUMENT)
142     {
143         css::uno::Sequence< css::frame::DispatchInformation > lDocInfos(1);
144         lDocInfos[0].Command = URL_CLOSEDOC;
145         lDocInfos[0].GroupId = css::frame::CommandGroup::DOCUMENT;
146         return lDocInfos;
147     }
148 
149     return css::uno::Sequence< css::frame::DispatchInformation >();
150 }
151 
152 //-----------------------------------------------
addStatusListener(const css::uno::Reference<css::frame::XStatusListener> &,const css::util::URL &)153 void SAL_CALL CloseDispatcher::addStatusListener(const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/,
154                                                  const css::util::URL&                                     /*aURL*/     )
155     throw(css::uno::RuntimeException)
156 {
157 }
158 
159 //-----------------------------------------------
removeStatusListener(const css::uno::Reference<css::frame::XStatusListener> &,const css::util::URL &)160 void SAL_CALL CloseDispatcher::removeStatusListener(const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/,
161                                                     const css::util::URL&                                     /*aURL*/     )
162     throw(css::uno::RuntimeException)
163 {
164 }
165 
166 //-----------------------------------------------
dispatchWithNotification(const css::util::URL & aURL,const css::uno::Sequence<css::beans::PropertyValue> & lArguments,const css::uno::Reference<css::frame::XDispatchResultListener> & xListener)167 void SAL_CALL CloseDispatcher::dispatchWithNotification(const css::util::URL&                                             aURL      ,
168                                                         const css::uno::Sequence< css::beans::PropertyValue >&            lArguments,
169                                                         const css::uno::Reference< css::frame::XDispatchResultListener >& xListener )
170     throw(css::uno::RuntimeException)
171 {
172     // SAFE -> ----------------------------------
173     WriteGuard aWriteLock(m_aLock);
174 
175     // This reference indicates, that we already called before and
176     // our asynchronous process was not finished yet.
177     // We have to reject double calls. Otherwise we risk,
178     // that we try to close an already closed resource ...
179     // And it's no problem to do nothing then. The UI user will try it again, if
180     // none of these jobs was successfully.
181     if (m_xSelfHold.is())
182     {
183         aWriteLock.unlock();
184         // <- SAFE ------------------------------
185 
186         implts_notifyResultListener(
187             xListener,
188             css::frame::DispatchResultState::DONTKNOW,
189             css::uno::Any());
190         return;
191     }
192 
193     // First we have to check, if this dispatcher is used right. Means if valid URLs are used.
194     // If not - we have to break this operation. But an optional listener must be informed.
195     // BTW: We save the information about the requested operation. Because
196     // we need it later.
197     if (aURL.Complete.equals(URL_CLOSEDOC))
198         m_eOperation = E_CLOSE_DOC;
199     else
200     if (aURL.Complete.equals(URL_CLOSEWIN))
201         m_eOperation = E_CLOSE_WIN;
202     else
203     if (aURL.Complete.equals(URL_CLOSEFRAME))
204         m_eOperation = E_CLOSE_FRAME;
205     else
206     {
207         aWriteLock.unlock();
208         // <- SAFE ------------------------------
209 
210         implts_notifyResultListener(
211             xListener,
212             css::frame::DispatchResultState::FAILURE,
213             css::uno::Any());
214         return;
215     }
216 
217     // OK - URLs are the right ones.
218     // But we can't execute synchronously :-)
219     // May we are called from a generic key-input handler,
220     // which isn't aware that this call kill its own environment ...
221     // Do it asynchronous every time!
222 
223     // But don't forget to hold usself alive.
224     // We are called back from an environment, which doesn't know an uno reference.
225     // They call us back by using our c++ interface.
226 
227     m_xResultListener = xListener;
228     m_xSelfHold       = css::uno::Reference< css::uno::XInterface >(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
229 
230     aWriteLock.unlock();
231     // <- SAFE ----------------------------------
232 
233 	sal_Bool bIsSynchron = sal_False;
234 	for (sal_Int32 nArgs=0; nArgs<lArguments.getLength(); nArgs++ )
235 	{
236 		if ( lArguments[nArgs].Name.equalsAscii("SynchronMode") )
237 		{
238 			lArguments[nArgs].Value >>= bIsSynchron;
239 			break;
240 		}
241 	}
242 
243 	if ( bIsSynchron )
244 		impl_asyncCallback(0);
245 	else
246 		m_aAsyncCallback.Post(0);
247 }
248 
249 //-----------------------------------------------
250 /**
251     @short      asynchronous callback
252     @descr      We start all actions inside this object asynchronous.
253                 (see comments there).
254                 Now we do the following:
255                 - close all views to the same document, if needed and possible
256                 - make the current frame empty
257                   ! This step is necessary to handle errors during closing the
258                     document inside the frame. May the document shows a dialog and
259                     the user ignore it. Then the state of the office can be changed
260                     during we try to close frame and document.
261                 - check the environment (means count open frames - excluding our
262                   current one)
263                 - decide then, if we must close this frame only, establish the backing mode
264                   or shutdown the whole application.
265 */
IMPL_LINK(CloseDispatcher,impl_asyncCallback,void *,EMPTYARG)266 IMPL_LINK( CloseDispatcher, impl_asyncCallback, void*, EMPTYARG )
267 {
268     try
269     {
270 
271     // Allow calling of XController->suspend() every time.
272     // Dispatch is an UI functionality. We implement such dispatch object here.
273     // And further XController->suspend() was designed to bring an UI ...
274     sal_Bool bAllowSuspend        = sal_True;
275     sal_Bool bControllerSuspended = sal_False;
276 
277     // SAFE -> ----------------------------------
278     ReadGuard aReadLock(m_aLock);
279 
280     // Closing of all views, related to the same document, is allowed
281     // only if the dispatched URL was ".uno:CloseDoc"!
282     sal_Bool bCloseAllViewsToo = (m_eOperation == E_CLOSE_DOC);
283 
284     // BTW: Make some copies, which are needed later ...
285     EOperation                                                  eOperation  = m_eOperation;
286     css::uno::Reference< css::lang::XMultiServiceFactory >      xSMGR       = m_xSMGR;
287     css::uno::Reference< css::frame::XFrame >                   xCloseFrame (m_xCloseFrame.get(), css::uno::UNO_QUERY);
288     css::uno::Reference< css::frame::XDispatchResultListener >  xListener   = m_xResultListener;
289 
290     aReadLock.unlock();
291     // <- SAFE ----------------------------------
292 
293     // frame already dead ?!
294     // Nothing to do !
295     if (! xCloseFrame.is())
296         return 0;
297 
298     sal_Bool bCloseFrame           = sal_False;
299     sal_Bool bEstablishBackingMode = sal_False;
300     sal_Bool bTerminateApp         = sal_False;
301 
302     // Analyze the environment a first time.
303     // If we found some special cases, we can
304     // make some decisions erliar!
305     css::uno::Reference< css::frame::XFramesSupplier > xDesktop(xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY_THROW);
306     FrameListAnalyzer aCheck1(xDesktop, xCloseFrame, FrameListAnalyzer::E_HELP | FrameListAnalyzer::E_BACKINGCOMPONENT);
307 
308     // a) If the current frame (where the close dispatch was requested for) does not have
309     //    any parent frame ... it will close this frame only. Such frame isn't part of the
310     //    global desktop tree ... and such frames are used as "implementation details" only.
311     //    E.g. the live previews of our wizards doing such things. And then the owner of the frame
312     //    is responsible for closing the application or accepting closing of the application
313     //    by others.
314     if ( ! xCloseFrame->getCreator().is())
315         bCloseFrame = sal_True;
316     else
317 
318     // b) The help window can't disagree with any request.
319     //    Because it doesn't implement a controller - it uses a window only.
320     //    Further t can't be the last open frame - if we do all other things
321     //    right inside this CloseDispatcher implementation.
322     //    => close it!
323     if (aCheck1.m_bReferenceIsHelp)
324         bCloseFrame = sal_True;
325     else
326 
327     // c) If we are already in "backing mode", we have to terminate
328     //    the application, if this special frame is closed.
329     //    It doesn't matter, how many other frames (can be the help or hidden frames only)
330     //    are open then.
331     //    => terminate the application!
332     if (aCheck1.m_bReferenceIsBacking)
333         bTerminateApp = sal_True;
334     else
335 
336     // d) Otherwise we have to: close all views to the same document, close the
337     //    document inside our own frame and decide then again, what has to be done!
338     {
339         if (implts_prepareFrameForClosing(m_xCloseFrame, bAllowSuspend, bCloseAllViewsToo, bControllerSuspended))
340         {
341             // OK; this frame is empty now.
342             // Check the environment again to decide, what is the next step.
343             FrameListAnalyzer aCheck2(xDesktop, xCloseFrame, FrameListAnalyzer::E_ALL);
344 
345             // c1) there is as minimum 1 frame open, which is visible and contains a document
346             //     different from our one. And its not the help!
347             //     => close our frame only - nothing else.
348             if (aCheck2.m_lOtherVisibleFrames.getLength()>0)
349                 bCloseFrame = sal_True;
350             else
351 
352             // c2) if we close the current view ... but not all other views
353             //     to the same document, we must close the current frame only!
354             //     Because implts_closeView() suspended this view only - does not
355             //     close the frame.
356             if (
357                 (!bCloseAllViewsToo                    ) &&
358                 (aCheck2.m_lModelFrames.getLength() > 0)
359                )
360                 bCloseFrame = sal_True;
361 
362 			else
363             // c3) there is no other (visible) frame open ...
364             //     The help module will be ignored every time!
365             //     But we have to decide if we must terminate the
366             //     application or establish the backing mode now.
367             //     And that depends from the dispatched URL ...
368             {
369                 if (eOperation == E_CLOSE_FRAME)
370                     bTerminateApp = sal_True;
371                 else if( SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::E_SSTARTMODULE) )
372                     bEstablishBackingMode = sal_True;
373                 else
374                     bTerminateApp = sal_True;
375             }
376         }
377     }
378 
379     // Do it now ...
380     sal_Bool bSuccess = sal_False;
381     if (bCloseFrame)
382         bSuccess = implts_closeFrame();
383     else
384     if (bEstablishBackingMode)
385     #if defined QUARTZ
386     {
387         // on mac close down, quickstarter keeps the process alive
388         // however if someone has shut down the quickstarter
389         // behave as any other platform
390 
391         bool bQuickstarterRunning = false;
392         // get quickstart service
393         try
394         {
395             css::uno::Reference< css::beans::XFastPropertySet > xSet( xSMGR->createInstance(IMPLEMENTATIONNAME_QUICKLAUNCHER), css::uno::UNO_QUERY_THROW );
396             if( xSet.is() )
397             {
398                 css::uno::Any aVal( xSet->getFastPropertyValue( 0 ) );
399                 sal_Bool bState = sal_False;
400                 if( aVal >>= bState )
401                     bQuickstarterRunning = bState;
402             }
403         }
404         catch( css::uno::Exception& )
405         {
406         }
407         bSuccess = bQuickstarterRunning ? implts_terminateApplication() : implts_establishBackingMode();
408     }
409     #else
410         bSuccess = implts_establishBackingMode();
411     #endif
412     else
413     if (bTerminateApp)
414         bSuccess = implts_terminateApplication();
415 
416     if (
417         ( ! bSuccess             ) &&
418         (   bControllerSuspended )
419        )
420     {
421         css::uno::Reference< css::frame::XController > xController = xCloseFrame->getController();
422         if (xController.is())
423             xController->suspend(sal_False);
424     }
425 
426     // inform listener
427     sal_Int16 nState = css::frame::DispatchResultState::FAILURE;
428     if (bSuccess)
429         nState = css::frame::DispatchResultState::SUCCESS;
430     implts_notifyResultListener(xListener, nState, css::uno::Any());
431 
432     // SAFE -> ----------------------------------
433     WriteGuard aWriteLock(m_aLock);
434 
435     // This method was called asynchronous from our main thread by using a pointer.
436     // We reached this method only, by using a reference to ourself :-)
437     // Further this member is used to detect still running and not yet finished
438     // asynchronous operations. So its time now to release this reference.
439     // But hold it temp alive. Otherwise we die before we can finish this method really :-))
440     css::uno::Reference< css::uno::XInterface > xTempHold = m_xSelfHold;
441     m_xSelfHold.clear();
442     m_xResultListener.clear();
443 
444     aWriteLock.unlock();
445     // <- SAFE ----------------------------------
446 
447     }
448     catch(const css::lang::DisposedException&)
449     {
450         LOG_ERROR("CloseDispatcher::impl_asyncCallback", "Congratulation! You found the reason for bug #120310#. Please contact the right developer and show him a scenario, which trigger this bug. THX.")
451     }
452 
453     return 0;
454 }
455 
456 //-----------------------------------------------
implts_prepareFrameForClosing(const css::uno::Reference<css::frame::XFrame> & xFrame,sal_Bool bAllowSuspend,sal_Bool bCloseAllOtherViewsToo,sal_Bool & bControllerSuspended)457 sal_Bool CloseDispatcher::implts_prepareFrameForClosing(const css::uno::Reference< css::frame::XFrame >& xFrame                ,
458                                                               sal_Bool                                   bAllowSuspend         ,
459                                                               sal_Bool                                   bCloseAllOtherViewsToo,
460                                                               sal_Bool&                                  bControllerSuspended  )
461 {
462     // Frame already dead ... so this view is closed ... is closed ... is ... .-)
463     if (! xFrame.is())
464         return sal_True;
465 
466     // Close all views to the same document ... if forced to do so.
467     // But don't touch our own frame here!
468     // We must do so ... because the may be following controller->suspend()
469     // will show the "save/discard/cancel" dialog for the last view only!
470     if (bCloseAllOtherViewsToo)
471     {
472         // SAFE -> ----------------------------------
473         ReadGuard aReadLock(m_aLock);
474         css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
475         aReadLock.unlock();
476         // <- SAFE ----------------------------------
477 
478         css::uno::Reference< css::frame::XFramesSupplier > xDesktop(xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY_THROW);
479         FrameListAnalyzer aCheck(xDesktop, xFrame, FrameListAnalyzer::E_ALL);
480 
481         sal_Int32 c = aCheck.m_lModelFrames.getLength();
482         sal_Int32 i = 0;
483         for (i=0; i<c; ++i)
484         {
485             if (!fpf::closeIt(aCheck.m_lModelFrames[i], sal_False))
486                 return sal_False;
487         }
488     }
489 
490     // If allowed - inform user about modified documents or
491     // still running jobs (e.g. printing).
492     if (bAllowSuspend)
493     {
494         css::uno::Reference< css::frame::XController > xController = xFrame->getController();
495         if (xController.is()) // some views don't uses a controller .-( (e.g. the help window)
496         {
497             bControllerSuspended = xController->suspend(sal_True);
498             if (! bControllerSuspended)
499                 return sal_False;
500         }
501     }
502 
503     // don't remove the component really by e.g. calling setComponent(null, null).
504     // It's enough to suspend the controller.
505     // If we close the frame later this controller doesn't show the same dialog again.
506     return sal_True;
507 }
508 
509 //-----------------------------------------------
implts_closeFrame()510 sal_Bool CloseDispatcher::implts_closeFrame()
511 {
512     // SAFE -> ----------------------------------
513     ReadGuard aReadLock(m_aLock);
514     css::uno::Reference< css::frame::XFrame > xFrame (m_xCloseFrame.get(), css::uno::UNO_QUERY);
515     aReadLock.unlock();
516     // <- SAFE ----------------------------------
517 
518     // frame already dead ? => so it's closed ... it's closed ...
519     if ( ! xFrame.is() )
520         return sal_True;
521 
522     // don't deliver ownership; our "UI user" will try it again if it failed.
523     // OK - he will get an empty frame then. But normally an empty frame
524     // should be closeable always :-)
525     if (!fpf::closeIt(xFrame, sal_False))
526         return sal_False;
527 
528     // SAFE -> ----------------------------------
529     WriteGuard aWriteLock(m_aLock);
530     m_xCloseFrame = css::uno::WeakReference< css::frame::XFrame >();
531     aWriteLock.unlock();
532     // <- SAFE ----------------------------------
533 
534     return sal_True;
535 }
536 
537 //-----------------------------------------------
implts_establishBackingMode()538 sal_Bool CloseDispatcher::implts_establishBackingMode()
539 {
540     // SAFE -> ----------------------------------
541     ReadGuard aReadLock(m_aLock);
542     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
543     css::uno::Reference< css::frame::XFrame >              xFrame (m_xCloseFrame.get(), css::uno::UNO_QUERY);
544     aReadLock.unlock();
545     // <- SAFE ----------------------------------
546 
547     if (!xFrame.is())
548         return sal_False;
549 
550 	css::uno::Reference < css::document::XActionLockable > xLock( xFrame, css::uno::UNO_QUERY );
551 	if ( xLock.is() && xLock->isActionLocked() )
552 		return sal_False;
553 
554     css::uno::Reference< css::awt::XWindow > xContainerWindow = xFrame->getContainerWindow();
555     css::uno::Sequence< css::uno::Any > lArgs(1);
556     lArgs[0] <<= xContainerWindow;
557 
558     css::uno::Reference< css::frame::XController > xBackingComp(
559         xSMGR->createInstanceWithArguments(SERVICENAME_STARTMODULE, lArgs),
560         css::uno::UNO_QUERY_THROW);
561 
562     // Attention: You MUST(!) call setComponent() before you call attachFrame().
563     css::uno::Reference< css::awt::XWindow > xBackingWin(xBackingComp, css::uno::UNO_QUERY);
564     xFrame->setComponent(xBackingWin, xBackingComp);
565     xBackingComp->attachFrame(xFrame);
566     xContainerWindow->setVisible(sal_True);
567 
568     return sal_True;
569 }
570 
571 //-----------------------------------------------
implts_terminateApplication()572 sal_Bool CloseDispatcher::implts_terminateApplication()
573 {
574     // SAFE -> ----------------------------------
575     ReadGuard aReadLock(m_aLock);
576     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
577     aReadLock.unlock();
578     // <- SAFE ----------------------------------
579 
580     css::uno::Reference< css::frame::XDesktop > xDesktop(
581         xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY_THROW);
582 
583     return xDesktop->terminate();
584 }
585 
586 //-----------------------------------------------
implts_notifyResultListener(const css::uno::Reference<css::frame::XDispatchResultListener> & xListener,sal_Int16 nState,const css::uno::Any & aResult)587 void CloseDispatcher::implts_notifyResultListener(const css::uno::Reference< css::frame::XDispatchResultListener >& xListener,
588                                                         sal_Int16                                                   nState   ,
589                                                   const css::uno::Any&                                              aResult  )
590 {
591     if (!xListener.is())
592         return;
593 
594     css::frame::DispatchResultEvent aEvent(
595         css::uno::Reference< css::uno::XInterface >(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY),
596         nState,
597         aResult);
598 
599     xListener->dispatchFinished(aEvent);
600 }
601 
602 //-----------------------------------------------
static_impl_searchRightTargetFrame(const css::uno::Reference<css::frame::XFrame> & xFrame,const::rtl::OUString & sTarget)603 css::uno::Reference< css::frame::XFrame > CloseDispatcher::static_impl_searchRightTargetFrame(const css::uno::Reference< css::frame::XFrame >& xFrame ,
604                                                                                               const ::rtl::OUString&                           sTarget)
605 {
606     if (sTarget.equalsIgnoreAsciiCaseAscii("_self"))
607         return xFrame;
608 
609     OSL_ENSURE((sTarget.getLength() < 1), "CloseDispatch used for unexpected target. Magic things will happen now .-)");
610 
611     css::uno::Reference< css::frame::XFrame > xTarget = xFrame;
612     while(sal_True)
613     {
614         // a) top frames will be closed
615         if (xTarget->isTop())
616             return xTarget;
617 
618         // b) even child frame containing top level windows (e.g. query designer of database) will be closed
619         css::uno::Reference< css::awt::XWindow >    xWindow        = xTarget->getContainerWindow();
620         css::uno::Reference< css::awt::XTopWindow > xTopWindowCheck(xWindow, css::uno::UNO_QUERY);
621         if (xTopWindowCheck.is())
622         {
623             // b1) Note: Toolkit interface XTopWindow sometimes is used by real VCL-child-windows also .-)
624             //     Be sure that these window is really a "top system window".
625             //     Attention ! Checking Window->GetParent() isn't the right approach here.
626             //     Because sometimes VCL create "implicit border windows" as parents even we created
627             //     a simple XWindow using the toolkit only .-(
628             ::vos::OGuard aSolarLock(&Application::GetSolarMutex());
629             Window* pWindow = VCLUnoHelper::GetWindow( xWindow );
630             if (
631                 (pWindow				  ) &&
632                 (pWindow->IsSystemWindow())
633                )
634                 return xTarget;
635         }
636 
637         // c) try to find better results on parent frame
638         //    If no parent frame exists (because this frame is used outside the desktop tree)
639         //    the given frame must be used directly.
640         css::uno::Reference< css::frame::XFrame > xParent(xTarget->getCreator(), css::uno::UNO_QUERY);
641         if ( ! xParent.is())
642             return xTarget;
643 
644         // c1) check parent frame inside next loop ...
645         xTarget = xParent;
646     }
647 }
648 
649 } // namespace framework
650