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 //_________________________________________________________________________________________________________________
30 #include <pattern/window.hxx>
31 #include <helper/persistentwindowstate.hxx>
32 #include <threadhelp/writeguard.hxx>
33 #include <threadhelp/readguard.hxx>
34 #include <macros/generic.hxx>
35 #include <services.h>
36 
37 //_________________________________________________________________________________________________________________
38 //	interface includes
39 //_________________________________________________________________________________________________________________
40 #include <com/sun/star/awt/XWindow.hpp>
41 
42 #ifndef _COM_SUN_STAR_LANG_XSERVICXEINFO_HPP_
43 #include <com/sun/star/lang/XServiceInfo.hpp>
44 #endif
45 #include <com/sun/star/lang/IllegalArgumentException.hpp>
46 #include <com/sun/star/frame/XModuleManager.hpp>
47 
48 //_________________________________________________________________________________________________________________
49 //	other includes
50 //_________________________________________________________________________________________________________________
51 #include <comphelper/configurationhelper.hxx>
52 #include <vcl/window.hxx>
53 #include <vcl/syswin.hxx>
54 
55 #ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_
56 #include <toolkit/unohlp.hxx>
57 #endif
58 #include <vcl/svapp.hxx>
59 #include <vcl/wrkwin.hxx>
60 #include <rtl/string.hxx>
61 
62 //_________________________________________________________________________________________________________________
63 //	namespace
64 
65 namespace framework{
66 
67 //_________________________________________________________________________________________________________________
68 //	definitions
69 
70 //*****************************************************************************************************************
71 //  XInterface, XTypeProvider
72 
73 DEFINE_XINTERFACE_4(PersistentWindowState                                                       ,
74                     OWeakObject                                                                 ,
75                     DIRECT_INTERFACE (css::lang::XTypeProvider                                  ),
76                     DIRECT_INTERFACE (css::lang::XInitialization                                ),
77                     DIRECT_INTERFACE (css::frame::XFrameActionListener                          ),
78                     DERIVED_INTERFACE(css::lang::XEventListener,css::frame::XFrameActionListener))
79 
80 DEFINE_XTYPEPROVIDER_4(PersistentWindowState           ,
81                        css::lang::XTypeProvider        ,
82                        css::lang::XInitialization      ,
83                        css::frame::XFrameActionListener,
84                        css::lang::XEventListener       )
85 
86 //*****************************************************************************************************************
87 PersistentWindowState::PersistentWindowState(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
88     : ThreadHelpBase          (&Application::GetSolarMutex())
89     , m_xSMGR                 (xSMGR                        )
90     , m_bWindowStateAlreadySet(sal_False                    )
91 {
92 }
93 
94 //*****************************************************************************************************************
95 PersistentWindowState::~PersistentWindowState()
96 {
97 }
98 
99 //*****************************************************************************************************************
100 void SAL_CALL PersistentWindowState::initialize(const css::uno::Sequence< css::uno::Any >& lArguments)
101     throw(css::uno::Exception       ,
102           css::uno::RuntimeException)
103 {
104     // check arguments
105     css::uno::Reference< css::frame::XFrame > xFrame;
106     if (lArguments.getLength() < 1)
107         throw css::lang::IllegalArgumentException(
108                 DECLARE_ASCII("Empty argument list!"),
109                 static_cast< ::cppu::OWeakObject* >(this),
110                 1);
111 
112     lArguments[0] >>= xFrame;
113     if (!xFrame.is())
114         throw css::lang::IllegalArgumentException(
115                 DECLARE_ASCII("No valid frame specified!"),
116                 static_cast< ::cppu::OWeakObject* >(this),
117                 1);
118 
119     // SAFE -> ----------------------------------
120     WriteGuard aWriteLock(m_aLock);
121     // hold the frame as weak reference(!) so it can die everytimes :-)
122     m_xFrame = xFrame;
123     aWriteLock.unlock();
124     // <- SAFE ----------------------------------
125 
126     // start listening
127     xFrame->addFrameActionListener(this);
128 }
129 
130 //*****************************************************************************************************************
131 void SAL_CALL PersistentWindowState::frameAction(const css::frame::FrameActionEvent& aEvent)
132     throw(css::uno::RuntimeException)
133 {
134     // SAFE -> ----------------------------------
135     ReadGuard aReadLock(m_aLock);
136     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR ;
137     css::uno::Reference< css::frame::XFrame >              xFrame(m_xFrame.get(), css::uno::UNO_QUERY);
138     sal_Bool                                               bRestoreWindowState = !m_bWindowStateAlreadySet;
139     aReadLock.unlock();
140     // <- SAFE ----------------------------------
141 
142     // frame already gone ? We hold it weak only ...
143     if (!xFrame.is())
144         return;
145 
146     // no window -> no position and size available
147     css::uno::Reference< css::awt::XWindow > xWindow = xFrame->getContainerWindow();
148     if (!xWindow.is())
149         return;
150 
151     // unknown module -> no configuration available!
152     ::rtl::OUString sModuleName = PersistentWindowState::implst_identifyModule(xSMGR, xFrame);
153     if (!sModuleName.getLength())
154         return;
155 
156     switch(aEvent.Action)
157     {
158         case css::frame::FrameAction_COMPONENT_ATTACHED :
159             {
160                 if (bRestoreWindowState)
161                 {
162                     ::rtl::OUString sWindowState = PersistentWindowState::implst_getWindowStateFromConfig(xSMGR, sModuleName);
163                     PersistentWindowState::implst_setWindowStateOnWindow(xWindow,sWindowState);
164                     // SAFE -> ----------------------------------
165                     WriteGuard aWriteLock(m_aLock);
166                     m_bWindowStateAlreadySet = sal_True;
167                     aWriteLock.unlock();
168                     // <- SAFE ----------------------------------
169                 }
170             }
171             break;
172 
173         case css::frame::FrameAction_COMPONENT_REATTACHED :
174             {
175                 // nothing todo here, because its not allowed to change position and size
176                 // of an alredy existing frame!
177             }
178             break;
179 
180         case css::frame::FrameAction_COMPONENT_DETACHING :
181             {
182                 ::rtl::OUString sWindowState = PersistentWindowState::implst_getWindowStateFromWindow(xWindow);
183                 PersistentWindowState::implst_setWindowStateOnConfig(xSMGR, sModuleName, sWindowState);
184             }
185             break;
186         default:
187             break;
188     }
189 }
190 
191 //*****************************************************************************************************************
192 void SAL_CALL PersistentWindowState::disposing(const css::lang::EventObject&)
193     throw(css::uno::RuntimeException)
194 {
195     // nothing todo here - because we hold the frame as weak reference only
196 }
197 
198 //*****************************************************************************************************************
199 ::rtl::OUString PersistentWindowState::implst_identifyModule(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR ,
200                                                              const css::uno::Reference< css::frame::XFrame >&              xFrame)
201 {
202     ::rtl::OUString sModuleName;
203 
204     css::uno::Reference< css::frame::XModuleManager > xModuleManager(
205         xSMGR->createInstance(SERVICENAME_MODULEMANAGER),
206         css::uno::UNO_QUERY_THROW);
207 
208     try
209     {
210         sModuleName = xModuleManager->identify(xFrame);
211     }
212     catch(const css::uno::RuntimeException& exRun)
213         { throw exRun; }
214     catch(const css::uno::Exception&)
215         { sModuleName = ::rtl::OUString(); }
216 
217     return sModuleName;
218 }
219 
220 //*****************************************************************************************************************
221 ::rtl::OUString PersistentWindowState::implst_getWindowStateFromConfig(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR      ,
222                                                                        const ::rtl::OUString&                                        sModuleName)
223 {
224     ::rtl::OUString sWindowState;
225 
226     ::rtl::OUStringBuffer sRelPathBuf(256);
227     sRelPathBuf.appendAscii("Office/Factories/*[\"");
228     sRelPathBuf.append     (sModuleName            );
229     sRelPathBuf.appendAscii("\"]"                  );
230 
231     ::rtl::OUString sPackage = ::rtl::OUString::createFromAscii("org.openoffice.Setup/");
232     ::rtl::OUString sRelPath = sRelPathBuf.makeStringAndClear();
233     ::rtl::OUString sKey     = ::rtl::OUString::createFromAscii("ooSetupFactoryWindowAttributes");
234 
235     try
236     {
237         ::comphelper::ConfigurationHelper::readDirectKey(xSMGR,
238                                                                                       sPackage,
239                                                                                       sRelPath,
240                                                                                       sKey,
241                                                                                       ::comphelper::ConfigurationHelper::E_READONLY) >>= sWindowState;
242     }
243     catch(const css::uno::RuntimeException& exRun)
244         { throw exRun; }
245     catch(const css::uno::Exception&)
246         { sWindowState = ::rtl::OUString(); }
247 
248     return sWindowState;
249 }
250 
251 //*****************************************************************************************************************
252 void PersistentWindowState::implst_setWindowStateOnConfig(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR       ,
253                                                           const ::rtl::OUString&                                        sModuleName ,
254                                                           const ::rtl::OUString&                                        sWindowState)
255 {
256     ::rtl::OUStringBuffer sRelPathBuf(256);
257     sRelPathBuf.appendAscii("Office/Factories/*[\"");
258     sRelPathBuf.append     (sModuleName            );
259     sRelPathBuf.appendAscii("\"]"                  );
260 
261     ::rtl::OUString sPackage = ::rtl::OUString::createFromAscii("org.openoffice.Setup/");
262     ::rtl::OUString sRelPath = sRelPathBuf.makeStringAndClear();
263     ::rtl::OUString sKey     = ::rtl::OUString::createFromAscii("ooSetupFactoryWindowAttributes");
264 
265     try
266     {
267         ::comphelper::ConfigurationHelper::writeDirectKey(xSMGR,
268                                                           sPackage,
269                                                           sRelPath,
270                                                           sKey,
271                                                           css::uno::makeAny(sWindowState),
272                                                           ::comphelper::ConfigurationHelper::E_STANDARD);
273     }
274     catch(const css::uno::RuntimeException& exRun)
275         { throw exRun; }
276     catch(const css::uno::Exception&)
277         {}
278 }
279 
280 //*****************************************************************************************************************
281 ::rtl::OUString PersistentWindowState::implst_getWindowStateFromWindow(const css::uno::Reference< css::awt::XWindow >& xWindow)
282 {
283     ::rtl::OUString sWindowState;
284 
285     if (xWindow.is())
286     {
287         // SOLAR SAFE -> ------------------------
288         ::vos::OClearableGuard aSolarLock(Application::GetSolarMutex());
289 
290         Window* pWindow = VCLUnoHelper::GetWindow(xWindow);
291         // check for system window is necessary to guarantee correct pointer cast!
292         if (
293             (pWindow                  ) &&
294             (pWindow->IsSystemWindow())
295            )
296         {
297             sal_uLong nMask  =   WINDOWSTATE_MASK_ALL;
298                   nMask &= ~(WINDOWSTATE_MASK_MINIMIZED);
299             sWindowState = B2U_ENC(
300                             ((SystemWindow*)pWindow)->GetWindowState(nMask),
301                             RTL_TEXTENCODING_UTF8);
302         }
303 
304         aSolarLock.clear();
305         // <- SOLAR SAFE ------------------------
306     }
307 
308     return sWindowState;
309 }
310 
311 
312 //*********************************************************************************************************
313 void PersistentWindowState::implst_setWindowStateOnWindow(const css::uno::Reference< css::awt::XWindow >& xWindow     ,
314                                                           const ::rtl::OUString&                          sWindowState)
315 {
316     if (
317         (!xWindow.is()                ) ||
318         ( sWindowState.getLength() < 1)
319        )
320         return;
321 
322     // SOLAR SAFE -> ------------------------
323     ::vos::OClearableGuard aSolarLock(Application::GetSolarMutex());
324 
325     Window* pWindow = VCLUnoHelper::GetWindow(xWindow);
326     if (!pWindow)
327         return;
328 
329     // check for system and work window - its necessary to guarantee correct pointer cast!
330     sal_Bool bSystemWindow = pWindow->IsSystemWindow();
331     sal_Bool bWorkWindow   = (pWindow->GetType() == WINDOW_WORKWINDOW);
332 
333     if (!bSystemWindow && !bWorkWindow)
334         return;
335 
336     SystemWindow* pSystemWindow = (SystemWindow*)pWindow;
337     WorkWindow*   pWorkWindow   = (WorkWindow*  )pWindow;
338 
339     // dont save this special state!
340     if (pWorkWindow->IsMinimized())
341         return;
342 
343     ::rtl::OUString sOldWindowState = ::rtl::OStringToOUString( pSystemWindow->GetWindowState(), RTL_TEXTENCODING_ASCII_US );
344     if ( sOldWindowState != sWindowState )
345         pSystemWindow->SetWindowState(U2B_ENC(sWindowState,RTL_TEXTENCODING_UTF8));
346 
347     aSolarLock.clear();
348     // <- SOLAR SAFE ------------------------
349 }
350 
351 } // namespace framework
352