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 <string.h>
21 
22 #include <comphelper/lok.hxx>
23 #include <comphelper/processfactory.hxx>
24 #include <tools/diagnose_ex.h>
25 #include <unotools/resmgr.hxx>
26 #include <sal/log.hxx>
27 
28 #include <configsettings.hxx>
29 #include <vcl/QueueInfo.hxx>
30 #include <vcl/cvtgrf.hxx>
31 #include <vcl/dockwin.hxx>
32 #include <vcl/fieldvalues.hxx>
33 #include <vcl/menu.hxx>
34 #include <vcl/print.hxx>
35 #include <vcl/settings.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/virdev.hxx>
38 #include <vcl/wrkwin.hxx>
39 #include <vcl/uitest/logger.hxx>
40 #include <salframe.hxx>
41 #include <scrwnd.hxx>
42 #include <helpwin.hxx>
43 #include <vcl/toolkit/dialog.hxx>
44 #include <salinst.hxx>
45 #include <salgdi.hxx>
46 #include <svdata.hxx>
47 #include <salsys.hxx>
48 #include <windowdev.hxx>
49 #include <units.hrc>
50 #include <print.h>
51 
52 #include <com/sun/star/accessibility/MSAAService.hpp>
53 
54 #include <config_features.h>
55 #include <basegfx/utils/systemdependentdata.hxx>
56 #include <cppuhelper/basemutex.hxx>
57 
58 using namespace com::sun::star::uno;
59 using namespace com::sun::star::lang;
60 using namespace com::sun::star::awt;
61 
62 namespace
63 {
64     struct private_aImplSVData :
65         public rtl::Static<ImplSVData, private_aImplSVData> {};
66     /// Default instance ensures that ImplSVData::mpHelpData is never null.
67     struct private_aImplSVHelpData :
68         public rtl::Static<ImplSVHelpData, private_aImplSVHelpData> {};
69 
70     /// Default instance ensures that ImplSVData::mpWinData is never null.
71     struct private_aImplSVWinData :
72         public rtl::Static<ImplSVWinData, private_aImplSVWinData> {};
73 
74 }
75 
ImplGetSVData()76 ImplSVData* ImplGetSVData() {
77     return &private_aImplSVData::get();
78 }
79 
ImplGetSalSystem()80 SalSystem* ImplGetSalSystem()
81 {
82     ImplSVData* pSVData = ImplGetSVData();
83     if( ! pSVData->mpSalSystem )
84         pSVData->mpSalSystem.reset( pSVData->mpDefInst->CreateSalSystem() );
85     return pSVData->mpSalSystem.get();
86 }
87 
ImplDeInitSVData()88 void ImplDeInitSVData()
89 {
90     ImplSVData* pSVData = ImplGetSVData();
91 
92     // delete global instance data
93     pSVData->mpSettingsConfigItem.reset();
94 
95     pSVData->mpDockingManager.reset();
96 
97     pSVData->maCtrlData.maFieldUnitStrings.clear();
98     pSVData->maCtrlData.maCleanUnitStrings.clear();
99     pSVData->maPaperNames.clear();
100 }
101 
102 namespace
103 {
104     typedef ::std::map< basegfx::SystemDependentData_SharedPtr, sal_uInt32 > EntryMap;
105 
106     class SystemDependentDataBuffer final : public basegfx::SystemDependentDataManager, protected cppu::BaseMutex
107     {
108     private:
109         std::unique_ptr<AutoTimer> maTimer;
110         EntryMap maEntries;
111 
112         DECL_LINK(implTimeoutHdl, Timer *, void);
113 
114     public:
SystemDependentDataBuffer(const char * pDebugName)115         SystemDependentDataBuffer(const char* pDebugName)
116         :   basegfx::SystemDependentDataManager(),
117             maTimer(std::make_unique<AutoTimer>(pDebugName))
118         {
119             maTimer->SetTimeout(1000);
120             maTimer->SetInvokeHandler(LINK(this, SystemDependentDataBuffer, implTimeoutHdl));
121         }
122 
~SystemDependentDataBuffer()123         virtual ~SystemDependentDataBuffer() override
124         {
125             flushAll();
126         }
127 
startUsage(basegfx::SystemDependentData_SharedPtr & rData)128         void startUsage(basegfx::SystemDependentData_SharedPtr& rData) override
129         {
130             ::osl::MutexGuard aGuard(m_aMutex);
131             EntryMap::iterator aFound(maEntries.find(rData));
132 
133             if(aFound == maEntries.end())
134             {
135                 if(maTimer && !maTimer->IsActive())
136                 {
137                     maTimer->Start();
138                 }
139 
140                 maEntries[rData] = rData->calculateCombinedHoldCyclesInSeconds();
141             }
142         }
143 
endUsage(basegfx::SystemDependentData_SharedPtr & rData)144         void endUsage(basegfx::SystemDependentData_SharedPtr& rData) override
145         {
146             ::osl::MutexGuard aGuard(m_aMutex);
147             EntryMap::iterator aFound(maEntries.find(rData));
148 
149             if(aFound != maEntries.end())
150             {
151                 maEntries.erase(aFound);
152             }
153         }
154 
touchUsage(basegfx::SystemDependentData_SharedPtr & rData)155         void touchUsage(basegfx::SystemDependentData_SharedPtr& rData) override
156         {
157             ::osl::MutexGuard aGuard(m_aMutex);
158             EntryMap::iterator aFound(maEntries.find(rData));
159 
160             if(aFound != maEntries.end())
161             {
162                 aFound->second = rData->calculateCombinedHoldCyclesInSeconds();
163             }
164         }
165 
flushAll()166         void flushAll() override
167         {
168             ::osl::MutexGuard aGuard(m_aMutex);
169 
170             if(maTimer)
171             {
172                 maTimer->Stop();
173                 maTimer.reset();
174             }
175 
176             maEntries.clear();
177         }
178     };
179 
IMPL_LINK_NOARG(SystemDependentDataBuffer,implTimeoutHdl,Timer *,void)180     IMPL_LINK_NOARG(SystemDependentDataBuffer, implTimeoutHdl, Timer *, void)
181     {
182         ::osl::MutexGuard aGuard(m_aMutex);
183         EntryMap::iterator aIter(maEntries.begin());
184 
185         while(aIter != maEntries.end())
186         {
187             if(aIter->second)
188             {
189                 aIter->second--;
190                 ++aIter;
191             }
192             else
193             {
194                 aIter = maEntries.erase(aIter);
195             }
196         }
197 
198         if (maEntries.empty())
199             maTimer->Stop();
200     }
201 }
202 
ImplGetSystemDependentDataManager()203 basegfx::SystemDependentDataManager& ImplGetSystemDependentDataManager()
204 {
205     static SystemDependentDataBuffer aSystemDependentDataBuffer("vcl SystemDependentDataBuffer aSystemDependentDataBuffer");
206 
207     return aSystemDependentDataBuffer;
208 }
209 
210 /// Returns either the application window, or the default GL context window
ImplGetDefaultWindow()211 vcl::Window* ImplGetDefaultWindow()
212 {
213     ImplSVData* pSVData = ImplGetSVData();
214     if (pSVData->maFrameData.mpAppWin)
215         return pSVData->maFrameData.mpAppWin;
216     else
217         return ImplGetDefaultContextWindow();
218 }
219 
220 /// returns the default window created to hold the persistent VCL GL context.
ImplGetDefaultContextWindow()221 vcl::Window *ImplGetDefaultContextWindow()
222 {
223     ImplSVData* pSVData = ImplGetSVData();
224 
225     // Double check locking on mpDefaultWin.
226     if ( !pSVData->mpDefaultWin )
227     {
228         SolarMutexGuard aGuard;
229 
230         if (!pSVData->mpDefaultWin && !pSVData->mbDeInit)
231         {
232             try
233             {
234                 SAL_INFO( "vcl", "ImplGetDefaultWindow(): No AppWindow" );
235 
236                 pSVData->mpDefaultWin = VclPtr<WorkWindow>::Create(nullptr, WB_DEFAULTWIN);
237                 pSVData->mpDefaultWin->SetText( "VCL ImplGetDefaultWindow" );
238             }
239             catch (const css::uno::Exception&)
240             {
241                 TOOLS_WARN_EXCEPTION("vcl", "unable to create Default Window");
242             }
243         }
244     }
245 
246     return pSVData->mpDefaultWin;
247 }
248 
ImplGetResLocale()249 const std::locale& ImplGetResLocale()
250 {
251     ImplSVData* pSVData = ImplGetSVData();
252     if (!pSVData->mbResLocaleSet || comphelper::LibreOfficeKit::isActive())
253     {
254         pSVData->maResLocale = Translate::Create("vcl");
255         pSVData->mbResLocaleSet = true;
256     }
257     return pSVData->maResLocale;
258 }
259 
VclResId(const char * pId)260 OUString VclResId(const char* pId)
261 {
262     return Translate::get(pId, ImplGetResLocale());
263 }
264 
ImplGetFieldUnits()265 const FieldUnitStringList& ImplGetFieldUnits()
266 {
267     ImplSVData* pSVData = ImplGetSVData();
268     if( pSVData->maCtrlData.maFieldUnitStrings.empty() )
269     {
270         sal_uInt32 nUnits = SAL_N_ELEMENTS(SV_FUNIT_STRINGS);
271         pSVData->maCtrlData.maFieldUnitStrings.reserve( nUnits );
272         for (sal_uInt32 i = 0; i < nUnits; i++)
273         {
274             std::pair<OUString, FieldUnit> aElement(VclResId(SV_FUNIT_STRINGS[i].first), SV_FUNIT_STRINGS[i].second);
275             pSVData->maCtrlData.maFieldUnitStrings.push_back( aElement );
276         }
277     }
278     return pSVData->maCtrlData.maFieldUnitStrings;
279 }
280 
281 namespace vcl
282 {
EnglishStringToMetric(const OUString & rEnglishMetricString)283     FieldUnit EnglishStringToMetric(const OUString& rEnglishMetricString)
284     {
285         sal_uInt32 nUnits = SAL_N_ELEMENTS(SV_FUNIT_STRINGS);
286         for (sal_uInt32 i = 0; i < nUnits; ++i)
287         {
288             const char *pId = strchr(SV_FUNIT_STRINGS[i].first, '\004');
289             assert(pId);
290             if (rEnglishMetricString.equalsAscii(pId+1))
291                 return SV_FUNIT_STRINGS[i].second;
292         }
293         return FieldUnit::NONE;
294     }
295 }
296 
ImplGetCleanedFieldUnits()297 const FieldUnitStringList& ImplGetCleanedFieldUnits()
298 {
299     ImplSVData* pSVData = ImplGetSVData();
300     if( pSVData->maCtrlData.maCleanUnitStrings.empty() )
301     {
302         const FieldUnitStringList& rUnits = ImplGetFieldUnits();
303         size_t nUnits = rUnits.size();
304         pSVData->maCtrlData.maCleanUnitStrings.reserve(nUnits);
305         for (size_t i = 0; i < nUnits; ++i)
306         {
307             OUString aUnit(rUnits[i].first);
308             aUnit = aUnit.replaceAll(" ", "");
309             aUnit = aUnit.toAsciiLowerCase();
310             std::pair<OUString, FieldUnit> aElement(aUnit, rUnits[i].second);
311             pSVData->maCtrlData.maCleanUnitStrings.push_back(aElement);
312         }
313     }
314     return pSVData->maCtrlData.maCleanUnitStrings;
315 }
316 
ImplGetDockingManager()317 DockingManager* ImplGetDockingManager()
318 {
319     ImplSVData* pSVData = ImplGetSVData();
320     if ( !pSVData->mpDockingManager )
321         pSVData->mpDockingManager.reset(new DockingManager());
322 
323     return pSVData->mpDockingManager.get();
324 }
325 
ImplGetBlendFrameCache()326 BlendFrameCache* ImplGetBlendFrameCache()
327 {
328     ImplSVData* pSVData = ImplGetSVData();
329     if ( !pSVData->mpBlendFrameCache)
330         pSVData->mpBlendFrameCache.reset( new BlendFrameCache() );
331 
332     return pSVData->mpBlendFrameCache.get();
333 }
334 
335 #ifdef _WIN32
ImplInitAccessBridge()336 bool ImplInitAccessBridge()
337 {
338     ImplSVData* pSVData = ImplGetSVData();
339     if( ! pSVData->mxAccessBridge.is() )
340     {
341         css::uno::Reference< XComponentContext > xContext(comphelper::getProcessComponentContext());
342 
343         if (!HasAtHook() && !getenv("SAL_FORCE_IACCESSIBLE2"))
344         {
345             SAL_INFO("vcl", "Apparently no running AT -> "
346                      "not enabling IAccessible2 integration");
347         }
348         else
349         {
350             try {
351                  pSVData->mxAccessBridge
352                      = css::accessibility::MSAAService::create(xContext);
353                  SAL_INFO("vcl", "got IAccessible2 bridge");
354                  return true;
355              } catch (css::uno::DeploymentException &) {
356                  TOOLS_WARN_EXCEPTION(
357                     "vcl",
358                     "got no IAccessible2 bridge");
359                  return false;
360              }
361         }
362     }
363 
364     return true;
365 }
366 #endif
367 
ConfigurationChanged(utl::ConfigurationBroadcaster *,ConfigurationHints nHint)368 void LocaleConfigurationListener::ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints nHint )
369 {
370     AllSettings::LocaleSettingsChanged( nHint );
371 }
372 
CreateSVWinData()373 ImplSVWinData* CreateSVWinData()
374 {
375     if (!comphelper::LibreOfficeKit::isActive())
376         return nullptr;
377 
378     ImplSVWinData* p = new ImplSVWinData;
379 
380     ImplSVData* pSVData = ImplGetSVData();
381     assert(pSVData && pSVData->mpWinData);
382 
383     p->mpFocusWin = pSVData->mpWinData->mpFocusWin;
384     return p;
385 }
386 
DestroySVWinData(ImplSVWinData * pData)387 void DestroySVWinData(ImplSVWinData* pData)
388 {
389     delete pData;
390 }
391 
SetSVWinData(ImplSVWinData * pSVWinData)392 void SetSVWinData(ImplSVWinData* pSVWinData)
393 {
394     if (!comphelper::LibreOfficeKit::isActive())
395         return;
396 
397     ImplSVData* pSVData = ImplGetSVData();
398     assert(pSVData != nullptr);
399 
400     if (pSVData->mpWinData == pSVWinData)
401         return;
402 
403     // If current one is the static, clean it up to avoid having lingering references.
404     if (pSVData->mpWinData == &private_aImplSVWinData::get())
405     {
406         pSVData->mpWinData->mpFocusWin.reset();
407     }
408 
409     pSVData->mpWinData = pSVWinData;
410     if (pSVData->mpWinData == nullptr)
411     {
412         pSVData->mpWinData = &private_aImplSVWinData::get(); // Never leave it null.
413     }
414 }
415 
ImplSVData()416 ImplSVData::ImplSVData()
417 {
418     mpHelpData = &private_aImplSVHelpData::get();
419     mpWinData = &private_aImplSVWinData::get();
420 }
421 
CreateSVHelpData()422 ImplSVHelpData* CreateSVHelpData()
423 {
424     if (!comphelper::LibreOfficeKit::isActive())
425         return nullptr;
426 
427     ImplSVHelpData* pNewData = new ImplSVHelpData;
428 
429     // Set options set globally
430     ImplSVHelpData& aStaticHelpData = private_aImplSVHelpData::get();
431     pNewData->mbContextHelp = aStaticHelpData.mbContextHelp;
432     pNewData->mbExtHelp = aStaticHelpData.mbExtHelp;
433     pNewData->mbExtHelpMode = aStaticHelpData.mbExtHelpMode;
434     pNewData->mbOldBalloonMode = aStaticHelpData.mbOldBalloonMode;
435     pNewData->mbBalloonHelp = aStaticHelpData.mbBalloonHelp;
436     pNewData->mbQuickHelp = aStaticHelpData.mbQuickHelp;
437 
438     return pNewData;
439 }
440 
DestroySVHelpData(ImplSVHelpData * pSVHelpData)441 void DestroySVHelpData(ImplSVHelpData* pSVHelpData)
442 {
443     if (!comphelper::LibreOfficeKit::isActive())
444         return;
445 
446     // Change the SVData's help date if necessary
447     if(ImplGetSVData()->mpHelpData == pSVHelpData)
448     {
449         ImplGetSVData()->mpHelpData = &private_aImplSVHelpData::get();
450     }
451 
452     if(pSVHelpData)
453     {
454         ImplDestroyHelpWindow(*pSVHelpData, false);
455         delete pSVHelpData;
456     }
457 }
458 
SetSVHelpData(ImplSVHelpData * pSVHelpData)459 void SetSVHelpData(ImplSVHelpData* pSVHelpData)
460 {
461     if (!comphelper::LibreOfficeKit::isActive())
462         return;
463 
464     ImplSVData* pSVData = ImplGetSVData();
465     if (pSVData->mpHelpData == pSVHelpData)
466         return;
467 
468     // If current one is the static, clean it up to avoid having lingering references.
469     if (pSVData->mpHelpData == &private_aImplSVHelpData::get())
470     {
471         pSVData->mpHelpData->mpHelpWin.reset();
472     }
473 
474     pSVData->mpHelpData = pSVHelpData;
475     if (pSVData->mpHelpData == nullptr)
476     {
477         pSVData->mpHelpData = &private_aImplSVHelpData::get(); // Never leave it null.
478     }
479 }
480 
ImplGetSVHelpData()481 ImplSVHelpData& ImplGetSVHelpData()
482 {
483     ImplSVData* pSVData = ImplGetSVData();
484     if(pSVData->mpHelpData)
485     {
486         return *pSVData->mpHelpData;
487     }
488     else
489     {
490         return private_aImplSVHelpData::get();
491     }
492 }
493 
~ImplSVData()494 ImplSVData::~ImplSVData() {}
~ImplSVAppData()495 ImplSVAppData::~ImplSVAppData() {}
~ImplSVGDIData()496 ImplSVGDIData::~ImplSVGDIData() {}
~ImplSVFrameData()497 ImplSVFrameData::~ImplSVFrameData() {}
~ImplSVWinData()498 ImplSVWinData::~ImplSVWinData() {}
~ImplSVHelpData()499 ImplSVHelpData::~ImplSVHelpData() {}
500 
501 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
502