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