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 <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>
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
;
50 class SplashScreenWindow
: public IntroWindow
54 ScopedVclPtr
<VirtualDevice
> _vdev
;
55 explicit SplashScreenWindow(SplashScreen
*);
56 virtual ~SplashScreenWindow() override
{ disposeOnce(); }
57 virtual void dispose() override
;
59 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&) override
;
65 : public ::cppu::WeakImplHelper
< XStatusIndicator
, XInitialization
, XServiceInfo
>
67 friend class SplashScreenWindow
;
69 VclPtr
<SplashScreenWindow
> pWindow
;
71 DECL_LINK( AppEventListenerHdl
, VclSimpleEvent
&, void );
72 virtual ~SplashScreen() override
;
75 void SetScreenBitmap(BitmapEx
&rBitmap
);
76 static void determineProgressRatioValues( double& rXRelPos
, double& rYRelPos
, double& rRelWidth
, double& rRelHeight
);
79 Color _cProgressFrameColor
;
80 Color _cProgressBarColor
;
81 Color _cProgressTextColor
;
82 bool _bNativeProgress
;
84 OUString _sProgressText
;
91 bool _bFullScreenSplash
;
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;
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
;
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
)
124 , _vdev(VclPtr
<VirtualDevice
>::Create(*GetOutDev()))
126 _vdev
->EnableRTL(IsRTLEnabled());
129 void SplashScreenWindow::dispose()
132 IntroWindow::dispose();
135 void SplashScreenWindow::Redraw()
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)
152 , _bPaintProgress(false)
155 , _bFullScreenSplash(false)
156 , _bProgressEnd(false)
161 , _barwidth(NOT_LOADED
)
162 , _barheight(NOT_LOADED
)
164 , _textBaseline(NOT_LOADED
)
173 SplashScreen::~SplashScreen()
175 Application::RemoveEventListener(
176 LINK( this, SplashScreen
, AppEventListenerHdl
) );
178 pWindow
.disposeAndClear();
181 void SAL_CALL
SplashScreen::start(const OUString
&, sal_Int32 nRange
)
185 _bProgressEnd
= false;
186 SolarMutexGuard aSolarGuard
;
192 void SAL_CALL
SplashScreen::end()
199 _bProgressEnd
= true;
202 void SAL_CALL
SplashScreen::reset()
205 if (_bVisible
&& !_bProgressEnd
)
212 void SAL_CALL
SplashScreen::setText(const OUString
& rText
)
214 SolarMutexGuard aSolarGuard
;
215 if ( _sProgressText
!= rText
)
217 _sProgressText
= rText
;
219 if (_bVisible
&& !_bProgressEnd
)
227 void SAL_CALL
SplashScreen::setValue(sal_Int32 nValue
)
229 SAL_INFO( "desktop.splash", "setValue: " << nValue
);
231 SolarMutexGuard aSolarGuard
;
232 if (_bVisible
&& !_bProgressEnd
) {
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())
251 aArguments
[0] >>= _bVisible
;
252 if (aArguments
.getLength() > 1 )
253 aArguments
[1] >>= _sAppName
;
255 // start to determine bitmap and all other required value
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();
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
)
273 if ( NOT_LOADED
== _barheight
)
278 if ( NOT_LOADED
== _barwidth
)
279 _barwidth
= _width
- (2 * _xoffset
);
280 if ( NOT_LOADED
== _barheight
)
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
299 _cProgressBarColor
= Color( 157, 202, 18 );
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
)
315 if (!_bPaintProgress
)
316 _bPaintProgress
= true;
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
:
336 // Read keys from soffice{.ini|rc}:
337 OUString
implReadBootstrapKey( const OUString
& _rKey
)
340 rtl::Bootstrap::get(_rKey
, 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() )
371 sal_Int32 temp
= o3tl::toInt32(o3tl::getToken(sProgressFrameColor
, 0, ',', idx
));
374 nRed
= static_cast< sal_uInt8
>( temp
);
375 temp
= o3tl::toInt32(o3tl::getToken(sProgressFrameColor
, 0, ',', idx
));
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() )
389 sal_Int32 temp
= o3tl::toInt32(o3tl::getToken(sProgressBarColor
, 0, ',', idx
));
392 nRed
= static_cast< sal_uInt8
>( temp
);
393 temp
= o3tl::toInt32(o3tl::getToken(sProgressBarColor
, 0, ',', idx
));
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() )
407 sal_Int32 temp
= o3tl::toInt32(o3tl::getToken(sProgressTextColor
, 0, ',', idx
));
410 nRed
= static_cast< sal_uInt8
>( temp
);
411 temp
= o3tl::toInt32(o3tl::getToken(sProgressTextColor
, 0, ',', idx
));
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() )
434 sal_Int32 temp
= o3tl::toInt32(o3tl::getToken(sSize
, 0, ',', idx
));
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() )
448 sal_Int32 temp
= o3tl::toInt32(o3tl::getToken(sPosition
, 0, ',', idx
));
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();
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
))
478 if (Application::LoadBrandBitmap(Concat2View("intro" + aResBuf
), rBitmap
))
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();
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() )
528 double temp
= o3tl::toDouble(o3tl::getToken(sFullScreenProgressPos
, 0, ',', idx
));
532 rYRelPos
= o3tl::toDouble(o3tl::getToken(sFullScreenProgressPos
, 0, ',', idx
));
536 if ( !sFullScreenProgressSize
.isEmpty() )
539 double temp
= o3tl::toDouble(o3tl::getToken(sFullScreenProgressSize
, 0, ',', idx
));
543 rRelHeight
= o3tl::toDouble(o3tl::getToken(sFullScreenProgressSize
, 0, ',', idx
));
553 void SplashScreenWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
555 if (!pSpl
|| !pSpl
->_bVisible
)
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
))
584 // non native drawing
586 _vdev
->DrawBitmapEx(Point(), pSpl
->_aIntroBmp
);
588 if (pSpl
->_bPaintProgress
) {
590 tools::Long length
= (pSpl
->_iProgress
* pSpl
->_barwidth
/ pSpl
->_iMax
) - (2 * pSpl
->_barspace
);
591 if (length
< 0) length
= 0;
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
));
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: */