Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / desktop / source / splash / splash.cxx
blobc34673f3e881f8dcde0eafa551a5d822f72539fc
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 "splash.hxx"
22 #include <stdio.h>
23 #include <sal/log.hxx>
24 #include <unotools/bootstrap.hxx>
25 #include <tools/stream.hxx>
26 #include <vcl/bitmapex.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/salnativewidgets.hxx>
30 #include <com/sun/star/lang/XInitialization.hpp>
31 #include <com/sun/star/lang/XServiceInfo.hpp>
32 #include <com/sun/star/registry/XRegistryKey.hpp>
33 #include <com/sun/star/task/XStatusIndicator.hpp>
34 #include <cppuhelper/implbase.hxx>
35 #include <cppuhelper/supportsservice.hxx>
36 #include <rtl/bootstrap.hxx>
37 #include <rtl/strbuf.hxx>
38 #include <rtl/math.hxx>
39 #include <vcl/introwin.hxx>
40 #include <vcl/virdev.hxx>
42 #define NOT_LOADED (long(-1))
43 #define NOT_LOADED_COLOR (Color(0xffffffff))
45 using namespace ::com::sun::star::lang;
46 using namespace ::com::sun::star::registry;
47 using namespace ::com::sun::star::task;
48 using namespace ::com::sun::star::uno;
50 namespace {
52 class SplashScreen;
54 class SplashScreenWindow : public IntroWindow
56 public:
57 SplashScreen *pSpl;
58 ScopedVclPtr<VirtualDevice> _vdev;
59 explicit SplashScreenWindow(SplashScreen *);
60 virtual ~SplashScreenWindow() override { disposeOnce(); }
61 virtual void dispose() override;
62 // workwindow
63 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
64 void Redraw();
68 class SplashScreen
69 : public ::cppu::WeakImplHelper< XStatusIndicator, XInitialization, XServiceInfo >
71 friend class SplashScreenWindow;
72 private:
73 VclPtr<SplashScreenWindow> pWindow;
75 DECL_LINK( AppEventListenerHdl, VclSimpleEvent&, void );
76 virtual ~SplashScreen() override;
77 void loadConfig();
78 void updateStatus();
79 void SetScreenBitmap(BitmapEx &rBitmap);
80 static void determineProgressRatioValues( double& rXRelPos, double& rYRelPos, double& rRelWidth, double& rRelHeight );
82 static osl::Mutex _aMutex;
84 BitmapEx _aIntroBmp;
85 Color _cProgressFrameColor;
86 Color _cProgressBarColor;
87 Color _cProgressTextColor;
88 bool _bNativeProgress;
89 OUString _sAppName;
90 OUString _sProgressText;
92 sal_Int32 _iMax;
93 sal_Int32 _iProgress;
94 bool _bPaintProgress;
95 bool _bVisible;
96 bool _bShowLogo;
97 bool _bFullScreenSplash;
98 bool _bProgressEnd;
99 long _height, _width, _tlx, _tly, _barwidth;
100 long _barheight, _barspace, _textBaseline;
101 double _fXPos, _fYPos;
102 double _fWidth, _fHeight;
103 static constexpr long _xoffset = 12, _yoffset = 18;
105 public:
106 SplashScreen();
108 // XStatusIndicator
109 virtual void SAL_CALL end() override;
110 virtual void SAL_CALL reset() override;
111 virtual void SAL_CALL setText(const OUString& aText) override;
112 virtual void SAL_CALL setValue(sal_Int32 nValue) override;
113 virtual void SAL_CALL start(const OUString& aText, sal_Int32 nRange) override;
115 // XInitialize
116 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any>& aArguments ) override;
118 virtual OUString SAL_CALL getImplementationName() override
119 { return desktop::splash::getImplementationName(); }
121 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
122 { return cppu::supportsService(this, ServiceName); }
124 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
125 { return desktop::splash::getSupportedServiceNames(); }
128 SplashScreenWindow::SplashScreenWindow(SplashScreen *pSplash)
129 : IntroWindow()
130 , pSpl( pSplash )
131 , _vdev(VclPtr<VirtualDevice>::Create(*this))
133 _vdev->EnableRTL(IsRTLEnabled());
136 void SplashScreenWindow::dispose()
138 pSpl = nullptr;
139 IntroWindow::dispose();
142 void SplashScreenWindow::Redraw()
144 Invalidate();
145 // Trigger direct painting too - otherwise the splash screen won't be
146 // shown in some cases (when the idle timer won't be hit).
147 Paint(*this, tools::Rectangle());
148 Flush();
151 SplashScreen::SplashScreen()
152 : pWindow( VclPtr<SplashScreenWindow>::Create(this) )
153 , _cProgressFrameColor(NOT_LOADED_COLOR)
154 , _cProgressBarColor(NOT_LOADED_COLOR)
155 , _cProgressTextColor(NOT_LOADED_COLOR)
156 , _bNativeProgress(true)
157 , _iMax(100)
158 , _iProgress(0)
159 , _bPaintProgress(false)
160 , _bVisible(true)
161 , _bShowLogo(true)
162 , _bFullScreenSplash(false)
163 , _bProgressEnd(false)
164 , _height(0)
165 , _width(0)
166 , _tlx(NOT_LOADED)
167 , _tly(NOT_LOADED)
168 , _barwidth(NOT_LOADED)
169 , _barheight(NOT_LOADED)
170 , _barspace(2)
171 , _textBaseline(NOT_LOADED)
172 , _fXPos(-1.0)
173 , _fYPos(-1.0)
174 , _fWidth(-1.0)
175 , _fHeight(-1.0)
177 loadConfig();
180 SplashScreen::~SplashScreen()
182 Application::RemoveEventListener(
183 LINK( this, SplashScreen, AppEventListenerHdl ) );
184 pWindow->Hide();
185 pWindow.disposeAndClear();
188 void SAL_CALL SplashScreen::start(const OUString&, sal_Int32 nRange)
190 _iMax = nRange;
191 if (_bVisible) {
192 _bProgressEnd = false;
193 SolarMutexGuard aSolarGuard;
194 pWindow->Show();
195 pWindow->Redraw();
199 void SAL_CALL SplashScreen::end()
201 _iProgress = _iMax;
202 if (_bVisible )
204 pWindow->Hide();
206 _bProgressEnd = true;
209 void SAL_CALL SplashScreen::reset()
211 _iProgress = 0;
212 if (_bVisible && !_bProgressEnd )
214 pWindow->Show();
215 updateStatus();
219 void SAL_CALL SplashScreen::setText(const OUString& rText)
221 SolarMutexGuard aSolarGuard;
222 if ( _sProgressText != rText )
224 _sProgressText = rText;
226 if (_bVisible && !_bProgressEnd)
228 pWindow->Show();
229 updateStatus();
234 void SAL_CALL SplashScreen::setValue(sal_Int32 nValue)
236 SAL_INFO( "desktop.splash", "setValue: " << nValue );
238 SolarMutexGuard aSolarGuard;
239 if (_bVisible && !_bProgressEnd) {
240 pWindow->Show();
241 if (nValue >= _iMax)
242 _iProgress = _iMax;
243 else
244 _iProgress = nValue;
245 updateStatus();
249 // XInitialize
250 void SAL_CALL
251 SplashScreen::initialize( const css::uno::Sequence< css::uno::Any>& aArguments )
253 osl::MutexGuard aGuard( _aMutex );
254 if (aArguments.hasElements())
256 aArguments[0] >>= _bVisible;
257 if (aArguments.getLength() > 1 )
258 aArguments[1] >>= _sAppName;
260 // start to determine bitmap and all other required value
261 if ( _bShowLogo )
262 SetScreenBitmap (_aIntroBmp);
263 Size aSize = _aIntroBmp.GetSizePixel();
264 pWindow->SetOutputSizePixel( aSize );
265 pWindow->_vdev->SetOutputSizePixel( aSize );
266 _height = aSize.Height();
267 _width = aSize.Width();
268 if (_width > 500)
270 Point xtopleft(212,216);
271 if ( NOT_LOADED == _tlx || NOT_LOADED == _tly )
273 _tlx = xtopleft.X(); // top-left x
274 _tly = xtopleft.Y(); // top-left y
276 if ( NOT_LOADED == _barwidth )
277 _barwidth = 263;
278 if ( NOT_LOADED == _barheight )
279 _barheight = 8;
281 else
283 if ( NOT_LOADED == _barwidth )
284 _barwidth = _width - (2 * _xoffset);
285 if ( NOT_LOADED == _barheight )
286 _barheight = 6;
287 if ( NOT_LOADED == _tlx || NOT_LOADED == _tly )
289 _tlx = _xoffset; // top-left x
290 _tly = _height - _yoffset; // top-left y
294 if ( NOT_LOADED == _textBaseline )
295 _textBaseline = _height;
297 if ( NOT_LOADED_COLOR == _cProgressFrameColor )
298 _cProgressFrameColor = COL_LIGHTGRAY;
300 if ( NOT_LOADED_COLOR == _cProgressBarColor )
302 // progress bar: new color only for big bitmap format
303 if ( _width > 500 )
304 _cProgressBarColor = Color( 157, 202, 18 );
305 else
306 _cProgressBarColor = COL_BLUE;
309 if ( NOT_LOADED_COLOR == _cProgressTextColor )
310 _cProgressTextColor = COL_BLACK;
312 Application::AddEventListener(
313 LINK( this, SplashScreen, AppEventListenerHdl ) );
317 void SplashScreen::updateStatus()
319 if (!_bVisible || _bProgressEnd)
320 return;
321 if (!_bPaintProgress)
322 _bPaintProgress = true;
323 pWindow->Redraw();
326 // internal private methods
327 IMPL_LINK( SplashScreen, AppEventListenerHdl, VclSimpleEvent&, inEvent, void )
329 if (static_cast<VclWindowEvent&>(inEvent).GetWindow() == pWindow)
331 switch ( inEvent.GetId() )
333 case VclEventId::WindowShow:
334 pWindow->Redraw();
335 break;
336 default:
337 break;
342 // Read keys from soffice{.ini|rc}:
343 OUString implReadBootstrapKey( const OUString& _rKey )
345 OUString sValue;
346 rtl::Bootstrap::get(_rKey, sValue);
347 return sValue;
350 void SplashScreen::loadConfig()
352 _bShowLogo = implReadBootstrapKey( "Logo" ) != "0";
354 OUString sProgressFrameColor = implReadBootstrapKey( "ProgressFrameColor" );
355 OUString sProgressBarColor = implReadBootstrapKey( "ProgressBarColor" );
356 OUString sProgressTextColor = implReadBootstrapKey( "ProgressTextColor" );
357 OUString sProgressTextBaseline = implReadBootstrapKey( "ProgressTextBaseline" );
358 OUString sSize = implReadBootstrapKey( "ProgressSize" );
359 OUString sPosition = implReadBootstrapKey( "ProgressPosition" );
360 OUString sFullScreenSplash = implReadBootstrapKey( "FullScreenSplash" );
361 OUString sNativeProgress = implReadBootstrapKey( "NativeProgress" );
364 // Determine full screen splash mode
365 _bFullScreenSplash = (( !sFullScreenSplash.isEmpty() ) &&
366 ( sFullScreenSplash != "0" ));
368 // Try to retrieve the relative values for the progress bar. The current
369 // schema uses the screen ratio to retrieve the associated values.
370 if ( _bFullScreenSplash )
371 determineProgressRatioValues( _fXPos, _fYPos, _fWidth, _fHeight );
373 if ( !sProgressFrameColor.isEmpty() )
375 sal_uInt8 nRed = 0;
376 sal_Int32 idx = 0;
377 sal_Int32 temp = sProgressFrameColor.getToken( 0, ',', idx ).toInt32();
378 if ( idx != -1 )
380 nRed = static_cast< sal_uInt8 >( temp );
381 temp = sProgressFrameColor.getToken( 0, ',', idx ).toInt32();
383 if ( idx != -1 )
385 sal_uInt8 nGreen = static_cast< sal_uInt8 >( temp );
386 sal_uInt8 nBlue = static_cast< sal_uInt8 >( sProgressFrameColor.getToken( 0, ',', idx ).toInt32() );
387 _cProgressFrameColor = Color( nRed, nGreen, nBlue );
391 if ( !sProgressBarColor.isEmpty() )
393 sal_uInt8 nRed = 0;
394 sal_Int32 idx = 0;
395 sal_Int32 temp = sProgressBarColor.getToken( 0, ',', idx ).toInt32();
396 if ( idx != -1 )
398 nRed = static_cast< sal_uInt8 >( temp );
399 temp = sProgressBarColor.getToken( 0, ',', idx ).toInt32();
401 if ( idx != -1 )
403 sal_uInt8 nGreen = static_cast< sal_uInt8 >( temp );
404 sal_uInt8 nBlue = static_cast< sal_uInt8 >( sProgressBarColor.getToken( 0, ',', idx ).toInt32() );
405 _cProgressBarColor = Color( nRed, nGreen, nBlue );
409 if ( !sProgressTextColor.isEmpty() )
411 sal_uInt8 nRed = 0;
412 sal_Int32 idx = 0;
413 sal_Int32 temp = sProgressTextColor.getToken( 0, ',', idx ).toInt32();
414 if ( idx != -1 )
416 nRed = static_cast< sal_uInt8 >( temp );
417 temp = sProgressTextColor.getToken( 0, ',', idx ).toInt32();
419 if ( idx != -1 )
421 sal_uInt8 nGreen = static_cast< sal_uInt8 >( temp );
422 sal_uInt8 nBlue = static_cast< sal_uInt8 >( sProgressTextColor.getToken( 0, ',', idx ).toInt32() );
423 _cProgressTextColor = Color( nRed, nGreen, nBlue );
427 if ( !sProgressTextBaseline.isEmpty() )
429 _textBaseline = sProgressTextBaseline.toInt32();
432 if( !sNativeProgress.isEmpty() )
434 _bNativeProgress = sNativeProgress.toBoolean();
437 if ( !sSize.isEmpty() )
439 sal_Int32 idx = 0;
440 sal_Int32 temp = sSize.getToken( 0, ',', idx ).toInt32();
441 if ( idx != -1 )
443 _barwidth = temp;
444 _barheight = sSize.getToken( 0, ',', idx ).toInt32();
448 if ( _barheight >= 10 )
449 _barspace = 3; // more space between frame and bar
451 if ( !sPosition.isEmpty() )
453 sal_Int32 idx = 0;
454 sal_Int32 temp = sPosition.getToken( 0, ',', idx ).toInt32();
455 if ( idx != -1 )
457 _tlx = temp;
458 _tly = sPosition.getToken( 0, ',', idx ).toInt32();
463 void SplashScreen::SetScreenBitmap(BitmapEx &rBitmap)
465 sal_Int32 nWidth( 0 );
466 sal_Int32 nHeight( 0 );
468 // determine desktop resolution
469 sal_uInt32 nCount = Application::GetScreenCount();
470 if ( nCount > 0 )
472 // retrieve size from first screen
473 tools::Rectangle aScreenArea = Application::GetScreenPosSizePixel(static_cast<unsigned int>(0));
474 nWidth = aScreenArea.GetWidth();
475 nHeight = aScreenArea.GetHeight();
478 // create file name from screen resolution information
479 OStringBuffer aStrBuf( 128 );
480 aStrBuf.append( "intro_" );
481 if ( !_sAppName.isEmpty() )
483 aStrBuf.append( OUStringToOString(_sAppName, RTL_TEXTENCODING_UTF8) );
484 aStrBuf.append( "_" );
486 OString aResBuf = OString::number( nWidth ) + "x" + OString::number( nHeight );
488 aStrBuf.append( aResBuf.getStr() );
489 if (Application::LoadBrandBitmap (aStrBuf.makeStringAndClear().getStr(), rBitmap))
490 return;
492 aStrBuf.append( "intro_" );
493 aStrBuf.append( aResBuf.getStr() );
494 if (Application::LoadBrandBitmap (aResBuf.getStr(), rBitmap))
495 return;
497 (void)Application::LoadBrandBitmap ("intro", rBitmap);
500 void SplashScreen::determineProgressRatioValues(
501 double& rXRelPos, double& rYRelPos,
502 double& rRelWidth, double& rRelHeight )
504 sal_Int32 nWidth( 0 );
505 sal_Int32 nHeight( 0 );
506 sal_Int32 nScreenRatio( 0 );
508 // determine desktop resolution
509 sal_uInt32 nCount = Application::GetScreenCount();
510 if ( nCount > 0 )
512 // retrieve size from first screen
513 tools::Rectangle aScreenArea = Application::GetScreenPosSizePixel(static_cast<unsigned int>(0));
514 nWidth = aScreenArea.GetWidth();
515 nHeight = aScreenArea.GetHeight();
516 nScreenRatio = nHeight ? sal_Int32( rtl::math::round( double( nWidth ) / double( nHeight ), 2 ) * 100 ) : 0;
519 char szFullScreenProgressRatio[] = "FullScreenProgressRatio0";
520 char szFullScreenProgressPos[] = "FullScreenProgressPos0";
521 char szFullScreenProgressSize[] = "FullScreenProgressSize0";
522 for ( sal_Int32 i = 0; i <= 9; i++ )
524 char cNum = '0' + char( i );
525 szFullScreenProgressRatio[23] = cNum;
526 szFullScreenProgressPos[21] = cNum;
527 szFullScreenProgressSize[22] = cNum;
529 OUString sFullScreenProgressRatio = implReadBootstrapKey(
530 OUString::createFromAscii( szFullScreenProgressRatio ) );
532 if ( !sFullScreenProgressRatio.isEmpty() )
534 double fRatio = sFullScreenProgressRatio.toDouble();
535 sal_Int32 nRatio = sal_Int32( rtl::math::round( fRatio, 2 ) * 100 );
536 if ( nRatio == nScreenRatio )
538 OUString sFullScreenProgressPos = implReadBootstrapKey(
539 OUString::createFromAscii( szFullScreenProgressPos ) );
540 OUString sFullScreenProgressSize = implReadBootstrapKey(
541 OUString::createFromAscii( szFullScreenProgressSize ) );
543 if ( !sFullScreenProgressPos.isEmpty() )
545 sal_Int32 idx = 0;
546 double temp = sFullScreenProgressPos.getToken( 0, ',', idx ).toDouble();
547 if ( idx != -1 )
549 rXRelPos = temp;
550 rYRelPos = sFullScreenProgressPos.getToken( 0, ',', idx ).toDouble();
554 if ( !sFullScreenProgressSize.isEmpty() )
556 sal_Int32 idx = 0;
557 double temp = sFullScreenProgressSize.getToken( 0, ',', idx ).toDouble();
558 if ( idx != -1 )
560 rRelWidth = temp;
561 rRelHeight = sFullScreenProgressSize.getToken( 0, ',', idx ).toDouble();
566 else
567 break;
571 void SplashScreenWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
573 if (!pSpl || !pSpl->_bVisible)
574 return;
576 //native drawing
577 // in case of native controls we need to draw directly to the window
578 if (pSpl->_bNativeProgress && rRenderContext.IsNativeControlSupported(ControlType::IntroProgress, ControlPart::Entire))
580 rRenderContext.DrawBitmapEx(Point(), pSpl->_aIntroBmp);
582 ImplControlValue aValue( pSpl->_iProgress * pSpl->_barwidth / pSpl->_iMax);
583 tools::Rectangle aDrawRect( Point(pSpl->_tlx, pSpl->_tly), Size( pSpl->_barwidth, pSpl->_barheight));
584 tools::Rectangle aNativeControlRegion, aNativeContentRegion;
586 if (rRenderContext.GetNativeControlRegion(ControlType::IntroProgress, ControlPart::Entire, aDrawRect,
587 ControlState::ENABLED, aValue,
588 aNativeControlRegion, aNativeContentRegion))
590 long nProgressHeight = aNativeControlRegion.GetHeight();
591 aDrawRect.AdjustTop( -((nProgressHeight - pSpl->_barheight)/2) );
592 aDrawRect.AdjustBottom((nProgressHeight - pSpl->_barheight)/2 );
595 if (rRenderContext.DrawNativeControl(ControlType::IntroProgress, ControlPart::Entire, aDrawRect,
596 ControlState::ENABLED, aValue, pSpl->_sProgressText))
598 return;
602 // non native drawing
603 // draw bitmap
604 _vdev->DrawBitmapEx(Point(), pSpl->_aIntroBmp);
606 if (pSpl->_bPaintProgress) {
607 // draw progress...
608 long length = (pSpl->_iProgress * pSpl->_barwidth / pSpl->_iMax) - (2 * pSpl->_barspace);
609 if (length < 0) length = 0;
611 // border
612 _vdev->SetFillColor();
613 _vdev->SetLineColor( pSpl->_cProgressFrameColor );
614 _vdev->DrawRect(tools::Rectangle(pSpl->_tlx, pSpl->_tly, pSpl->_tlx+pSpl->_barwidth, pSpl->_tly+pSpl->_barheight));
615 _vdev->SetFillColor( pSpl->_cProgressBarColor );
616 _vdev->SetLineColor();
617 _vdev->DrawRect(tools::Rectangle(pSpl->_tlx+pSpl->_barspace, pSpl->_tly+pSpl->_barspace, pSpl->_tlx+pSpl->_barspace+length, pSpl->_tly+pSpl->_barheight-pSpl->_barspace));
618 vcl::Font aFont;
619 aFont.SetFontSize(Size(0, 12));
620 aFont.SetAlignment(ALIGN_BASELINE);
621 _vdev->SetFont(aFont);
622 _vdev->SetTextColor(pSpl->_cProgressTextColor);
623 _vdev->DrawText(Point(pSpl->_tlx, pSpl->_textBaseline), pSpl->_sProgressText);
625 rRenderContext.DrawOutDev(Point(), GetOutputSizePixel(), Point(), _vdev->GetOutputSizePixel(), *_vdev.get());
629 // get service instance...
630 osl::Mutex SplashScreen::_aMutex;
634 css::uno::Reference< css::uno::XInterface > desktop::splash::create(
635 css::uno::Reference< css::uno::XComponentContext > const &)
637 return static_cast< cppu::OWeakObject * >(new SplashScreen);
640 OUString desktop::splash::getImplementationName() {
641 return "com.sun.star.office.comp.SplashScreen";
644 css::uno::Sequence< OUString > desktop::splash::getSupportedServiceNames()
646 return { "com.sun.star.office.SplashScreen" };
649 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */