Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/framework/source/helper/persistentwindowstate.cxx
Line
Count
Source
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 <helper/persistentwindowstate.hxx>
21
22
#include <com/sun/star/awt/XWindow.hpp>
23
#include <com/sun/star/lang/IllegalArgumentException.hpp>
24
#include <com/sun/star/frame/ModuleManager.hpp>
25
#include <com/sun/star/document/XViewDataSupplier.hpp>
26
#include <com/sun/star/container/XIndexAccess.hpp>
27
#include <com/sun/star/beans/XPropertySet.hpp>
28
#include <com/sun/star/beans/XPropertySetInfo.hpp>
29
30
#include <comphelper/lok.hxx>
31
#include <comphelper/configurationhelper.hxx>
32
#include <utility>
33
#include <vcl/window.hxx>
34
#include <vcl/syswin.hxx>
35
36
#include <toolkit/helper/vclunohelper.hxx>
37
#include <vcl/svapp.hxx>
38
#include <vcl/wrkwin.hxx>
39
40
namespace framework{
41
42
PersistentWindowState::PersistentWindowState(css::uno::Reference< css::uno::XComponentContext >  xContext)
43
11.0k
    : m_xContext              (std::move(xContext                     ))
44
11.0k
    , m_bWindowStateAlreadySet(false                    )
45
11.0k
{
46
11.0k
}
47
48
PersistentWindowState::~PersistentWindowState()
49
6.21k
{
50
6.21k
}
51
52
void SAL_CALL PersistentWindowState::initialize(const css::uno::Sequence< css::uno::Any >& lArguments)
53
11.0k
{
54
    // check arguments
55
11.0k
    css::uno::Reference< css::frame::XFrame > xFrame;
56
11.0k
    if (!lArguments.hasElements())
57
0
        throw css::lang::IllegalArgumentException(
58
0
                u"Empty argument list!"_ustr,
59
0
                static_cast< ::cppu::OWeakObject* >(this),
60
0
                1);
61
62
11.0k
    lArguments[0] >>= xFrame;
63
11.0k
    if (!xFrame.is())
64
0
        throw css::lang::IllegalArgumentException(
65
0
                u"No valid frame specified!"_ustr,
66
0
                static_cast< ::cppu::OWeakObject* >(this),
67
0
                1);
68
69
11.0k
    {
70
11.0k
        SolarMutexGuard g;
71
11.0k
        m_xFrame = xFrame;
72
11.0k
    }
73
74
    // start listening
75
11.0k
    xFrame->addFrameActionListener(this);
76
11.0k
}
77
78
void SAL_CALL PersistentWindowState::frameAction(const css::frame::FrameActionEvent& aEvent)
79
12.4k
{
80
    // We don't want to do this stuff when being used through LibreOfficeKit
81
12.4k
    if( comphelper::LibreOfficeKit::isActive() )
82
0
        return;
83
84
12.4k
    css::uno::Reference< css::uno::XComponentContext >     xContext;
85
12.4k
    css::uno::Reference< css::frame::XFrame >              xFrame;
86
12.4k
    bool                                               bRestoreWindowState;
87
12.4k
    {
88
12.4k
        SolarMutexGuard g;
89
12.4k
        xContext = m_xContext;
90
12.4k
        xFrame.set(m_xFrame.get(), css::uno::UNO_QUERY);
91
12.4k
        bRestoreWindowState = !m_bWindowStateAlreadySet;
92
12.4k
    }
93
94
    // frame already gone ? We hold it weak only ...
95
12.4k
    if (!xFrame.is())
96
0
        return;
97
98
    // no window -> no position and size available
99
12.4k
    css::uno::Reference< css::awt::XWindow > xWindow = xFrame->getContainerWindow();
100
12.4k
    if (!xWindow.is())
101
0
        return;
102
103
    // unknown module -> no configuration available!
104
12.4k
    OUString sModuleName = PersistentWindowState::implst_identifyModule(xContext, xFrame);
105
12.4k
    if (sModuleName.isEmpty())
106
6.21k
        return;
107
108
6.21k
    css::uno::Reference<css::frame::XModel> xModel;
109
6.21k
    if (auto xController = xFrame->getController())
110
6.21k
        xModel = xController->getModel();
111
112
6.21k
    switch(aEvent.Action)
113
6.21k
    {
114
6.21k
        case css::frame::FrameAction_COMPONENT_ATTACHED :
115
6.21k
            {
116
6.21k
                if (bRestoreWindowState)
117
6.21k
                {
118
6.21k
                    OUString sWindowState = PersistentWindowState::implst_getWindowStateFromModel(xModel);
119
6.21k
                    if (sWindowState.isEmpty())
120
6.21k
                        sWindowState = PersistentWindowState::implst_getWindowStateFromConfig(xContext, sModuleName);
121
6.21k
                    PersistentWindowState::implst_setWindowStateOnWindow(xWindow,sWindowState);
122
6.21k
                    SolarMutexGuard g;
123
6.21k
                    m_bWindowStateAlreadySet = true;
124
6.21k
                }
125
6.21k
            }
126
6.21k
            break;
127
128
0
        case css::frame::FrameAction_COMPONENT_REATTACHED :
129
0
            {
130
                // nothing todo here, because it's not allowed to change position and size
131
                // of an already existing frame!
132
0
            }
133
0
            break;
134
135
0
        case css::frame::FrameAction_COMPONENT_DETACHING :
136
0
            {
137
0
                OUString sWindowState = PersistentWindowState::implst_getWindowStateFromWindow(xWindow);
138
0
                PersistentWindowState::implst_setWindowStateOnConfig(xContext, sModuleName, sWindowState);
139
0
            }
140
0
            break;
141
0
        default:
142
0
            break;
143
6.21k
    }
144
6.21k
}
145
146
void SAL_CALL PersistentWindowState::disposing(const css::lang::EventObject&)
147
0
{
148
0
    css::uno::Reference< css::frame::XFrame > xFrame(m_xFrame.get(), css::uno::UNO_QUERY);
149
0
    if (xFrame.is())
150
0
        xFrame->removeFrameActionListener(this);
151
152
    // nothing todo here - because we hold the frame as weak reference only
153
0
}
154
155
OUString PersistentWindowState::implst_identifyModule(const css::uno::Reference< css::uno::XComponentContext >& rxContext,
156
                                                             const css::uno::Reference< css::frame::XFrame >&              xFrame)
157
12.4k
{
158
12.4k
    OUString sModuleName;
159
160
12.4k
    css::uno::Reference< css::frame::XModuleManager2 > xModuleManager =
161
12.4k
        css::frame::ModuleManager::create( rxContext );
162
163
12.4k
    try
164
12.4k
    {
165
12.4k
        sModuleName = xModuleManager->identify(xFrame);
166
12.4k
    }
167
12.4k
    catch(const css::uno::RuntimeException&)
168
12.4k
        { throw; }
169
12.4k
    catch(const css::uno::Exception&)
170
12.4k
        { sModuleName.clear(); }
171
172
12.4k
    return sModuleName;
173
12.4k
}
174
175
OUString PersistentWindowState::implst_getWindowStateFromConfig(
176
        const css::uno::Reference< css::uno::XComponentContext >& rxContext,
177
        std::u16string_view sModuleName)
178
6.21k
{
179
6.21k
    OUString sWindowState;
180
6.21k
    try
181
6.21k
    {
182
6.21k
        ::comphelper::ConfigurationHelper::readDirectKey(rxContext,
183
6.21k
            u"org.openoffice.Setup/"_ustr,
184
6.21k
            OUString::Concat("Office/Factories/*[\"") + sModuleName + "\"]",
185
6.21k
            u"ooSetupFactoryWindowAttributes"_ustr,
186
6.21k
            ::comphelper::EConfigurationModes::ReadOnly) >>= sWindowState;
187
6.21k
    }
188
6.21k
    catch(const css::uno::RuntimeException&)
189
6.21k
        { throw; }
190
6.21k
    catch(const css::uno::Exception&)
191
6.21k
        { sWindowState.clear(); }
192
193
0
    return sWindowState;
194
6.21k
}
195
196
void PersistentWindowState::implst_setWindowStateOnConfig(
197
        const css::uno::Reference< css::uno::XComponentContext >& rxContext,
198
        std::u16string_view sModuleName, const OUString& sWindowState)
199
0
{
200
0
    try
201
0
    {
202
0
        ::comphelper::ConfigurationHelper::writeDirectKey(rxContext,
203
0
            u"org.openoffice.Setup/"_ustr,
204
0
            OUString::Concat("Office/Factories/*[\"") + sModuleName + "\"]",
205
0
            u"ooSetupFactoryWindowAttributes"_ustr,
206
0
            css::uno::Any(sWindowState),
207
0
            ::comphelper::EConfigurationModes::Standard);
208
0
    }
209
0
    catch(const css::uno::RuntimeException&)
210
0
        { throw; }
211
0
    catch(const css::uno::Exception&)
212
0
        {}
213
0
}
214
215
OUString PersistentWindowState::implst_getWindowStateFromWindow(const css::uno::Reference< css::awt::XWindow >& xWindow)
216
0
{
217
0
    OUString sWindowState;
218
219
0
    if (xWindow.is())
220
0
    {
221
        // SOLAR SAFE -> ------------------------
222
0
        SolarMutexGuard aSolarGuard;
223
224
0
        VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow);
225
        // check for system window is necessary to guarantee correct pointer cast!
226
0
        if ( pWindow && pWindow->IsSystemWindow() )
227
0
        {
228
0
            vcl::WindowDataMask const nMask = vcl::WindowDataMask::All & ~vcl::WindowDataMask::Minimized;
229
0
            sWindowState = static_cast<SystemWindow*>(pWindow.get())->GetWindowState(nMask).toStr();
230
0
        }
231
        // <- SOLAR SAFE ------------------------
232
0
    }
233
234
0
    return sWindowState;
235
0
}
236
237
void PersistentWindowState::implst_setWindowStateOnWindow(const css::uno::Reference< css::awt::XWindow >& xWindow     ,
238
                                                          std::u16string_view                      sWindowState)
239
0
{
240
0
    if (
241
0
        (!xWindow.is()                ) ||
242
0
        ( sWindowState.empty() )
243
0
       )
244
0
        return;
245
246
    // SOLAR SAFE -> ------------------------
247
0
    SolarMutexGuard aSolarGuard;
248
249
0
    VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xWindow);
250
0
    if (!pWindow)
251
0
        return;
252
253
    // check for system and work window - it's necessary to guarantee correct pointer cast!
254
0
    bool bSystemWindow = pWindow->IsSystemWindow();
255
0
    bool bWorkWindow   = (pWindow->GetType() == WindowType::WORKWINDOW);
256
257
0
    if (!bSystemWindow && !bWorkWindow)
258
0
        return;
259
260
0
    SystemWindow* pSystemWindow = static_cast<SystemWindow*>(pWindow.get());
261
0
    WorkWindow*   pWorkWindow   = static_cast<WorkWindow*  >(pWindow.get());
262
263
    // don't save this special state!
264
0
    if (pWorkWindow->IsMinimized())
265
0
        return;
266
267
0
    vcl::WindowData aOldWindowState = pSystemWindow->GetWindowState();
268
0
    if (aOldWindowState.toStr() != sWindowState)
269
0
        pSystemWindow->SetWindowState(vcl::WindowData(sWindowState));
270
    // <- SOLAR SAFE ------------------------
271
0
}
272
273
//static
274
void PersistentWindowState::SaveWindowStateToConfig(const css::uno::Reference<css::uno::XComponentContext>& rContext,
275
                                                    const css::uno::Reference<css::frame::XFrame>& rFrame)
276
0
{
277
    // We don't want to do this stuff when being used through LibreOfficeKit
278
0
    if (comphelper::LibreOfficeKit::isActive())
279
0
        return;
280
281
0
    if (!rFrame.is())
282
0
        return;
283
284
0
    css::uno::Reference<css::awt::XWindow> xWindow = rFrame->getContainerWindow();
285
0
    if (!xWindow.is())
286
0
        return;
287
288
    // unknown module -> no configuration available!
289
0
    OUString sModuleName = PersistentWindowState::implst_identifyModule(rContext, rFrame);
290
0
    if (sModuleName.isEmpty())
291
0
        return;
292
293
0
    OUString sWindowState = PersistentWindowState::implst_getWindowStateFromWindow(xWindow);
294
0
    PersistentWindowState::implst_setWindowStateOnConfig(rContext, sModuleName, sWindowState);
295
0
}
296
297
OUString PersistentWindowState::implst_getWindowStateFromModel(const css::uno::Reference<css::frame::XModel>& xModel)
298
6.21k
{
299
6.21k
    if (!xModel)
300
0
        return {};
301
302
6.21k
    OUString sWindowState;
303
304
6.21k
    if (auto xViewDataSupplier = xModel.query<css::document::XViewDataSupplier>())
305
6.21k
    {
306
6.21k
        css::uno::Reference<css::container::XIndexAccess> xIndexAccess(xViewDataSupplier->getViewData());
307
6.21k
        if (xIndexAccess && xIndexAccess->getCount() > 0)
308
519
        {
309
519
            css::uno::Sequence<css::beans::PropertyValue> aSeq;
310
519
            if (xIndexAccess->getByIndex(0) >>= aSeq)
311
519
            {
312
519
                for (const auto& rProp : aSeq)
313
5.45k
                {
314
5.45k
                    OUString sName(rProp.Name);
315
5.45k
                    if (sName == "WindowState")
316
0
                    {
317
0
                        rProp.Value >>= sWindowState;
318
0
                        if (!sWindowState.isEmpty())
319
0
                        {
320
0
                            return sWindowState;
321
0
                        }
322
0
                    }
323
5.45k
                }
324
519
            }
325
519
        }
326
6.21k
    }
327
    // no view supplier or empty window state
328
6.21k
    if (auto xProps = xModel.query<css::beans::XPropertySet>())
329
6.21k
    {
330
6.21k
        if (auto xInfo = xProps->getPropertySetInfo();
331
6.21k
            xInfo && xInfo->hasPropertyByName(u"WindowState"_ustr))
332
0
        {
333
0
            css::uno::Any any = xProps->getPropertyValue(u"WindowState"_ustr);
334
0
            any >>= sWindowState;
335
0
        }
336
6.21k
    }
337
338
6.21k
    return sWindowState;
339
6.21k
}
340
341
342
} // namespace framework
343
344
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */