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 "qdirectpainter_qws.h"
43 
44 #include "qscreen_qws.h"
45 #include "private/qobject_p.h"
46 #include "private/qapplication_p.h"
47 #include "qwsdisplay_qws.h"
48 #include "qwidget.h"
49 #include "qimage.h"
50 #include <qwsevent_qws.h>
51 #include <private/qwindowsurface_qws_p.h>
52 #include <private/qwsdisplay_qws_p.h>
53 
54 QT_BEGIN_NAMESPACE
55 
56 #ifdef Q_WS_QWS
57 #ifndef QT_NO_DIRECTPAINTER
58 
59 /*!
60     \class QDirectPainter
61     \ingroup painting
62     \ingroup qws
63 
64     \brief The QDirectPainter class provides direct access to the
65     underlying hardware in Qt for Embedded Linux.
66 
67     Note that this class is only available in \l{Qt for Embedded Linux}.
68 
69     QDirectPainter allows a client application to reserve a region of
70     the framebuffer and render directly onto the screen. There are two
71     ways of using the QDirectPainter class: You can either reserve a
72     region using the provided static functions, or you can instantiate
73     an object and make use of its more dynamic API.
74 
75     \tableofcontents
76 
77     \section1 Dynamic Allocation
78 
79     By instantiating a QDirectPainter object using the default
80     QDirectPainter::NonReserved surface flag, the client application
81     only gets some control over the reserved region, i.e., it can
82     still render directly onto the screen but the allocated region may
83     change (for example, if a window with a higher focus requests
84     parts of the same region). The currently allocated region can be
85     retrieved using the allocatedRegion() function, while the
86     requestedRegion() function returns the originally reserved
87     region.
88 
89 
90     \section1 Static Allocation
91 
92 
93     Using the static approach, the client application gets complete
94     control over the reserved region, i.e., the affected region will
95     never be modified by the screen driver.
96 
97     To create a static region, pass the QDirectPainter::Reserved
98     surface flag to the constructor. After the reserved region is
99     reported through regionChanged(), the allocated region will not
100     change, unless setRegion() is called.
101 
102     If QDirectPainter::ReservedSynchronous is passed to the
103     constructor, calls to setRegion() will block until the region is
104     reserved, meaning that allocatedRegion() will be available immediately.
105     Note that in the current version setRegion() will cause the application
106     event loop to be entered, potentially causing reentrancy issues.
107 
108     \section1 Rendering
109 
110     To draw on a given region, the application must first get hold of
111     a pointer to the framebuffer. In most cases, this pointer can be
112     retrieved using the QDirectPainter::frameBuffer() function. But
113     note that if the current screen has subscreens, you must query the
114     screen driver instead to identify the correct subscreen. A pointer
115     to the current screen driver can always be retrieved using the
116     static QScreen::instance() function. Then use QScreen's \l
117     {QScreen::}{subScreenIndexAt()} and \l {QScreen::}{subScreens()}
118     functions to access the correct subscreen, and the subscreen's \l
119     {QScreen::}{base()} function to retrieve a pointer to the
120     framebuffer.
121 
122     Depending on the hardware, it might be necessary to lock the
123     framebuffer for exclusive use while writing to it. This is
124     possible using the lock() and unlock() functions. Note that
125     calling lock() will prevent all other applications from working
126     until unlock() is called.
127 
128     In addition, QDirectPainter provides several functions returning
129     information about the framebuffer: the linestep() function returns
130     the length (in bytes) of each scanline of the framebuffer while
131     the screenDepth(), screenWidth() and screenHeight() function
132     return the screen metrics.
133 
134     \sa QScreen, QWSEmbedWidget, {Qt for Embedded Linux Architecture}
135 */
136 
137 /*!
138     \enum QDirectPainter::SurfaceFlag
139 
140     This enum describes the behavior of the region reserved by this
141     QDirectPainter object.
142 
143     \value NonReserved The allocated region may change, e.g., if a
144     window with a higher focus requests parts of the same region. See
145     also \l {Dynamic Allocation}.
146 
147     \value Reserved The allocated region will never change. See also
148     \l {Static Allocation}.
149 
150     \value ReservedSynchronous The allocated region will never change and
151     each function that changes the allocated region will be blocking.
152 
153     \sa allocatedRegion()
154 */
155 
156 /*!
157     \fn QRegion QDirectPainter::region()
158     \obsolete
159 
160     Use QDirectPainter::allocatedRegion() instead.
161 */
162 
getPrimaryScreen()163 static inline QScreen *getPrimaryScreen()
164 {
165     QScreen *screen = QScreen::instance();
166     if (!screen->base()) {
167         QList<QScreen*> subScreens = screen->subScreens();
168         if (subScreens.size() < 1)
169             return 0;
170         screen = subScreens.at(0);
171     }
172     return screen;
173 }
174 
screenS()175 static inline QSize screenS()
176 {
177     QScreen *screen = getPrimaryScreen();
178     if (!screen)
179         return QSize();
180     return QSize(screen->width(), screen->height());
181 }
182 
devS()183 static inline QSize devS()
184 {
185     QScreen *screen = getPrimaryScreen();
186     if (!screen)
187         return QSize();
188     return QSize(screen->deviceWidth(), screen->deviceHeight());
189 }
190 
191 
192 class QDirectPainterPrivate : public QObjectPrivate
193 {
194     Q_DECLARE_PUBLIC(QDirectPainter);
195 public:
196 
QDirectPainterPrivate()197     QDirectPainterPrivate() : surface(0), seenRegion(false) {}
198 
~QDirectPainterPrivate()199     ~QDirectPainterPrivate() {
200         if (QPaintDevice::qwsDisplay()) { // make sure not in QApplication destructor
201             qApp->d_func()->directPainters->remove(surface->windowId());
202             surface->setGeometry(QRect());
203         }
204         delete surface;
205     }
206 
207     QWSDirectPainterSurface *surface;
208     QRegion requested_region;
209 
210     static QDirectPainter *staticPainter;
211     bool seenRegion;
212 };
213 
214 QDirectPainter *QDirectPainterPrivate::staticPainter = 0;
215 
qt_directpainter_region(QDirectPainter * dp,const QRegion & alloc,int type)216 void qt_directpainter_region(QDirectPainter *dp, const QRegion &alloc, int type)
217 {
218     QDirectPainterPrivate *d = dp->d_func();
219 
220     QRegion r = alloc;
221     QScreen *screen = d->surface->screen();
222     if (screen->isTransformed()) {
223         const QSize screenSize(screen->width(), screen->height());
224         r = screen->mapToDevice(r, screenSize);
225     }
226     if (type == QWSRegionEvent::Allocation) {
227         d->surface->setClipRegion(alloc);
228         d->seenRegion = true;
229         if (dp != QDirectPainterPrivate::staticPainter) {
230             if (!d->surface->flushingRegionEvents) // recursion guard
231                 dp->regionChanged(r);
232         }
233     }
234 }
235 
236 #ifndef QT_NO_QWSEMBEDWIDGET
qt_directpainter_embedevent(QDirectPainter * dp,const QWSEmbedEvent * event)237 void qt_directpainter_embedevent(QDirectPainter *dp, const QWSEmbedEvent *event)
238 {
239     if (event->type | QWSEmbedEvent::Region) {
240         QScreen *screen = dp->d_func()->surface->screen();
241         QRegion r = event->region;
242         if (screen->isTransformed()) {
243             const QSize screenSize(screen->width(), screen->height());
244             r = screen->mapToDevice(r, screenSize);
245         }
246         dp->setRegion(r);
247     }
248 }
249 #endif
250 
251 /*!
252     Constructs a QDirectPainter object with the given \a parent and
253     surface \a flag.
254 */
QDirectPainter(QObject * parent,SurfaceFlag flag)255 QDirectPainter::QDirectPainter(QObject *parent, SurfaceFlag flag)
256     :QObject(*new QDirectPainterPrivate, parent)
257 {
258     Q_D(QDirectPainter);
259     d->surface = new QWSDirectPainterSurface(true, flag);
260 
261     if (flag != NonReserved)
262         d->surface->setReserved();
263 
264     QApplicationPrivate *ad = qApp->d_func();
265     if (!ad->directPainters)
266         ad->directPainters = new QMap<WId, QDirectPainter*>;
267     ad->directPainters->insert(d->surface->windowId(), this);
268 }
269 
270 /*!
271     Destroys this QDirectPainter object, releasing the reserved region.
272 
273     \sa allocatedRegion()
274 */
~QDirectPainter()275 QDirectPainter::~QDirectPainter()
276 {
277     /* should not be necessary
278     if (this == QDirectPainterPrivate::staticPainter)
279         QDirectPainterPrivate::staticPainter = 0;
280     */
281 }
282 
283 /*!
284     \fn void QDirectPainter::setGeometry(const QRect &rectangle)
285     \since 4.2
286 
287     Request to reserve the given \a rectangle of the framebuffer.
288 
289     Note that the actually allocated region might differ from the
290     requested one, e.g., if the given region overlaps with the
291     region of another QDirectPainter object.
292 
293     \sa geometry(), allocatedRegion(), setRegion()
294 */
setGeometry(const QRect & rect)295 void QDirectPainter::setGeometry(const QRect &rect)
296 {
297     setRegion(rect);
298 }
299 
300 /*!
301     \since 4.2
302 
303     Returns the bounding rectangle of the requested region.
304 
305     \sa setGeometry(), requestedRegion()
306 */
geometry() const307 QRect QDirectPainter::geometry() const
308 {
309     Q_D(const QDirectPainter);
310     return d->requested_region.boundingRect();
311 }
312 
313 /*!
314     \since 4.2
315 
316     Requests to reserve the given \a region of the framebuffer.
317 
318     Note that the actually allocated region might differ from the
319     requested one, e.g., if the given region overlaps with the region
320     of another QDirectPainter object.
321 
322     \sa requestedRegion(), allocatedRegion(), {Dynamic Allocation}
323 */
setRegion(const QRegion & region)324 void QDirectPainter::setRegion(const QRegion &region)
325 {
326     Q_D(QDirectPainter);
327     d->requested_region = region;
328 
329     const QScreen *screen = d->surface->screen();
330     if (screen->isTransformed()) {
331         const QSize devSize(screen->deviceWidth(), screen->deviceHeight());
332         const QRegion r = screen->mapFromDevice(region, devSize);
333         d->surface->setRegion(r);
334     } else {
335         d->surface->setRegion(region);
336     }
337 }
338 
339 /*!
340     \since 4.2
341 
342     Returns the region requested by this QDirectPainter.
343 
344     Note that if the QDirectPainter::Reserved flag is set, the region
345     returned by this function will always be equivalent to the region
346     returned by the allocatedRegion() function. Otherwise they might
347     differ (see \l {Dynamic Allocation} for details).
348 
349     \sa geometry(), setRegion(), allocatedRegion()
350 */
requestedRegion() const351 QRegion QDirectPainter::requestedRegion() const
352 {
353     Q_D(const QDirectPainter);
354     return d->requested_region;
355 }
356 
357 /*!
358     \since 4.2
359 
360     Returns the currently reserved region.
361 
362     Note that if the QDirectPainter::Reserved flag is set, the region
363     returned by this function will always be equivalent to the region
364     returned by the requestedRegion() function. Otherwise they might
365     differ (see \l {Dynamic Allocation} for details).
366 
367     \sa requestedRegion(), geometry()
368 */
allocatedRegion() const369 QRegion QDirectPainter::allocatedRegion() const
370 {
371     Q_D(const QDirectPainter);
372     const QScreen *screen = d->surface->screen();
373     if (screen->isTransformed()) {
374         const QSize screenSize(screen->width(), screen->height());
375         return screen->mapToDevice(d->surface->region(), screenSize);
376     } else {
377         return d->surface->region();
378     }
379 }
380 
381 /*!
382     \since 4.2
383 
384     Returns the window system identifier of the widget.
385 */
winId() const386 WId QDirectPainter::winId() const
387 {
388     Q_D(const QDirectPainter);
389     return d->surface->windowId();
390 }
391 
392 /*!
393     \fn void QDirectPainter::regionChanged(const QRegion &newRegion)
394     \since 4.2
395 
396     This function is called when the allocated region changes.
397 
398     This function is not called for region changes that happen while the
399     startPainting() function is executing.
400 
401     Note that the given region, \a newRegion, is not guaranteed to be correct at the
402     time you access the display. To prevent reentrancy problems you should
403     always call startPainting() before updating the display and then use
404     allocatedRegion() to retrieve the correct region.
405 
406     \sa allocatedRegion(), startPainting(), {Dynamic Allocation}
407 */
regionChanged(const QRegion & region)408 void QDirectPainter::regionChanged(const QRegion &region)
409 {
410     Q_UNUSED(region);
411 }
412 
413 /*!
414     \since 4.2
415 
416     Call this function before you start updating the pixels in the
417     allocated region. The hardware will be notified, if necessary,
418     that you are about to start painting operations.
419 
420     Set \a lockDisplay if you want startPainting() and endPainting()
421     to lock() and unlock() the display automatically.
422 
423     Note that for a NonReserved direct painter, you must call
424     allocatedRegion() after calling this function, since the allocated
425     region is only guaranteed to be correct after this function has
426     returned.
427 
428     The regionChanged() function will not be called between startPainting()
429     and endPainting().
430 
431     \sa endPainting(), flush()
432 */
startPainting(bool lockDisplay)433 void QDirectPainter::startPainting(bool lockDisplay)
434 {
435     Q_D(QDirectPainter);
436     d->surface->setLocking(lockDisplay);
437 
438     const QScreen *screen = d->surface->screen();
439     if (screen->isTransformed()) {
440         const QSize devSize(screen->deviceWidth(), screen->deviceHeight());
441         const QRegion r = screen->mapFromDevice(d->surface->region(), devSize);
442         d->surface->beginPaint(r);
443     } else {
444         d->surface->beginPaint(d->surface->region());
445     }
446 }
447 
448 /*!
449     \since 4.2
450 
451     Call this function when you are done updating the screen. It will
452     notify the hardware, if necessary, that your painting operations
453     have ended.
454 */
endPainting()455 void QDirectPainter::endPainting()
456 {
457     Q_D(QDirectPainter);
458 
459     const QScreen *screen = d->surface->screen();
460     if (screen->isTransformed()) {
461         const QSize devSize(screen->deviceWidth(), screen->deviceHeight());
462         const QRegion r = screen->mapFromDevice(d->surface->region(), devSize);
463         d->surface->endPaint(r);
464     } else {
465         d->surface->endPaint(d->surface->region());
466     }
467 }
468 
469 /*!
470     \since 4.3
471     \overload
472 
473     This function will automatically call flush() to flush the
474     \a region to the display before notifying the hardware, if
475     necessary, that painting operations have ended.
476 */
endPainting(const QRegion & region)477 void QDirectPainter::endPainting(const QRegion &region)
478 {
479     endPainting();
480     flush(region);
481 }
482 
483 /*!
484     \since 4.3
485 
486     Flushes the \a region onto the screen.
487 */
flush(const QRegion & region)488 void QDirectPainter::flush(const QRegion &region)
489 {
490     Q_D(QDirectPainter);
491 
492     const QScreen *screen = d->surface->screen();
493     if (screen->isTransformed()) {
494         const QSize devSize(screen->deviceWidth(), screen->deviceHeight());
495         const QRegion r = screen->mapFromDevice(region, devSize);
496         d->surface->flush(0, r, QPoint());
497     } else {
498         d->surface->flush(0, region, QPoint());
499     }
500 }
501 
502 /*!
503     \since 4.2
504 
505     Raises the reserved region to the top of the widget stack.
506 
507     After this call the reserved region will be visually in front of
508     any overlapping widgets.
509 
510     \sa lower(), requestedRegion()
511 */
raise()512 void QDirectPainter::raise()
513 {
514     QWidget::qwsDisplay()->setAltitude(winId(),QWSChangeAltitudeCommand::Raise);
515 }
516 
517 /*!
518     \since 4.2
519 
520     Lowers the reserved region to the bottom of the widget stack.
521 
522     After this call the reserved region will be visually behind (and
523     therefore obscured by) any overlapping widgets.
524 
525     \sa raise(), requestedRegion()
526 */
lower()527 void QDirectPainter::lower()
528 {
529     QWidget::qwsDisplay()->setAltitude(winId(),QWSChangeAltitudeCommand::Lower);
530 }
531 
532 
533 /*!
534     \fn QRegion QDirectPainter::reserveRegion(const QRegion &region)
535 
536     Attempts to reserve the \a region and returns the region that is
537     actually reserved.
538 
539     This function also releases the previously reserved region if
540     any. If not released explicitly, the region will be released on
541     application exit.
542 
543     \sa allocatedRegion(), {Static Allocation}
544 
545     \obsolete
546 
547     Construct a QDirectPainter using QDirectPainter::ReservedSynchronous instead.
548 */
reserveRegion(const QRegion & reg)549 QRegion QDirectPainter::reserveRegion(const QRegion &reg)
550 {
551     if (!QDirectPainterPrivate::staticPainter)
552         QDirectPainterPrivate::staticPainter = new QDirectPainter(qApp, ReservedSynchronous);
553 
554     QDirectPainter *dp = QDirectPainterPrivate::staticPainter;
555     dp->setRegion(reg);
556 
557     return dp->allocatedRegion();
558 }
559 
560 /*!
561     Returns a pointer to the beginning of the display memory.
562 
563     Note that it is the application's responsibility to limit itself
564     to modifying only the reserved region.
565 
566     Do not use this pointer if the current screen has subscreens,
567     query the screen driver instead: A pointer to the current screen
568     driver can always be retrieved using the static
569     QScreen::instance() function. Then use QScreen's \l
570     {QScreen::}{subScreenIndexAt()} and \l {QScreen::}{subScreens()}
571     functions to access the correct subscreen, and the subscreen's \l
572     {QScreen::}{base()} function to retrieve a pointer to the
573     framebuffer.
574 
575     \sa requestedRegion(), allocatedRegion(), linestep()
576 */
frameBuffer()577 uchar* QDirectPainter::frameBuffer()
578 {
579     QScreen *screen = getPrimaryScreen();
580     if (!screen)
581         return 0;
582     return screen->base();
583 }
584 
585 /*!
586     \since 4.2
587 
588     Returns the reserved region.
589 
590     \sa reserveRegion(), frameBuffer()
591 
592     \obsolete
593 
594     Use allocatedRegion() instead.
595 */
reservedRegion()596 QRegion QDirectPainter::reservedRegion()
597 {
598     return QDirectPainterPrivate::staticPainter
599         ? QDirectPainterPrivate::staticPainter->allocatedRegion() : QRegion();
600 }
601 
602 /*!
603     Returns the bit depth of the display.
604 
605     \sa screenHeight(), screenWidth()
606 */
screenDepth()607 int QDirectPainter::screenDepth()
608 {
609     QScreen *screen = getPrimaryScreen();
610     if (!screen)
611         return 0;
612     return screen->depth();
613 }
614 
615 /*!
616     Returns the width of the display in pixels.
617 
618     \sa screenHeight(), screenDepth()
619 */
screenWidth()620 int QDirectPainter::screenWidth()
621 {
622     QScreen *screen = getPrimaryScreen();
623     if (!screen)
624         return 0;
625     return screen->deviceWidth();
626 }
627 
628 /*!
629     Returns the height of the display in pixels.
630 
631     \sa screenWidth(), screenDepth()
632 */
screenHeight()633 int QDirectPainter::screenHeight()
634 {
635     QScreen *screen = getPrimaryScreen();
636     if (!screen)
637         return 0;
638     return screen->deviceHeight();
639 }
640 
641 /*!
642     Returns the length (in bytes) of each scanline of the framebuffer.
643 
644     \sa frameBuffer()
645 */
linestep()646 int QDirectPainter::linestep()
647 {
648     QScreen *screen = getPrimaryScreen();
649     if (!screen)
650         return 0;
651     return screen->linestep();
652 }
653 
654 
655 /*!
656   Locks access to the framebuffer.
657 
658   Note that calling this function will prevent all other
659   applications from updating the display until unlock() is called.
660 
661   \sa unlock()
662 */
lock()663 void QDirectPainter::lock()
664 {
665     QWSDisplay::grab(true);
666 }
667 /*!
668   Unlocks the lock on the framebuffer (set using the lock()
669   function), allowing other applications to access the screen.
670 
671   \sa lock()
672  */
unlock()673 void QDirectPainter::unlock()
674 {
675     QWSDisplay::ungrab();
676 }
677 
678 #endif //QT_NO_DIRECTPAINTER
679 
680 #endif
681 
682 QT_END_NAMESPACE
683