1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <comphelper/string.hxx>
30 #include <cppuhelper/implbase.hxx>
31 #include <cppuhelper/supportsservice.hxx>
32 #include <rtl/bootstrap.hxx>
33 #include <rtl/strbuf.hxx>
34 #include <rtl/math.hxx>
35 #include <vcl/introwin.hxx>
36 #include <vcl/virdev.hxx>
37 #include <o3tl/string_view.hxx>
41 #define NOT_LOADED (tools::Long(-1))
42 #define NOT_LOADED_COLOR (Color(ColorTransparency, 0xffffffff))
44 using namespace ::com::sun::star::lang
;
45 using namespace ::com::sun::star::task
;
46 using namespace ::com::sun::star::uno
;
52 class SplashScreenWindow
: public IntroWindow
56 ScopedVclPtr
<VirtualDevice
> _vdev
;
57 explicit SplashScreenWindow(SplashScreen
*);
58 virtual ~SplashScreenWindow() override
{ disposeOnce(); }
59 virtual void dispose() override
;
61 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&) override
;
67 : public ::cppu::WeakImplHelper
< XStatusIndicator
, XInitialization
, XServiceInfo
>
69 friend class SplashScreenWindow
;
71 VclPtr
<SplashScreenWindow
> pWindow
;
73 DECL_LINK( AppEventListenerHdl
, VclSimpleEvent
&, void );
74 virtual ~SplashScreen() override
;
77 void SetScreenBitmap(BitmapEx
&rBitmap
);
78 static void determineProgressRatioValues( double& rXRelPos
, double& rYRelPos
, double& rRelWidth
, double& rRelHeight
);
81 Color _cProgressFrameColor
;
82 Color _cProgressBarColor
;
83 Color _cProgressTextColor
;
84 bool _bNativeProgress
;
86 OUString _sProgressText
;
93 bool _bFullScreenSplash
;
95 tools::Long _height
, _width
, _tlx
, _tly
, _barwidth
;
96 tools::Long _barheight
, _barspace
, _textBaseline
;
97 double _fXPos
, _fYPos
;
98 double _fWidth
, _fHeight
;
99 static constexpr tools::Long _xoffset
= 12, _yoffset
= 18;
105 virtual void SAL_CALL
end() override
;
106 virtual void SAL_CALL
reset() override
;
107 virtual void SAL_CALL
setText(const OUString
& aText
) override
;
108 virtual void SAL_CALL
setValue(sal_Int32 nValue
) override
;
109 virtual void SAL_CALL
start(const OUString
& aText
, sal_Int32 nRange
) override
;
112 virtual void SAL_CALL
initialize( const css::uno::Sequence
< css::uno::Any
>& aArguments
) override
;
114 virtual OUString SAL_CALL
getImplementationName() override
115 { return "com.sun.star.office.comp.SplashScreen"; }
117 virtual sal_Bool SAL_CALL
supportsService(OUString
const & ServiceName
) override
118 { return cppu::supportsService(this, ServiceName
); }
120 virtual css::uno::Sequence
<OUString
> SAL_CALL
getSupportedServiceNames() override
121 { return { "com.sun.star.office.SplashScreen" }; }
124 SplashScreenWindow::SplashScreenWindow(SplashScreen
*pSplash
)
126 , _vdev(VclPtr
<VirtualDevice
>::Create(*GetOutDev()))
128 _vdev
->EnableRTL(IsRTLEnabled());
131 void SplashScreenWindow::dispose()
134 IntroWindow::dispose();
137 void SplashScreenWindow::Redraw()
140 // Trigger direct painting too - otherwise the splash screen won't be
141 // shown in some cases (when the idle timer won't be hit).
142 Paint(*GetOutDev(), tools::Rectangle());
143 GetOutDev()->Flush();
146 SplashScreen::SplashScreen()
147 : pWindow( VclPtr
<SplashScreenWindow
>::Create(this) )
148 , _cProgressFrameColor(NOT_LOADED_COLOR
)
149 , _cProgressBarColor(NOT_LOADED_COLOR
)
150 , _cProgressTextColor(NOT_LOADED_COLOR
)
151 , _bNativeProgress(true)
154 , _bPaintProgress(false)
157 , _bFullScreenSplash(false)
158 , _bProgressEnd(false)
163 , _barwidth(NOT_LOADED
)
164 , _barheight(NOT_LOADED
)
166 , _textBaseline(NOT_LOADED
)
175 SplashScreen::~SplashScreen()
177 Application::RemoveEventListener(
178 LINK( this, SplashScreen
, AppEventListenerHdl
) );
180 pWindow
.disposeAndClear();
183 void SAL_CALL
SplashScreen::start(const OUString
&, sal_Int32 nRange
)
187 _bProgressEnd
= false;
188 SolarMutexGuard aSolarGuard
;
194 void SAL_CALL
SplashScreen::end()
201 _bProgressEnd
= true;
204 void SAL_CALL
SplashScreen::reset()
207 if (_bVisible
&& !_bProgressEnd
)
214 void SAL_CALL
SplashScreen::setText(const OUString
& rText
)
216 SolarMutexGuard aSolarGuard
;
217 if ( _sProgressText
!= rText
)
219 _sProgressText
= rText
;
221 if (_bVisible
&& !_bProgressEnd
)
229 void SAL_CALL
SplashScreen::setValue(sal_Int32 nValue
)
231 SAL_INFO( "desktop.splash", "setValue: " << nValue
);
233 SolarMutexGuard aSolarGuard
;
234 if (_bVisible
&& !_bProgressEnd
) {
246 SplashScreen::initialize( const css::uno::Sequence
< css::uno::Any
>& aArguments
)
248 static std::mutex aMutex
;
249 std::lock_guard
aGuard( aMutex
);
250 if (!aArguments
.hasElements())
253 aArguments
[0] >>= _bVisible
;
254 if (aArguments
.getLength() > 1 )
255 aArguments
[1] >>= _sAppName
;
257 // start to determine bitmap and all other required value
259 SetScreenBitmap (_aIntroBmp
);
260 Size aSize
= _aIntroBmp
.GetSizePixel();
261 pWindow
->SetOutputSizePixel( aSize
);
262 pWindow
->_vdev
->SetOutputSizePixel( aSize
);
263 _height
= aSize
.Height();
264 _width
= aSize
.Width();
267 Point
xtopleft(212,216);
268 if ( NOT_LOADED
== _tlx
|| NOT_LOADED
== _tly
)
270 _tlx
= xtopleft
.X(); // top-left x
271 _tly
= xtopleft
.Y(); // top-left y
273 if ( NOT_LOADED
== _barwidth
)
275 if ( NOT_LOADED
== _barheight
)
280 if ( NOT_LOADED
== _barwidth
)
281 _barwidth
= _width
- (2 * _xoffset
);
282 if ( NOT_LOADED
== _barheight
)
284 if ( NOT_LOADED
== _tlx
|| NOT_LOADED
== _tly
)
286 _tlx
= _xoffset
; // top-left x
287 _tly
= _height
- _yoffset
; // top-left y
291 if ( NOT_LOADED
== _textBaseline
)
292 _textBaseline
= _height
;
294 if ( NOT_LOADED_COLOR
== _cProgressFrameColor
)
295 _cProgressFrameColor
= COL_LIGHTGRAY
;
297 if ( NOT_LOADED_COLOR
== _cProgressBarColor
)
299 // progress bar: new color only for big bitmap format
301 _cProgressBarColor
= Color( 157, 202, 18 );
303 _cProgressBarColor
= COL_BLUE
;
306 if ( NOT_LOADED_COLOR
== _cProgressTextColor
)
307 _cProgressTextColor
= COL_BLACK
;
309 Application::AddEventListener(
310 LINK( this, SplashScreen
, AppEventListenerHdl
) );
313 void SplashScreen::updateStatus()
315 if (!_bVisible
|| _bProgressEnd
)
317 if (!_bPaintProgress
)
318 _bPaintProgress
= true;
322 // internal private methods
323 IMPL_LINK( SplashScreen
, AppEventListenerHdl
, VclSimpleEvent
&, inEvent
, void )
325 if (static_cast<VclWindowEvent
&>(inEvent
).GetWindow() == pWindow
)
327 switch ( inEvent
.GetId() )
329 case VclEventId::WindowShow
:
338 // Read keys from soffice{.ini|rc}:
339 OUString
implReadBootstrapKey( const OUString
& _rKey
)
342 rtl::Bootstrap::get(_rKey
, sValue
);
346 void SplashScreen::loadConfig()
348 _bShowLogo
= implReadBootstrapKey( "Logo" ) != "0";
350 OUString sProgressFrameColor
= implReadBootstrapKey( "ProgressFrameColor" );
351 OUString sProgressBarColor
= implReadBootstrapKey( "ProgressBarColor" );
352 OUString sProgressTextColor
= implReadBootstrapKey( "ProgressTextColor" );
353 OUString sProgressTextBaseline
= implReadBootstrapKey( "ProgressTextBaseline" );
354 OUString sSize
= implReadBootstrapKey( "ProgressSize" );
355 OUString sPosition
= implReadBootstrapKey( "ProgressPosition" );
356 OUString sFullScreenSplash
= implReadBootstrapKey( "FullScreenSplash" );
357 OUString sNativeProgress
= implReadBootstrapKey( "NativeProgress" );
360 // Determine full screen splash mode
361 _bFullScreenSplash
= (( !sFullScreenSplash
.isEmpty() ) &&
362 ( sFullScreenSplash
!= "0" ));
364 // Try to retrieve the relative values for the progress bar. The current
365 // schema uses the screen ratio to retrieve the associated values.
366 if ( _bFullScreenSplash
)
367 determineProgressRatioValues( _fXPos
, _fYPos
, _fWidth
, _fHeight
);
369 if ( !sProgressFrameColor
.isEmpty() )
373 sal_Int32 temp
= o3tl::toInt32(o3tl::getToken(sProgressFrameColor
, 0, ',', idx
));
376 nRed
= static_cast< sal_uInt8
>( temp
);
377 temp
= o3tl::toInt32(o3tl::getToken(sProgressFrameColor
, 0, ',', idx
));
381 sal_uInt8 nGreen
= static_cast< sal_uInt8
>( temp
);
382 sal_uInt8 nBlue
= static_cast< sal_uInt8
>( o3tl::toInt32(o3tl::getToken(sProgressFrameColor
, 0, ',', idx
)) );
383 _cProgressFrameColor
= Color( nRed
, nGreen
, nBlue
);
387 if ( !sProgressBarColor
.isEmpty() )
391 sal_Int32 temp
= o3tl::toInt32(o3tl::getToken(sProgressBarColor
, 0, ',', idx
));
394 nRed
= static_cast< sal_uInt8
>( temp
);
395 temp
= o3tl::toInt32(o3tl::getToken(sProgressBarColor
, 0, ',', idx
));
399 sal_uInt8 nGreen
= static_cast< sal_uInt8
>( temp
);
400 sal_uInt8 nBlue
= static_cast< sal_uInt8
>( o3tl::toInt32(o3tl::getToken(sProgressBarColor
, 0, ',', idx
)) );
401 _cProgressBarColor
= Color( nRed
, nGreen
, nBlue
);
405 if ( !sProgressTextColor
.isEmpty() )
409 sal_Int32 temp
= o3tl::toInt32(o3tl::getToken(sProgressTextColor
, 0, ',', idx
));
412 nRed
= static_cast< sal_uInt8
>( temp
);
413 temp
= o3tl::toInt32(o3tl::getToken(sProgressTextColor
, 0, ',', idx
));
417 sal_uInt8 nGreen
= static_cast< sal_uInt8
>( temp
);
418 sal_uInt8 nBlue
= static_cast< sal_uInt8
>( o3tl::toInt32(o3tl::getToken(sProgressTextColor
, 0, ',', idx
)) );
419 _cProgressTextColor
= Color( nRed
, nGreen
, nBlue
);
423 if ( !sProgressTextBaseline
.isEmpty() )
425 _textBaseline
= sProgressTextBaseline
.toInt32();
428 if( !sNativeProgress
.isEmpty() )
430 _bNativeProgress
= sNativeProgress
.toBoolean();
433 if ( !sSize
.isEmpty() )
436 sal_Int32 temp
= o3tl::toInt32(o3tl::getToken(sSize
, 0, ',', idx
));
440 _barheight
= o3tl::toInt32(o3tl::getToken(sSize
, 0, ',', idx
));
444 if ( _barheight
>= 10 )
445 _barspace
= 3; // more space between frame and bar
447 if ( !sPosition
.isEmpty() )
450 sal_Int32 temp
= o3tl::toInt32(o3tl::getToken(sPosition
, 0, ',', idx
));
454 _tly
= o3tl::toInt32(o3tl::getToken(sPosition
, 0, ',', idx
));
459 void SplashScreen::SetScreenBitmap(BitmapEx
&rBitmap
)
461 sal_Int32
nWidth( 0 );
462 sal_Int32
nHeight( 0 );
464 // determine desktop resolution
465 sal_uInt32 nCount
= Application::GetScreenCount();
468 // retrieve size from first screen
469 tools::Rectangle aScreenArea
= Application::GetScreenPosSizePixel(static_cast<unsigned int>(0));
470 nWidth
= aScreenArea
.GetWidth();
471 nHeight
= aScreenArea
.GetHeight();
474 // create file name from screen resolution information
475 OUString aResBuf
= "_" + OUString::number(nWidth
) + "x" + OUString::number(nHeight
);
476 if ( !_sAppName
.isEmpty() )
477 if (Application::LoadBrandBitmap(Concat2View("intro_" + _sAppName
+ aResBuf
), rBitmap
))
480 if (Application::LoadBrandBitmap(Concat2View("intro" + aResBuf
), rBitmap
))
483 (void)Application::LoadBrandBitmap (u
"intro", rBitmap
);
486 void SplashScreen::determineProgressRatioValues(
487 double& rXRelPos
, double& rYRelPos
,
488 double& rRelWidth
, double& rRelHeight
)
490 sal_Int32
nScreenRatio( 0 );
492 // determine desktop resolution
493 sal_uInt32 nCount
= Application::GetScreenCount();
496 // retrieve size from first screen
497 tools::Rectangle aScreenArea
= Application::GetScreenPosSizePixel(static_cast<unsigned int>(0));
498 sal_Int32 nWidth
= aScreenArea
.GetWidth();
499 sal_Int32 nHeight
= aScreenArea
.GetHeight();
500 nScreenRatio
= nHeight
? sal_Int32( rtl::math::round( double( nWidth
) / double( nHeight
), 2 ) * 100 ) : 0;
503 char szFullScreenProgressRatio
[] = "FullScreenProgressRatio0";
504 char szFullScreenProgressPos
[] = "FullScreenProgressPos0";
505 char szFullScreenProgressSize
[] = "FullScreenProgressSize0";
506 for ( sal_Int32 i
= 0; i
<= 9; i
++ )
508 char cNum
= '0' + char( i
);
509 szFullScreenProgressRatio
[23] = cNum
;
510 szFullScreenProgressPos
[21] = cNum
;
511 szFullScreenProgressSize
[22] = cNum
;
513 OUString sFullScreenProgressRatio
= implReadBootstrapKey(
514 OUString::createFromAscii( szFullScreenProgressRatio
) );
516 if ( !sFullScreenProgressRatio
.isEmpty() )
518 double fRatio
= sFullScreenProgressRatio
.toDouble();
519 sal_Int32 nRatio
= sal_Int32( rtl::math::round( fRatio
, 2 ) * 100 );
520 if ( nRatio
== nScreenRatio
)
522 OUString sFullScreenProgressPos
= implReadBootstrapKey(
523 OUString::createFromAscii( szFullScreenProgressPos
) );
524 OUString sFullScreenProgressSize
= implReadBootstrapKey(
525 OUString::createFromAscii( szFullScreenProgressSize
) );
527 if ( !sFullScreenProgressPos
.isEmpty() )
530 double temp
= o3tl::toDouble(o3tl::getToken(sFullScreenProgressPos
, 0, ',', idx
));
534 rYRelPos
= o3tl::toDouble(o3tl::getToken(sFullScreenProgressPos
, 0, ',', idx
));
538 if ( !sFullScreenProgressSize
.isEmpty() )
541 double temp
= o3tl::toDouble(o3tl::getToken(sFullScreenProgressSize
, 0, ',', idx
));
545 rRelHeight
= o3tl::toDouble(o3tl::getToken(sFullScreenProgressSize
, 0, ',', idx
));
555 void SplashScreenWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
557 if (!pSpl
|| !pSpl
->_bVisible
)
561 // in case of native controls we need to draw directly to the window
562 if (pSpl
->_bNativeProgress
&& rRenderContext
.IsNativeControlSupported(ControlType::IntroProgress
, ControlPart::Entire
))
564 rRenderContext
.DrawBitmapEx(Point(), pSpl
->_aIntroBmp
);
566 ImplControlValue
aValue( pSpl
->_iProgress
* pSpl
->_barwidth
/ pSpl
->_iMax
);
567 tools::Rectangle
aDrawRect( Point(pSpl
->_tlx
, pSpl
->_tly
), Size( pSpl
->_barwidth
, pSpl
->_barheight
));
568 tools::Rectangle aNativeControlRegion
, aNativeContentRegion
;
570 if (rRenderContext
.GetNativeControlRegion(ControlType::IntroProgress
, ControlPart::Entire
, aDrawRect
,
571 ControlState::ENABLED
, aValue
,
572 aNativeControlRegion
, aNativeContentRegion
))
574 tools::Long nProgressHeight
= aNativeControlRegion
.GetHeight();
575 aDrawRect
.AdjustTop( -((nProgressHeight
- pSpl
->_barheight
)/2) );
576 aDrawRect
.AdjustBottom((nProgressHeight
- pSpl
->_barheight
)/2 );
579 if (rRenderContext
.DrawNativeControl(ControlType::IntroProgress
, ControlPart::Entire
, aDrawRect
,
580 ControlState::ENABLED
, aValue
, pSpl
->_sProgressText
))
586 // non native drawing
588 _vdev
->DrawBitmapEx(Point(), pSpl
->_aIntroBmp
);
590 if (pSpl
->_bPaintProgress
) {
592 tools::Long length
= (pSpl
->_iProgress
* pSpl
->_barwidth
/ pSpl
->_iMax
) - (2 * pSpl
->_barspace
);
593 if (length
< 0) length
= 0;
596 _vdev
->SetFillColor();
597 _vdev
->SetLineColor( pSpl
->_cProgressFrameColor
);
598 _vdev
->DrawRect(tools::Rectangle(pSpl
->_tlx
, pSpl
->_tly
, pSpl
->_tlx
+pSpl
->_barwidth
, pSpl
->_tly
+pSpl
->_barheight
));
599 _vdev
->SetFillColor( pSpl
->_cProgressBarColor
);
600 _vdev
->SetLineColor();
601 _vdev
->DrawRect(tools::Rectangle(pSpl
->_tlx
+pSpl
->_barspace
, pSpl
->_tly
+pSpl
->_barspace
, pSpl
->_tlx
+pSpl
->_barspace
+length
, pSpl
->_tly
+pSpl
->_barheight
-pSpl
->_barspace
));
603 aFont
.SetFontSize(Size(0, 12));
604 aFont
.SetAlignment(ALIGN_BASELINE
);
605 _vdev
->SetFont(aFont
);
606 _vdev
->SetTextColor(pSpl
->_cProgressTextColor
);
607 _vdev
->DrawText(Point(pSpl
->_tlx
, pSpl
->_textBaseline
), pSpl
->_sProgressText
);
609 rRenderContext
.DrawOutDev(Point(), GetOutputSizePixel(), Point(), _vdev
->GetOutputSizePixel(), *_vdev
);
614 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
615 desktop_SplashScreen_get_implementation(
616 css::uno::XComponentContext
* , css::uno::Sequence
<css::uno::Any
> const&)
618 return cppu::acquire(new SplashScreen());
622 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */