1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qsplashscreen.h"
43 
44 #ifndef QT_NO_SPLASHSCREEN
45 
46 #include "qapplication.h"
47 #include "qdesktopwidget.h"
48 #include "qpainter.h"
49 #include "qpixmap.h"
50 #include "qtextdocument.h"
51 #include "qtextcursor.h"
52 #include <QtCore/qdebug.h>
53 #include <private/qwidget_p.h>
54 
55 QT_BEGIN_NAMESPACE
56 
57 class QSplashScreenPrivate : public QWidgetPrivate
58 {
59     Q_DECLARE_PUBLIC(QSplashScreen)
60 public:
61     QPixmap pixmap;
62     QString currStatus;
63     QColor currColor;
64     int currAlign;
65 
66     inline QSplashScreenPrivate();
67 };
68 
69 /*!
70    \class QSplashScreen
71    \brief The QSplashScreen widget provides a splash screen that can
72    be shown during application startup.
73 
74    A splash screen is a widget that is usually displayed when an
75    application is being started. Splash screens are often used for
76    applications that have long start up times (e.g. database or
77    networking applications that take time to establish connections) to
78    provide the user with feedback that the application is loading.
79 
80    The splash screen appears in the center of the screen. It may be
81    useful to add the Qt::WindowStaysOnTopHint to the splash widget's
82    window flags if you want to keep it above all the other windows on
83    the desktop.
84 
85    Some X11 window managers do not support the "stays on top" flag. A
86    solution is to set up a timer that periodically calls raise() on
87    the splash screen to simulate the "stays on top" effect.
88 
89    The most common usage is to show a splash screen before the main
90    widget is displayed on the screen. This is illustrated in the
91    following code snippet in which a splash screen is displayed and
92    some initialization tasks are performed before the application's
93    main window is shown:
94 
95    \snippet doc/src/snippets/qsplashscreen/main.cpp 0
96    \dots
97    \snippet doc/src/snippets/qsplashscreen/main.cpp 1
98 
99    The user can hide the splash screen by clicking on it with the
100    mouse. Since the splash screen is typically displayed before the
101    event loop has started running, it is necessary to periodically
102    call QApplication::processEvents() to receive the mouse clicks.
103 
104    It is sometimes useful to update the splash screen with messages,
105    for example, announcing connections established or modules loaded
106    as the application starts up:
107 
108    \snippet doc/src/snippets/code/src_gui_widgets_qsplashscreen.cpp 0
109 
110    QSplashScreen supports this with the showMessage() function. If you
111    wish to do your own drawing you can get a pointer to the pixmap
112    used in the splash screen with pixmap().  Alternatively, you can
113    subclass QSplashScreen and reimplement drawContents().
114 */
115 
116 /*!
117     Construct a splash screen that will display the \a pixmap.
118 
119     There should be no need to set the widget flags, \a f, except
120     perhaps Qt::WindowStaysOnTopHint.
121 */
QSplashScreen(const QPixmap & pixmap,Qt::WindowFlags f)122 QSplashScreen::QSplashScreen(const QPixmap &pixmap, Qt::WindowFlags f)
123     : QWidget(*(new QSplashScreenPrivate()), 0, Qt::SplashScreen | Qt::FramelessWindowHint | f)
124 {
125     setPixmap(pixmap);  // Does an implicit repaint
126 }
127 
128 /*!
129     \overload
130 
131     This function allows you to specify a parent for your splashscreen. The
132     typical use for this constructor is if you have a multiple screens and
133     prefer to have the splash screen on a different screen than your primary
134     one. In that case pass the proper desktop() as the \a parent.
135 */
QSplashScreen(QWidget * parent,const QPixmap & pixmap,Qt::WindowFlags f)136 QSplashScreen::QSplashScreen(QWidget *parent, const QPixmap &pixmap, Qt::WindowFlags f)
137     : QWidget(*new QSplashScreenPrivate, parent, Qt::SplashScreen | f)
138 {
139     d_func()->pixmap = pixmap;
140     setPixmap(d_func()->pixmap);  // Does an implicit repaint
141 }
142 
143 /*!
144   Destructor.
145 */
~QSplashScreen()146 QSplashScreen::~QSplashScreen()
147 {
148 }
149 
150 /*!
151     \reimp
152 */
mousePressEvent(QMouseEvent *)153 void QSplashScreen::mousePressEvent(QMouseEvent *)
154 {
155     hide();
156 }
157 
158 /*!
159     This overrides QWidget::repaint(). It differs from the standard
160     repaint function in that it also calls QApplication::flush() to
161     ensure the updates are displayed, even when there is no event loop
162     present.
163 */
repaint()164 void QSplashScreen::repaint()
165 {
166     QWidget::repaint();
167     QApplication::flush();
168 }
169 
170 /*!
171     \fn QSplashScreen::messageChanged(const QString &message)
172 
173     This signal is emitted when the message on the splash screen
174     changes. \a message is the new message and is a null-string
175     when the message has been removed.
176 
177     \sa showMessage(), clearMessage()
178 */
179 
180 
181 
182 /*!
183     Draws the \a message text onto the splash screen with color \a
184     color and aligns the text according to the flags in \a alignment.
185 
186     To make sure the splash screen is repainted immediately, you can
187     call \l{QCoreApplication}'s
188     \l{QCoreApplication::}{processEvents()} after the call to
189     showMessage(). You usually want this to make sure that the message
190     is kept up to date with what your application is doing (e.g.,
191     loading files).
192 
193     \sa Qt::Alignment, clearMessage()
194 */
showMessage(const QString & message,int alignment,const QColor & color)195 void QSplashScreen::showMessage(const QString &message, int alignment,
196                                 const QColor &color)
197 {
198     Q_D(QSplashScreen);
199     d->currStatus = message;
200     d->currAlign = alignment;
201     d->currColor = color;
202     emit messageChanged(d->currStatus);
203     repaint();
204 }
205 
206 /*!
207     Removes the message being displayed on the splash screen
208 
209     \sa showMessage()
210  */
clearMessage()211 void QSplashScreen::clearMessage()
212 {
213     d_func()->currStatus.clear();
214     emit messageChanged(d_func()->currStatus);
215     repaint();
216 }
217 
218 /*!
219     Makes the splash screen wait until the widget \a mainWin is displayed
220     before calling close() on itself.
221 */
finish(QWidget * mainWin)222 void QSplashScreen::finish(QWidget *mainWin)
223 {
224     if (mainWin) {
225 #if defined(Q_WS_X11)
226         extern void qt_x11_wait_for_window_manager(QWidget *mainWin, bool);
227         qt_x11_wait_for_window_manager(mainWin, false);
228 #endif
229     }
230     close();
231 }
232 
233 /*!
234     Sets the pixmap that will be used as the splash screen's image to
235     \a pixmap.
236 */
setPixmap(const QPixmap & pixmap)237 void QSplashScreen::setPixmap(const QPixmap &pixmap)
238 {
239     Q_D(QSplashScreen);
240 
241     d->pixmap = pixmap;
242     setAttribute(Qt::WA_TranslucentBackground, pixmap.hasAlpha());
243 
244     QRect r(QPoint(), d->pixmap.size());
245     resize(r.size());
246     move(QApplication::desktop()->screenGeometry().center() - r.center());
247     if (isVisible())
248         repaint();
249 }
250 
251 /*!
252     Returns the pixmap that is used in the splash screen. The image
253     does not have any of the text drawn by showMessage() calls.
254 */
pixmap() const255 const QPixmap QSplashScreen::pixmap() const
256 {
257     return d_func()->pixmap;
258 }
259 
260 /*!
261     \internal
262 */
QSplashScreenPrivate()263 inline QSplashScreenPrivate::QSplashScreenPrivate() : currAlign(Qt::AlignLeft)
264 {
265 }
266 
267 /*!
268     Draw the contents of the splash screen using painter \a painter.
269     The default implementation draws the message passed by showMessage().
270     Reimplement this function if you want to do your own drawing on
271     the splash screen.
272 */
drawContents(QPainter * painter)273 void QSplashScreen::drawContents(QPainter *painter)
274 {
275     Q_D(QSplashScreen);
276     painter->setPen(d->currColor);
277     QRect r = rect().adjusted(5, 5, -5, -5);
278     if (Qt::mightBeRichText(d->currStatus)) {
279         QTextDocument doc;
280 #ifdef QT_NO_TEXTHTMLPARSER
281         doc.setPlainText(d->currStatus);
282 #else
283         doc.setHtml(d->currStatus);
284 #endif
285         doc.setTextWidth(r.width());
286         QTextCursor cursor(&doc);
287         cursor.select(QTextCursor::Document);
288         QTextBlockFormat fmt;
289         fmt.setAlignment(Qt::Alignment(d->currAlign));
290         cursor.mergeBlockFormat(fmt);
291         painter->save();
292         painter->translate(r.topLeft());
293         doc.drawContents(painter);
294         painter->restore();
295     } else {
296         painter->drawText(r, d->currAlign, d->currStatus);
297     }
298 }
299 
300 /*!
301     \fn void QSplashScreen::message(const QString &message, int alignment,
302                                     const QColor &color)
303     \compat
304 
305     Use showMessage() instead.
306 */
307 
308 /*!
309     \fn void QSplashScreen::clear()
310     \compat
311 
312     Use clearMessage() instead.
313 */
314 
315 /*! \reimp */
event(QEvent * e)316 bool QSplashScreen::event(QEvent *e)
317 {
318     if (e->type() == QEvent::Paint) {
319         Q_D(QSplashScreen);
320         QPainter painter(this);
321         if (!d->pixmap.isNull())
322             painter.drawPixmap(QPoint(), d->pixmap);
323         drawContents(&painter);
324     }
325     return QWidget::event(e);
326 }
327 
328 QT_END_NAMESPACE
329 
330 #endif //QT_NO_SPLASHSCREEN
331