defer finding dialog parent until we need it
[LibreOffice.git] / desktop / source / splash / splash.cxx
blob3392e9f5e886457ee2f2ec3c1ec2446120b82cac
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <sal/log.hxx>
22 #include <vcl/bitmapex.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/salnativewidgets.hxx>
26 #include <com/sun/star/lang/XInitialization.hpp>
27 #include <com/sun/star/lang/XServiceInfo.hpp>
28 #include <com/sun/star/task/XStatusIndicator.hpp>
29 #include <cppuhelper/implbase.hxx>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <rtl/bootstrap.hxx>
32 #include <rtl/math.hxx>
33 #include <vcl/introwin.hxx>
34 #include <vcl/virdev.hxx>
35 #include <o3tl/string_view.hxx>
37 #include <mutex>
39 #define NOT_LOADED (tools::Long(-1))
40 #define NOT_LOADED_COLOR (Color(ColorTransparency, 0xffffffff))
42 using namespace ::com::sun::star::lang;
43 using namespace ::com::sun::star::task;
44 using namespace ::com::sun::star::uno;
46 namespace {
48 class SplashScreen;
50 class SplashScreenWindow : public IntroWindow
52 public:
53 SplashScreen *pSpl;
54 ScopedVclPtr<VirtualDevice> _vdev;
55 explicit SplashScreenWindow(SplashScreen *);
56 virtual ~SplashScreenWindow() override { disposeOnce(); }
57 virtual void dispose() override;
58 // workwindow
59 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
60 void Redraw();
64 class SplashScreen
65 : public ::cppu::WeakImplHelper< XStatusIndicator, XInitialization, XServiceInfo >
67 friend class SplashScreenWindow;
68 private:
69 VclPtr<SplashScreenWindow> pWindow;
71 DECL_LINK( AppEventListenerHdl, VclSimpleEvent&, void );
72 virtual ~SplashScreen() override;
73 void loadConfig();
74 void updateStatus();
75 void SetScreenBitmap(BitmapEx &rBitmap);
76 static void determineProgressRatioValues( double& rXRelPos, double& rYRelPos, double& rRelWidth, double& rRelHeight );
78 BitmapEx _aIntroBmp;
79 Color _cProgressFrameColor;
80 Color _cProgressBarColor;
81 Color _cProgressTextColor;
82 bool _bNativeProgress;
83 OUString _sAppName;
84 OUString _sProgressText;
86 sal_Int32 _iMax;
87 sal_Int32 _iProgress;
88 bool _bPaintProgress;
89 bool _bVisible;
90 bool _bShowLogo;
91 bool _bFullScreenSplash;
92 bool _bProgressEnd;
93 tools::Long _height, _width, _tlx, _tly, _barwidth;
94 tools::Long _barheight, _barspace, _textBaseline;
95 double _fXPos, _fYPos;
96 double _fWidth, _fHeight;
97 static constexpr tools::Long _xoffset = 12, _yoffset = 18;
99 public:
100 SplashScreen();
102 // XStatusIndicator
103 virtual void SAL_CALL end() override;
104 virtual void SAL_CALL reset() override;
105 virtual void SAL_CALL setText(const OUString& aText) override;
106 virtual void SAL_CALL setValue(sal_Int32 nValue) override;
107 virtual void SAL_CALL start(const OUString& aText, sal_Int32 nRange) override;
109 // XInitialize
110 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any>& aArguments ) override;
112 virtual OUString SAL_CALL getImplementationName() override
113 { return u"com.sun.star.office.comp.SplashScreen"_ustr; }
115 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
116 { return cppu::supportsService(this, ServiceName); }
118 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
119 { return { u"com.sun.star.office.SplashScreen"_ustr }; }
122 SplashScreenWindow::SplashScreenWindow(SplashScreen *pSplash)
123 : pSpl( pSplash )
124 , _vdev(VclPtr<VirtualDevice>::Create(*GetOutDev()))
126 _vdev->EnableRTL(IsRTLEnabled());
129 void SplashScreenWindow::dispose()
131 pSpl = nullptr;
132 IntroWindow::dispose();
135 void SplashScreenWindow::Redraw()
137 Invalidate();
138 // Trigger direct painting too - otherwise the splash screen won't be
139 // shown in some cases (when the idle timer won't be hit).
140 Paint(*GetOutDev(), tools::Rectangle());
141 GetOutDev()->Flush();
144 SplashScreen::SplashScreen()
145 : pWindow( VclPtr<SplashScreenWindow>::Create(this) )
146 , _cProgressFrameColor(NOT_LOADED_COLOR)
147 , _cProgressBarColor(NOT_LOADED_COLOR)
148 , _cProgressTextColor(NOT_LOADED_COLOR)
149 , _bNativeProgress(true)
150 , _iMax(100)
151 , _iProgress(0)
152 , _bPaintProgress(false)
153 , _bVisible(true)
154 , _bShowLogo(true)
155 , _bFullScreenSplash(false)
156 , _bProgressEnd(false)
157 , _height(0)
158 , _width(0)
159 , _tlx(NOT_LOADED)
160 , _tly(NOT_LOADED)
161 , _barwidth(NOT_LOADED)
162 , _barheight(NOT_LOADED)
163 , _barspace(2)
164 , _textBaseline(NOT_LOADED)
165 , _fXPos(-1.0)
166 , _fYPos(-1.0)
167 , _fWidth(-1.0)
168 , _fHeight(-1.0)
170 loadConfig();
173 SplashScreen::~SplashScreen()
175 Application::RemoveEventListener(
176 LINK( this, SplashScreen, AppEventListenerHdl ) );
177 pWindow->Hide();
178 pWindow.disposeAndClear();
181 void SAL_CALL SplashScreen::start(const OUString&, sal_Int32 nRange)
183 _iMax = nRange;
184 if (_bVisible) {
185 _bProgressEnd = false;
186 SolarMutexGuard aSolarGuard;
187 pWindow->Show();
188 pWindow->Redraw();
192 void SAL_CALL SplashScreen::end()
194 _iProgress = _iMax;
195 if (_bVisible )
197 pWindow->Hide();
199 _bProgressEnd = true;
202 void SAL_CALL SplashScreen::reset()
204 _iProgress = 0;
205 if (_bVisible && !_bProgressEnd )
207 pWindow->Show();
208 updateStatus();
212 void SAL_CALL SplashScreen::setText(const OUString& rText)
214 SolarMutexGuard aSolarGuard;
215 if ( _sProgressText != rText )
217 _sProgressText = rText;
219 if (_bVisible && !_bProgressEnd)
221 pWindow->Show();
222 updateStatus();
227 void SAL_CALL SplashScreen::setValue(sal_Int32 nValue)
229 SAL_INFO( "desktop.splash", "setValue: " << nValue );
231 SolarMutexGuard aSolarGuard;
232 if (_bVisible && !_bProgressEnd) {
233 pWindow->Show();
234 if (nValue >= _iMax)
235 _iProgress = _iMax;
236 else
237 _iProgress = nValue;
238 updateStatus();
242 // XInitialize
243 void SAL_CALL
244 SplashScreen::initialize( const css::uno::Sequence< css::uno::Any>& aArguments )
246 static std::mutex aMutex;
247 std::lock_guard aGuard( aMutex );
248 if (!aArguments.hasElements())
249 return;
251 aArguments[0] >>= _bVisible;
252 if (aArguments.getLength() > 1 )
253 aArguments[1] >>= _sAppName;
255 // start to determine bitmap and all other required value
256 if ( _bShowLogo )
257 SetScreenBitmap (_aIntroBmp);
258 Size aSize = _aIntroBmp.GetSizePixel();
259 pWindow->SetOutputSizePixel( aSize );
260 pWindow->_vdev->SetOutputSizePixel( aSize );
261 _height = aSize.Height();
262 _width = aSize.Width();
263 if (_width > 500)
265 Point xtopleft(212,216);
266 if ( NOT_LOADED == _tlx || NOT_LOADED == _tly )
268 _tlx = xtopleft.X(); // top-left x
269 _tly = xtopleft.Y(); // top-left y
271 if ( NOT_LOADED == _barwidth )
272 _barwidth = 263;
273 if ( NOT_LOADED == _barheight )
274 _barheight = 8;
276 else
278 if ( NOT_LOADED == _barwidth )
279 _barwidth = _width - (2 * _xoffset);
280 if ( NOT_LOADED == _barheight )
281 _barheight = 6;
282 if ( NOT_LOADED == _tlx || NOT_LOADED == _tly )
284 _tlx = _xoffset; // top-left x
285 _tly = _height - _yoffset; // top-left y
289 if ( NOT_LOADED == _textBaseline )
290 _textBaseline = _height;
292 if ( NOT_LOADED_COLOR == _cProgressFrameColor )
293 _cProgressFrameColor = COL_LIGHTGRAY;
295 if ( NOT_LOADED_COLOR == _cProgressBarColor )
297 // progress bar: new color only for big bitmap format
298 if ( _width > 500 )
299 _cProgressBarColor = Color( 157, 202, 18 );
300 else
301 _cProgressBarColor = COL_BLUE;
304 if ( NOT_LOADED_COLOR == _cProgressTextColor )
305 _cProgressTextColor = COL_BLACK;
307 Application::AddEventListener(
308 LINK( this, SplashScreen, AppEventListenerHdl ) );
311 void SplashScreen::updateStatus()
313 if (!_bVisible || _bProgressEnd)
314 return;
315 if (!_bPaintProgress)
316 _bPaintProgress = true;
317 pWindow->Redraw();
320 // internal private methods
321 IMPL_LINK( SplashScreen, AppEventListenerHdl, VclSimpleEvent&, inEvent, void )
323 if (static_cast<VclWindowEvent&>(inEvent).GetWindow() == pWindow)
325 switch ( inEvent.GetId() )
327 case VclEventId::WindowShow:
328 pWindow->Redraw();
329 break;
330 default:
331 break;
336 // Read keys from soffice{.ini|rc}:
337 OUString implReadBootstrapKey( const OUString& _rKey )
339 OUString sValue;
340 rtl::Bootstrap::get(_rKey, sValue);
341 return sValue;
344 void SplashScreen::loadConfig()
346 _bShowLogo = implReadBootstrapKey( u"Logo"_ustr ) != "0";
348 OUString sProgressFrameColor = implReadBootstrapKey( u"ProgressFrameColor"_ustr );
349 OUString sProgressBarColor = implReadBootstrapKey( u"ProgressBarColor"_ustr );
350 OUString sProgressTextColor = implReadBootstrapKey( u"ProgressTextColor"_ustr );
351 OUString sProgressTextBaseline = implReadBootstrapKey( u"ProgressTextBaseline"_ustr );
352 OUString sSize = implReadBootstrapKey( u"ProgressSize"_ustr );
353 OUString sPosition = implReadBootstrapKey( u"ProgressPosition"_ustr );
354 OUString sFullScreenSplash = implReadBootstrapKey( u"FullScreenSplash"_ustr );
355 OUString sNativeProgress = implReadBootstrapKey( u"NativeProgress"_ustr );
358 // Determine full screen splash mode
359 _bFullScreenSplash = (( !sFullScreenSplash.isEmpty() ) &&
360 ( sFullScreenSplash != "0" ));
362 // Try to retrieve the relative values for the progress bar. The current
363 // schema uses the screen ratio to retrieve the associated values.
364 if ( _bFullScreenSplash )
365 determineProgressRatioValues( _fXPos, _fYPos, _fWidth, _fHeight );
367 if ( !sProgressFrameColor.isEmpty() )
369 sal_uInt8 nRed = 0;
370 sal_Int32 idx = 0;
371 sal_Int32 temp = o3tl::toInt32(o3tl::getToken(sProgressFrameColor, 0, ',', idx ));
372 if ( idx != -1 )
374 nRed = static_cast< sal_uInt8 >( temp );
375 temp = o3tl::toInt32(o3tl::getToken(sProgressFrameColor, 0, ',', idx ));
377 if ( idx != -1 )
379 sal_uInt8 nGreen = static_cast< sal_uInt8 >( temp );
380 sal_uInt8 nBlue = static_cast< sal_uInt8 >( o3tl::toInt32(o3tl::getToken(sProgressFrameColor, 0, ',', idx )) );
381 _cProgressFrameColor = Color( nRed, nGreen, nBlue );
385 if ( !sProgressBarColor.isEmpty() )
387 sal_uInt8 nRed = 0;
388 sal_Int32 idx = 0;
389 sal_Int32 temp = o3tl::toInt32(o3tl::getToken(sProgressBarColor, 0, ',', idx ));
390 if ( idx != -1 )
392 nRed = static_cast< sal_uInt8 >( temp );
393 temp = o3tl::toInt32(o3tl::getToken(sProgressBarColor, 0, ',', idx ));
395 if ( idx != -1 )
397 sal_uInt8 nGreen = static_cast< sal_uInt8 >( temp );
398 sal_uInt8 nBlue = static_cast< sal_uInt8 >( o3tl::toInt32(o3tl::getToken(sProgressBarColor, 0, ',', idx )) );
399 _cProgressBarColor = Color( nRed, nGreen, nBlue );
403 if ( !sProgressTextColor.isEmpty() )
405 sal_uInt8 nRed = 0;
406 sal_Int32 idx = 0;
407 sal_Int32 temp = o3tl::toInt32(o3tl::getToken(sProgressTextColor, 0, ',', idx ));
408 if ( idx != -1 )
410 nRed = static_cast< sal_uInt8 >( temp );
411 temp = o3tl::toInt32(o3tl::getToken(sProgressTextColor, 0, ',', idx ));
413 if ( idx != -1 )
415 sal_uInt8 nGreen = static_cast< sal_uInt8 >( temp );
416 sal_uInt8 nBlue = static_cast< sal_uInt8 >( o3tl::toInt32(o3tl::getToken(sProgressTextColor, 0, ',', idx )) );
417 _cProgressTextColor = Color( nRed, nGreen, nBlue );
421 if ( !sProgressTextBaseline.isEmpty() )
423 _textBaseline = sProgressTextBaseline.toInt32();
426 if( !sNativeProgress.isEmpty() )
428 _bNativeProgress = sNativeProgress.toBoolean();
431 if ( !sSize.isEmpty() )
433 sal_Int32 idx = 0;
434 sal_Int32 temp = o3tl::toInt32(o3tl::getToken(sSize, 0, ',', idx ));
435 if ( idx != -1 )
437 _barwidth = temp;
438 _barheight = o3tl::toInt32(o3tl::getToken(sSize, 0, ',', idx ));
442 if ( _barheight >= 10 )
443 _barspace = 3; // more space between frame and bar
445 if ( !sPosition.isEmpty() )
447 sal_Int32 idx = 0;
448 sal_Int32 temp = o3tl::toInt32(o3tl::getToken(sPosition, 0, ',', idx ));
449 if ( idx != -1 )
451 _tlx = temp;
452 _tly = o3tl::toInt32(o3tl::getToken(sPosition, 0, ',', idx ));
457 void SplashScreen::SetScreenBitmap(BitmapEx &rBitmap)
459 sal_Int32 nWidth( 0 );
460 sal_Int32 nHeight( 0 );
462 // determine desktop resolution
463 sal_uInt32 nCount = Application::GetScreenCount();
464 if ( nCount > 0 )
466 // retrieve size from first screen
467 AbsoluteScreenPixelRectangle aScreenArea = Application::GetScreenPosSizePixel(static_cast<unsigned int>(0));
468 nWidth = aScreenArea.GetWidth();
469 nHeight = aScreenArea.GetHeight();
472 // create file name from screen resolution information
473 OUString aResBuf = "_" + OUString::number(nWidth) + "x" + OUString::number(nHeight);
474 if ( !_sAppName.isEmpty() )
475 if (Application::LoadBrandBitmap(Concat2View("intro_" + _sAppName + aResBuf), rBitmap))
476 return;
478 if (Application::LoadBrandBitmap(Concat2View("intro" + aResBuf), rBitmap))
479 return;
481 (void)Application::LoadBrandBitmap (u"intro", rBitmap);
484 void SplashScreen::determineProgressRatioValues(
485 double& rXRelPos, double& rYRelPos,
486 double& rRelWidth, double& rRelHeight )
488 sal_Int32 nScreenRatio( 0 );
490 // determine desktop resolution
491 sal_uInt32 nCount = Application::GetScreenCount();
492 if ( nCount > 0 )
494 // retrieve size from first screen
495 AbsoluteScreenPixelRectangle aScreenArea = Application::GetScreenPosSizePixel(static_cast<unsigned int>(0));
496 sal_Int32 nWidth = aScreenArea.GetWidth();
497 sal_Int32 nHeight = aScreenArea.GetHeight();
498 nScreenRatio = nHeight ? sal_Int32( rtl::math::round( double( nWidth ) / double( nHeight ), 2 ) * 100 ) : 0;
501 char szFullScreenProgressRatio[] = "FullScreenProgressRatio0";
502 char szFullScreenProgressPos[] = "FullScreenProgressPos0";
503 char szFullScreenProgressSize[] = "FullScreenProgressSize0";
504 for ( sal_Int32 i = 0; i <= 9; i++ )
506 char cNum = '0' + char( i );
507 szFullScreenProgressRatio[23] = cNum;
508 szFullScreenProgressPos[21] = cNum;
509 szFullScreenProgressSize[22] = cNum;
511 OUString sFullScreenProgressRatio = implReadBootstrapKey(
512 OUString::createFromAscii( szFullScreenProgressRatio ) );
514 if ( !sFullScreenProgressRatio.isEmpty() )
516 double fRatio = sFullScreenProgressRatio.toDouble();
517 sal_Int32 nRatio = sal_Int32( rtl::math::round( fRatio, 2 ) * 100 );
518 if ( nRatio == nScreenRatio )
520 OUString sFullScreenProgressPos = implReadBootstrapKey(
521 OUString::createFromAscii( szFullScreenProgressPos ) );
522 OUString sFullScreenProgressSize = implReadBootstrapKey(
523 OUString::createFromAscii( szFullScreenProgressSize ) );
525 if ( !sFullScreenProgressPos.isEmpty() )
527 sal_Int32 idx = 0;
528 double temp = o3tl::toDouble(o3tl::getToken(sFullScreenProgressPos, 0, ',', idx ));
529 if ( idx != -1 )
531 rXRelPos = temp;
532 rYRelPos = o3tl::toDouble(o3tl::getToken(sFullScreenProgressPos, 0, ',', idx ));
536 if ( !sFullScreenProgressSize.isEmpty() )
538 sal_Int32 idx = 0;
539 double temp = o3tl::toDouble(o3tl::getToken(sFullScreenProgressSize, 0, ',', idx ));
540 if ( idx != -1 )
542 rRelWidth = temp;
543 rRelHeight = o3tl::toDouble(o3tl::getToken(sFullScreenProgressSize, 0, ',', idx ));
548 else
549 break;
553 void SplashScreenWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
555 if (!pSpl || !pSpl->_bVisible)
556 return;
558 //native drawing
559 // in case of native controls we need to draw directly to the window
560 if (pSpl->_bNativeProgress && rRenderContext.IsNativeControlSupported(ControlType::IntroProgress, ControlPart::Entire))
562 rRenderContext.DrawBitmapEx(Point(), pSpl->_aIntroBmp);
564 ImplControlValue aValue( pSpl->_iProgress * pSpl->_barwidth / pSpl->_iMax);
565 tools::Rectangle aDrawRect( Point(pSpl->_tlx, pSpl->_tly), Size( pSpl->_barwidth, pSpl->_barheight));
566 tools::Rectangle aNativeControlRegion, aNativeContentRegion;
568 if (rRenderContext.GetNativeControlRegion(ControlType::IntroProgress, ControlPart::Entire, aDrawRect,
569 ControlState::ENABLED, aValue,
570 aNativeControlRegion, aNativeContentRegion))
572 tools::Long nProgressHeight = aNativeControlRegion.GetHeight();
573 aDrawRect.AdjustTop( -((nProgressHeight - pSpl->_barheight)/2) );
574 aDrawRect.AdjustBottom((nProgressHeight - pSpl->_barheight)/2 );
577 if (rRenderContext.DrawNativeControl(ControlType::IntroProgress, ControlPart::Entire, aDrawRect,
578 ControlState::ENABLED, aValue, pSpl->_sProgressText))
580 return;
584 // non native drawing
585 // draw bitmap
586 _vdev->DrawBitmapEx(Point(), pSpl->_aIntroBmp);
588 if (pSpl->_bPaintProgress) {
589 // draw progress...
590 tools::Long length = (pSpl->_iProgress * pSpl->_barwidth / pSpl->_iMax) - (2 * pSpl->_barspace);
591 if (length < 0) length = 0;
593 // border
594 _vdev->SetFillColor();
595 _vdev->SetLineColor( pSpl->_cProgressFrameColor );
596 _vdev->DrawRect(tools::Rectangle(pSpl->_tlx, pSpl->_tly, pSpl->_tlx+pSpl->_barwidth, pSpl->_tly+pSpl->_barheight));
597 _vdev->SetFillColor( pSpl->_cProgressBarColor );
598 _vdev->SetLineColor();
599 _vdev->DrawRect(tools::Rectangle(pSpl->_tlx+pSpl->_barspace, pSpl->_tly+pSpl->_barspace, pSpl->_tlx+pSpl->_barspace+length, pSpl->_tly+pSpl->_barheight-pSpl->_barspace));
600 vcl::Font aFont;
601 aFont.SetFontSize(Size(0, 12));
602 aFont.SetAlignment(ALIGN_BASELINE);
603 _vdev->SetFont(aFont);
604 _vdev->SetTextColor(pSpl->_cProgressTextColor);
605 _vdev->DrawText(Point(pSpl->_tlx, pSpl->_textBaseline), pSpl->_sProgressText);
607 rRenderContext.DrawOutDev(Point(), GetOutputSizePixel(), Point(), _vdev->GetOutputSizePixel(), *_vdev);
612 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
613 desktop_SplashScreen_get_implementation(
614 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
616 return cppu::acquire(new SplashScreen());
620 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */