source: trunk/src/gui/painting/qwindowsurface_qws.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 38.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qwindowsurface_qws_p.h"
43#include <qwidget.h>
44#include <qscreen_qws.h>
45#include <qwsmanager_qws.h>
46#include <qapplication.h>
47#include <qwsdisplay_qws.h>
48#include <qrgb.h>
49#include <qpaintengine.h>
50#include <qdesktopwidget.h>
51#include <private/qapplication_p.h>
52#include <private/qwsdisplay_qws_p.h>
53#include <private/qwidget_p.h>
54#include <private/qwsmanager_p.h>
55#include <private/qwslock_p.h>
56#include <private/qbackingstore_p.h>
57#include <stdio.h>
58
59QT_BEGIN_NAMESPACE
60
61#ifdef Q_BACKINGSTORE_SUBSURFACES
62
63typedef QMap<int, QWSWindowSurface*> SurfaceMap;
64Q_GLOBAL_STATIC(SurfaceMap, winIdToSurfaceMap);
65
66QWSWindowSurface* qt_findWindowSurface(int winId)
67{
68 return winIdToSurfaceMap()->value(winId);
69}
70
71static void qt_insertWindowSurface(int winId, QWSWindowSurface *surface)
72{
73 if (!surface)
74 winIdToSurfaceMap()->remove(winId);
75 else
76 winIdToSurfaceMap()->insert(winId, surface);
77}
78
79#endif // Q_BACKINGSTORE_SUBSURFACES
80
81inline bool isWidgetOpaque(const QWidget *w)
82{
83 return w->d_func()->isOpaque && !w->testAttribute(Qt::WA_TranslucentBackground);
84}
85
86static inline QScreen *getScreen(const QWidget *w)
87{
88 const QList<QScreen*> subScreens = qt_screen->subScreens();
89 if (subScreens.isEmpty())
90 return qt_screen;
91
92 const int screen = QApplication::desktop()->screenNumber(w);
93
94 return qt_screen->subScreens().at(screen < 0 ? 0 : screen);
95}
96
97static int bytesPerPixel(QImage::Format format)
98{
99 switch (format) {
100 case QImage::Format_Invalid:
101 return 0;
102#ifndef QT_NO_DEBUG
103 case QImage::Format_Mono:
104 case QImage::Format_MonoLSB:
105 qFatal("QWSWindowSurface: Invalid backingstore format: %i",
106 int(format));
107#endif
108 case QImage::Format_Indexed8:
109 return 1;
110 case QImage::Format_RGB32:
111 case QImage::Format_ARGB32:
112 case QImage::Format_ARGB32_Premultiplied:
113 return 4;
114 case QImage::Format_RGB16:
115 case QImage::Format_RGB555:
116 case QImage::Format_RGB444:
117 case QImage::Format_ARGB4444_Premultiplied:
118 return 2;
119 case QImage::Format_ARGB8565_Premultiplied:
120 case QImage::Format_ARGB8555_Premultiplied:
121 case QImage::Format_ARGB6666_Premultiplied:
122 case QImage::Format_RGB666:
123 case QImage::Format_RGB888:
124 return 3;
125 default:
126#ifndef QT_NO_DEBUG
127 qFatal("QWSWindowSurface: Invalid backingstore format: %i",
128 int(format));
129#endif
130 return 0;
131 }
132}
133
134static inline int nextMulOf4(int n)
135{
136 return ((n + 3) & 0xfffffffc);
137}
138
139static inline void setImageMetrics(QImage &img, QWidget *window) {
140 QScreen *myScreen = getScreen(window);
141 if (myScreen) {
142 int dpmx = myScreen->width()*1000 / myScreen->physicalWidth();
143 int dpmy = myScreen->height()*1000 / myScreen->physicalHeight();
144 img.setDotsPerMeterX(dpmx);
145 img.setDotsPerMeterY(dpmy);
146 }
147}
148
149void QWSWindowSurface::invalidateBuffer()
150{
151
152 QWidget *win = window();
153 if (win) {
154 win->d_func()->invalidateBuffer(win->rect());
155#ifndef QT_NO_QWS_MANAGER
156 QTLWExtra *topextra = win->d_func()->extra->topextra;
157 QWSManager *manager = topextra->qwsManager;
158 if (manager)
159 manager->d_func()->dirtyRegion(QDecoration::All,
160 QDecoration::Normal);
161#endif
162 }
163}
164
165QWSWindowSurfacePrivate::QWSWindowSurfacePrivate()
166 : flags(0),
167#ifdef QT_QWS_CLIENTBLIT
168 directId(-1),
169#endif
170 winId(0)
171{
172}
173
174void QWSWindowSurfacePrivate::setWinId(int id)
175{
176 winId = id;
177}
178
179int QWSWindowSurface::winId() const
180{
181 // XXX: the widget winId may change during the lifetime of the widget!!!
182
183 const QWidget *win = window();
184 if (win && win->isWindow())
185 return win->internalWinId();
186
187#ifdef Q_BACKINGSTORE_SUBSURFACES
188 if (!d_ptr->winId) {
189 QWSWindowSurface *that = const_cast<QWSWindowSurface*>(this);
190 QWSDisplay *display = QWSDisplay::instance();
191 const int id = display->takeId();
192 qt_insertWindowSurface(id, that);
193 that->d_ptr->winId = id;
194
195 if (win)
196 display->nameRegion(id, win->objectName(), win->windowTitle());
197 else
198 display->nameRegion(id, QString(), QString());
199
200 display->setAltitude(id, 1, true); // XXX
201 }
202#endif
203
204 return d_ptr->winId;
205}
206
207void QWSWindowSurface::setWinId(int id)
208{
209 d_ptr->winId = id;
210}
211
212/*!
213 \class QWSWindowSurface
214 \since 4.2
215 \ingroup qws
216 \preliminary
217 \internal
218
219 \brief The QWSWindowSurface class provides the drawing area for top-level
220 windows in Qt for Embedded Linux.
221
222 Note that this class is only available in Qt for Embedded Linux.
223
224 In \l{Qt for Embedded Linux}, the default behavior is for each client to
225 render its widgets into memory while the server is responsible for
226 putting the contents of the memory onto the
227 screen. QWSWindowSurface is used by the window system to implement
228 the associated memory allocation.
229
230 When a screen update is required, the server runs through all the
231 top-level windows that intersect with the region that is about to
232 be updated, and ensures that the associated clients have updated
233 their memory buffer. Then the server uses the screen driver to
234 copy the content of the memory to the screen. To locate the
235 relevant parts of memory, the driver is provided with the list of
236 top-level windows that intersect with the given region. Associated
237 with each of the top-level windows there is a window surface
238 representing the drawing area of the window.
239
240 When deriving from the QWSWindowSurface class, e.g., when adding
241 an \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
242 {accelerated graphics driver}, there are several pure virtual
243 functions that must be implemented. In addition, QWSWindowSurface
244 provides several virtual functions that can be reimplemented to
245 customize the drawing process.
246
247 \tableofcontents
248
249 \section1 Pure Virtual Functions
250
251 There are in fact two window surface instances for each top-level
252 window; one used by the application when drawing a window, and
253 another used by the server application to perform window
254 compositioning. Implement the attach() to create the server-side
255 representation of the surface. The data() function must be
256 implemented to provide the required data.
257
258 Implement the key() function to uniquely identify the surface
259 class, and the isValid() function to determine is a surface
260 corresponds to a given widget.
261
262 The geometry() function must be implemented to let the window
263 system determine the area required by the window surface
264 (QWSWindowSurface also provides a corresponding virtual
265 setGeometry() function that is called whenever the area necessary
266 for the top-level window to be drawn, changes). The image()
267 function is called by the window system during window
268 compositioning, and must be implemented to return an image of the
269 top-level window.
270
271 Finally, the paintDevice() function must be implemented to return
272 the appropriate paint device, and the scroll() function must be
273 implemented to scroll the given region of the surface the given
274 number of pixels.
275
276 \section1 Virtual Functions
277
278 When painting onto the surface, the window system will always call
279 the beginPaint() function before any painting operations are
280 performed. Likewise the endPaint() function is automatically
281 called when the painting is done. Reimplement the painterOffset()
282 function to alter the offset that is applied when drawing.
283
284 The window system uses the flush() function to put a given region
285 of the widget onto the screen, and the release() function to
286 deallocate the screen region corresponding to this window surface.
287
288 \section1 Other Members
289
290 QWSWindowSurface provides the window() function returning a
291 pointer to the top-level window the surface is representing. The
292 currently visible region of the associated widget can be retrieved
293 and set using the clipRegion() and setClipRegion() functions,
294 respectively.
295
296 When the window system performs the window compositioning, it uses
297 the SurfaceFlag enum describing the surface content. The currently
298 set surface flags can be retrieved and altered using the
299 surfaceFlags() and setSurfaceFlags() functions. In addition,
300 QWSWindowSurface provides the isBuffered(), isOpaque() and
301 isRegionReserved() convenience functions.
302
303 \sa {Qt for Embedded Linux Architecture#Drawing on Screen}{Qt for
304 Embedded Linux Architecture}
305*/
306
307/*!
308 \enum QWSWindowSurface::SurfaceFlag
309
310 This enum is used to describe the window surface's contents. It
311 is used by the screen driver to handle region allocation and
312 composition.
313
314 \value RegionReserved The surface contains a reserved area. Once
315 allocated, a reserved area can not not be changed by the window
316 system, i.e., no other widgets can be drawn on top of this.
317
318 \value Buffered
319 The surface is in a memory area which is not part of a framebuffer.
320 (A top-level window with QWidget::windowOpacity() other than 1.0 must use
321 a buffered surface in order to making blending with the background work.)
322
323 \value Opaque
324 The surface contains only opaque pixels.
325
326 \sa surfaceFlags(), setSurfaceFlags()
327*/
328
329/*!
330 \fn bool QWSWindowSurface::isValid() const
331 \since 4.3
332
333 Implement this function to return true if the surface is a valid
334 surface for the given top-level \a window; otherwise return
335 false.
336
337 \sa window(), key()
338*/
339
340/*!
341 \fn QString QWSWindowSurface::key() const
342
343 Implement this function to return a string that uniquely
344 identifies the class of this surface.
345
346 \sa window(), isValid()
347*/
348
349/*!
350 \fn QByteArray QWSWindowSurface::permanentState() const
351 \since 4.3
352
353 Implement this function to return the data required for creating a
354 server-side representation of the surface.
355
356 \sa attach()
357*/
358
359/*!
360 \fn void QWSWindowSurface::setPermanentState(const QByteArray &data)
361 \since 4.3
362
363 Implement this function to attach a server-side surface instance
364 to the corresponding client side instance using the given \a
365 data. Return true if successful; otherwise return false.
366
367 \sa data()
368*/
369
370/*!
371 \fn const QImage QWSWindowSurface::image() const
372
373 Implement this function to return an image of the top-level window.
374
375 \sa geometry()
376*/
377
378/*!
379 \fn bool QWSWindowSurface::isRegionReserved() const
380
381 Returns true if the QWSWindowSurface::RegionReserved is set; otherwise
382 returns false.
383
384 \sa surfaceFlags()
385*/
386
387/*!
388 \fn bool QWSWindowSurface::isBuffered() const
389
390 Returns true if the QWSWindowSurface::Buffered is set; otherwise returns false.
391
392 \sa surfaceFlags()
393*/
394
395/*!
396 \fn bool QWSWindowSurface::isOpaque() const
397
398 Returns true if the QWSWindowSurface::Opaque is set; otherwise
399 returns false.
400
401 \sa surfaceFlags()
402*/
403
404
405/*!
406 Constructs an empty surface.
407*/
408QWSWindowSurface::QWSWindowSurface()
409 : QWindowSurface(0), d_ptr(new QWSWindowSurfacePrivate)
410{
411}
412
413/*!
414 Constructs an empty surface for the given top-level \a widget.
415*/
416QWSWindowSurface::QWSWindowSurface(QWidget *widget)
417 : QWindowSurface(widget), d_ptr(new QWSWindowSurfacePrivate)
418{
419}
420
421QWSWindowSurface::~QWSWindowSurface()
422{
423#ifdef Q_BACKINGSTORE_SUBSURFACES
424 if (d_ptr->winId)
425 winIdToSurfaceMap()->remove(d_ptr->winId);
426#endif
427
428 delete d_ptr;
429}
430
431/*!
432 Returns the offset to be used when painting.
433
434 \sa paintDevice()
435*/
436QPoint QWSWindowSurface::painterOffset() const
437{
438 const QWidget *w = window();
439 if (!w)
440 return QPoint();
441 return w->geometry().topLeft() - w->frameGeometry().topLeft();
442}
443
444void QWSWindowSurface::beginPaint(const QRegion &)
445{
446 lock();
447}
448
449void QWSWindowSurface::endPaint(const QRegion &)
450{
451 unlock();
452}
453
454// XXX: documentation!!!
455QByteArray QWSWindowSurface::transientState() const
456{
457 return QByteArray();
458}
459
460QByteArray QWSWindowSurface::permanentState() const
461{
462 return QByteArray();
463}
464
465void QWSWindowSurface::setTransientState(const QByteArray &state)
466{
467 Q_UNUSED(state);
468}
469
470void QWSWindowSurface::setPermanentState(const QByteArray &state)
471{
472 Q_UNUSED(state);
473}
474
475bool QWSWindowSurface::lock(int timeout)
476{
477 Q_UNUSED(timeout);
478 return true;
479}
480
481void QWSWindowSurface::unlock()
482{
483}
484
485#ifdef QT_QWS_CLIENTBLIT
486/*! \internal */
487const QRegion QWSWindowSurface::directRegion() const
488{
489 return d_ptr->direct;
490}
491
492/*! \internal */
493int QWSWindowSurface::directRegionId() const
494{
495 return d_ptr->directId;
496}
497
498/*! \internal */
499void QWSWindowSurface::setDirectRegion(const QRegion &r, int id)
500{
501 d_ptr->direct = r;
502 d_ptr->directId = id;
503}
504#endif
505
506/*!
507 Returns the region currently visible on the screen.
508
509 \sa setClipRegion()
510*/
511const QRegion QWSWindowSurface::clipRegion() const
512{
513 return d_ptr->clip;
514}
515
516/*!
517 Sets the region currently visible on the screen to be the given \a
518 clip region.
519
520 \sa clipRegion()
521*/
522void QWSWindowSurface::setClipRegion(const QRegion &clip)
523{
524 if (clip == d_ptr->clip)
525 return;
526
527 QRegion expose = (clip - d_ptr->clip);
528 d_ptr->clip = clip;
529
530 if (expose.isEmpty() || clip.isEmpty())
531 return; // No repaint or flush required.
532
533 QWidget *win = window();
534 if (!win)
535 return;
536
537 if (isBuffered()) {
538 // No repaint required. Flush exposed area via the backing store.
539 win->d_func()->syncBackingStore(expose);
540 return;
541 }
542
543#ifndef QT_NO_QWS_MANAGER
544 // Invalidate exposed decoration area.
545 if (win && win->isWindow()) {
546 QTLWExtra *topextra = win->d_func()->extra->topextra;
547 if (QWSManager *manager = topextra->qwsManager) {
548 QRegion decorationExpose(manager->region());
549 decorationExpose.translate(-win->geometry().topLeft());
550 decorationExpose &= expose;
551 if (!decorationExpose.isEmpty()) {
552 expose -= decorationExpose;
553 manager->d_func()->dirtyRegion(QDecoration::All, QDecoration::Normal, decorationExpose);
554 }
555 }
556 }
557#endif
558
559 // Invalidate exposed widget area.
560 win->d_func()->invalidateBuffer(expose);
561}
562
563/*!
564 Returns the surface flags describing the contents of this surface.
565
566 \sa isBuffered(), isOpaque(), isRegionReserved()
567*/
568QWSWindowSurface::SurfaceFlags QWSWindowSurface::surfaceFlags() const
569{
570 return d_ptr->flags;
571}
572
573/*!
574 Sets the surface flags describing the contents of this surface, to
575 be the given \a flags.
576
577 \sa surfaceFlags()
578*/
579void QWSWindowSurface::setSurfaceFlags(SurfaceFlags flags)
580{
581 d_ptr->flags = flags;
582}
583
584void QWSWindowSurface::setGeometry(const QRect &rect)
585{
586 QRegion mask = rect;
587
588 const QWidget *win = window();
589 if (win) {
590#ifndef QT_NO_QWS_MANAGER
591 if (win->isWindow()) {
592 QTLWExtra *topextra = win->d_func()->extra->topextra;
593 QWSManager *manager = topextra->qwsManager;
594
595 if (manager) {
596 // The frame geometry is the bounding rect of manager->region,
597 // which could be too much, so we need to clip.
598 mask &= (manager->region() + win->geometry());
599 }
600 }
601#endif
602
603 const QRegion winMask = win->mask();
604 if (!winMask.isEmpty())
605 mask &= winMask.translated(win->geometry().topLeft());
606 }
607
608 setGeometry(rect, mask);
609}
610
611void QWSWindowSurface::setGeometry(const QRect &rect, const QRegion &mask)
612{
613 if (rect == geometry()) // XXX: && mask == prevMask
614 return;
615
616 const bool isResize = rect.size() != geometry().size();
617 const bool needsRepaint = isResize || !isBuffered();
618
619 QWindowSurface::setGeometry(rect);
620
621 const QRegion region = mask & rect;
622 QWidget *win = window();
623 // Only request regions for widgets visible on the screen.
624 // (Added the !win check for compatibility reasons, because
625 // there was no "if (win)" check before).
626 const bool requestQWSRegion = !win || !win->testAttribute(Qt::WA_DontShowOnScreen);
627 if (requestQWSRegion)
628 QWidget::qwsDisplay()->requestRegion(winId(), key(), permanentState(), region);
629
630 if (needsRepaint)
631 invalidateBuffer();
632
633 if (!requestQWSRegion) {
634 // We didn't request a region, hence we won't get a QWSRegionEvent::Allocation
635 // event back from the server so we set the clip directly. We have to
636 // do this after the invalidateBuffer() call above, as it might trigger a
637 // backing store sync, resulting in too many update requests.
638 setClipRegion(region);
639 }
640}
641
642static inline void flushUpdate(QWidget *widget, const QRegion &region,
643 const QPoint &offset)
644{
645#ifdef QT_NO_PAINT_DEBUG
646 Q_UNUSED(widget);
647 Q_UNUSED(region);
648 Q_UNUSED(offset);
649#else
650 static int delay = -1;
651
652 if (delay == -1)
653 delay = qgetenv("QT_FLUSH_UPDATE").toInt() * 10;
654
655 if (delay == 0)
656 return;
657
658 static QWSYellowSurface surface(true);
659 surface.setDelay(delay);
660 surface.flush(widget, region, offset);
661#endif // QT_NO_PAINT_DEBUG
662}
663
664void QWSWindowSurface::flush(QWidget *widget, const QRegion &region,
665 const QPoint &offset)
666{
667 const QWidget *win = window();
668 if (!win)
669 return;
670
671#ifndef QT_NO_GRAPHICSVIEW
672 QWExtra *extra = win->d_func()->extra;
673 if (extra && extra->proxyWidget)
674 return;
675#endif //QT_NO_GRAPHICSVIEW
676
677 Q_UNUSED(offset);
678
679 const bool opaque = isOpaque();
680#ifdef QT_QWS_DISABLE_FLUSHCLIPPING
681 QRegion toFlush = region;
682#else
683 QRegion toFlush = region & d_ptr->clip;
684#endif
685
686 if (!toFlush.isEmpty()) {
687 flushUpdate(widget, toFlush, QPoint(0, 0));
688 QPoint globalZero = win->mapToGlobal(QPoint(0, 0));
689 toFlush.translate(globalZero);
690
691#ifdef QT_QWS_CLIENTBLIT
692 bool needRepaint = true;
693 if (opaque) {
694 QScreen* widgetScreen = getScreen(widget);
695 if (widgetScreen->supportsBlitInClients()) {
696
697 QWSDisplay::grab();
698 if(directRegion().intersected(toFlush) == toFlush) {
699 QPoint translate = -globalZero + painterOffset() + geometry().topLeft();
700 QRegion flushRegion = toFlush.translated(translate);
701 widgetScreen->blit(image(), geometry().topLeft(), flushRegion);
702 widgetScreen->setDirty(toFlush.boundingRect());
703 needRepaint = false;
704 }
705 QWSDisplay::ungrab();
706 }
707 }
708
709 if(needRepaint)
710#endif
711 win->qwsDisplay()->repaintRegion(winId(), win->windowFlags(), opaque, toFlush);
712 }
713}
714
715/*!
716 Move the surface with the given \a offset.
717
718 A subclass may reimplement this function to enable accelerated window move.
719 It must return true if the move was successful and no repaint is necessary,
720 false otherwise.
721
722 The default implementation updates the QWindowSurface geometry and
723 returns true if the surface is buffered; false otherwise.
724
725 This function is called by the window system on the client instance.
726
727 \sa isBuffered()
728*/
729bool QWSWindowSurface::move(const QPoint &offset)
730{
731 QWindowSurface::setGeometry(geometry().translated(offset));
732 return isBuffered();
733}
734
735/*!
736 Move the surface with the given \a offset.
737
738 The new visible region after the window move is given by \a newClip
739 in screen coordinates.
740
741 A subclass may reimplement this function to enable accelerated window move.
742 The returned region indicates the area that still needs to be composed
743 on the screen.
744
745 The default implementation updates the QWindowSurface geometry and
746 returns the union of the old and new geometry.
747
748 This function is called by the window system on the server instance.
749*/
750QRegion QWSWindowSurface::move(const QPoint &offset, const QRegion &newClip)
751{
752 const QRegion oldGeometry = geometry();
753 QWindowSurface::setGeometry(geometry().translated(offset));
754 return oldGeometry + newClip;
755}
756
757void QWSWindowSurface::releaseSurface()
758{
759}
760
761bool QWSMemorySurface::lock(int timeout)
762{
763 Q_UNUSED(timeout);
764#ifndef QT_NO_QWS_MULTIPROCESS
765 if (memlock && !memlock->lock(QWSLock::BackingStore))
766 return false;
767#endif
768#ifndef QT_NO_THREAD
769 threadLock.lock();
770#endif
771 return true;
772}
773
774void QWSMemorySurface::unlock()
775{
776#ifndef QT_NO_THREAD
777 threadLock.unlock();
778#endif
779#ifndef QT_NO_QWS_MULTIPROCESS
780 if (memlock)
781 memlock->unlock(QWSLock::BackingStore);
782#endif
783}
784
785QWSMemorySurface::QWSMemorySurface()
786 : QWSWindowSurface()
787#ifndef QT_NO_QWS_MULTIPROCESS
788 , memlock(0)
789#endif
790{
791 setSurfaceFlags(Buffered);
792}
793
794QWSMemorySurface::QWSMemorySurface(QWidget *w)
795 : QWSWindowSurface(w)
796{
797 SurfaceFlags flags = Buffered;
798 if (isWidgetOpaque(w))
799 flags |= Opaque;
800 setSurfaceFlags(flags);
801
802#ifndef QT_NO_QWS_MULTIPROCESS
803 memlock = QWSDisplay::Data::getClientLock();
804#endif
805}
806
807QWSMemorySurface::~QWSMemorySurface()
808{
809}
810
811
812QImage::Format
813QWSMemorySurface::preferredImageFormat(const QWidget *widget) const
814{
815 QScreen *screen = getScreen(widget);
816 const int depth = screen->depth();
817 const bool opaque = isWidgetOpaque(widget);
818
819 if (!opaque) {
820 if (depth <= 12)
821 return QImage::Format_ARGB4444_Premultiplied;
822 else if (depth <= 15)
823 return QImage::Format_ARGB8555_Premultiplied;
824 else if (depth <= 16)
825 return QImage::Format_ARGB8565_Premultiplied;
826 else if (depth <= 18)
827 return QImage::Format_ARGB6666_Premultiplied;
828 else
829 return QImage::Format_ARGB32_Premultiplied;
830 }
831
832 QImage::Format format = screen->pixelFormat();
833 if (format > QImage::Format_Indexed8) // ### assumes all new image formats supports a QPainter
834 return format;
835
836 if (depth <= 12)
837 return QImage::Format_RGB444;
838 else if (depth <= 15)
839 return QImage::Format_RGB555;
840 else if (depth <= 16)
841 return QImage::Format_RGB16;
842 else if (depth <= 18)
843 return QImage::Format_RGB666;
844 else if (depth <= 24)
845 return QImage::Format_RGB888;
846 else
847 return QImage::Format_ARGB32_Premultiplied;
848}
849
850#ifndef QT_NO_QWS_MULTIPROCESS
851void QWSMemorySurface::setLock(int lockId)
852{
853 if (memlock && memlock->id() == lockId)
854 return;
855 delete memlock;
856 memlock = (lockId == -1 ? 0 : new QWSLock(lockId));
857 return;
858}
859#endif // QT_NO_QWS_MULTIPROCESS
860
861bool QWSMemorySurface::isValid() const
862{
863 if (img.isNull())
864 return true;
865
866 const QWidget *win = window();
867 if (preferredImageFormat(win) != img.format())
868 return false;
869
870 if (isOpaque() != isWidgetOpaque(win)) // XXX: use QWidgetPrivate::isOpaque()
871 return false;
872
873 return true;
874}
875
876// ### copied from qwindowsurface_raster.cpp -- should be cross-platform
877void QWSMemorySurface::beginPaint(const QRegion &rgn)
878{
879 if (!isWidgetOpaque(window())) {
880 QPainter p(&img);
881 p.setCompositionMode(QPainter::CompositionMode_Source);
882 const QVector<QRect> rects = rgn.rects();
883 const QColor blank = Qt::transparent;
884 for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
885 QRect r = *it;
886#ifdef Q_BACKINGSTORE_SUBSURFACES
887 r.translate(painterOffset());
888#endif
889 p.fillRect(r, blank);
890 }
891 }
892 QWSWindowSurface::beginPaint(rgn);
893}
894
895// from qwindowsurface.cpp
896extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
897
898bool QWSMemorySurface::scroll(const QRegion &area, int dx, int dy)
899{
900 const QVector<QRect> rects = area.rects();
901 for (int i = 0; i < rects.size(); ++i)
902 qt_scrollRectInImage(img, rects.at(i), QPoint(dx, dy));
903
904 return true;
905}
906
907QPoint QWSMemorySurface::painterOffset() const
908{
909 const QWidget *w = window();
910 if (!w)
911 return QPoint();
912
913 if (w->mask().isEmpty())
914 return QWSWindowSurface::painterOffset();
915
916 const QRegion region = w->mask()
917 & w->frameGeometry().translated(-w->geometry().topLeft());
918 return -region.boundingRect().topLeft();
919}
920
921QWSLocalMemSurface::QWSLocalMemSurface()
922 : QWSMemorySurface(), mem(0), memsize(0)
923{
924}
925
926QWSLocalMemSurface::QWSLocalMemSurface(QWidget *w)
927 : QWSMemorySurface(w), mem(0), memsize(0)
928{
929}
930
931QWSLocalMemSurface::~QWSLocalMemSurface()
932{
933 if (memsize)
934 delete[] mem;
935}
936
937void QWSLocalMemSurface::setGeometry(const QRect &rect)
938{
939 QSize size = rect.size();
940
941 QWidget *win = window();
942 if (win && !win->mask().isEmpty()) {
943 const QRegion region = win->mask()
944 & rect.translated(-win->geometry().topLeft());
945 size = region.boundingRect().size();
946 }
947
948 uchar *deleteLater = 0;
949 // In case of a Hide event we need to delete the memory after sending the
950 // event to the server in order to let the server animate the event.
951 if (size.isEmpty()) {
952 deleteLater = mem;
953 mem = 0;
954 }
955
956 if (img.size() != size) {
957 delete[] mem;
958 if (size.isEmpty()) {
959 mem = 0;
960 img = QImage();
961 } else {
962 const QImage::Format format = preferredImageFormat(win);
963 const int bpl = nextMulOf4(bytesPerPixel(format) * size.width());
964 const int memsize = bpl * size.height();
965 mem = new uchar[memsize];
966 img = QImage(mem, size.width(), size.height(), bpl, format);
967 setImageMetrics(img, win);
968 }
969 }
970
971 QWSWindowSurface::setGeometry(rect);
972 delete[] deleteLater;
973}
974
975QByteArray QWSLocalMemSurface::permanentState() const
976{
977 QByteArray array;
978 array.resize(sizeof(uchar*) + 3 * sizeof(int) +
979 sizeof(SurfaceFlags));
980
981 char *ptr = array.data();
982
983 *reinterpret_cast<uchar**>(ptr) = mem;
984 ptr += sizeof(uchar*);
985
986 reinterpret_cast<int*>(ptr)[0] = img.width();
987 reinterpret_cast<int*>(ptr)[1] = img.height();
988 ptr += 2 * sizeof(int);
989
990 *reinterpret_cast<int *>(ptr) = img.format();
991 ptr += sizeof(int);
992
993 *reinterpret_cast<SurfaceFlags*>(ptr) = surfaceFlags();
994
995 return array;
996}
997
998void QWSLocalMemSurface::setPermanentState(const QByteArray &data)
999{
1000 int width;
1001 int height;
1002 QImage::Format format;
1003 SurfaceFlags flags;
1004
1005 const char *ptr = data.constData();
1006
1007 mem = *reinterpret_cast<uchar* const*>(ptr);
1008 ptr += sizeof(uchar*);
1009
1010 width = reinterpret_cast<const int*>(ptr)[0];
1011 height = reinterpret_cast<const int*>(ptr)[1];
1012 ptr += 2 * sizeof(int);
1013
1014 format = QImage::Format(*reinterpret_cast<const int*>(ptr));
1015 ptr += sizeof(int);
1016
1017 flags = *reinterpret_cast<const SurfaceFlags*>(ptr);
1018
1019 const int bpl = nextMulOf4(bytesPerPixel(format) * width);
1020 QWSMemorySurface::img = QImage(mem, width, height, bpl, format);
1021 setSurfaceFlags(flags);
1022}
1023
1024void QWSLocalMemSurface::releaseSurface()
1025{
1026 mem = 0;
1027 img = QImage();
1028}
1029
1030#ifndef QT_NO_QWS_MULTIPROCESS
1031
1032QWSSharedMemSurface::QWSSharedMemSurface()
1033 : QWSMemorySurface()
1034{
1035}
1036
1037QWSSharedMemSurface::QWSSharedMemSurface(QWidget *widget)
1038 : QWSMemorySurface(widget)
1039{
1040}
1041
1042QWSSharedMemSurface::~QWSSharedMemSurface()
1043{
1044 // mem.detach() is done automatically by ~QSharedMemory
1045}
1046
1047bool QWSSharedMemSurface::setMemory(int memId)
1048{
1049 if (mem.id() == memId)
1050 return true;
1051
1052 mem.detach();
1053 if (!mem.attach(memId)) {
1054 perror("QWSSharedMemSurface: attaching to shared memory");
1055 qCritical("QWSSharedMemSurface: Error attaching to"
1056 " shared memory 0x%x", memId);
1057 return false;
1058 }
1059
1060 return true;
1061}
1062
1063#ifdef QT_QWS_CLIENTBLIT
1064void QWSSharedMemSurface::setDirectRegion(const QRegion &r, int id)
1065{
1066 QWSMemorySurface::setDirectRegion(r, id);
1067 if(mem.address())
1068 *(uint *)mem.address() = id;
1069}
1070
1071const QRegion QWSSharedMemSurface::directRegion() const
1072{
1073 QWSSharedMemory *cmem = const_cast<QWSSharedMemory *>(&mem);
1074 if (cmem->address() && ((int*)cmem->address())[0] == directRegionId())
1075 return QWSMemorySurface::directRegion();
1076 else
1077 return QRegion();
1078}
1079#endif
1080
1081void QWSSharedMemSurface::setPermanentState(const QByteArray &data)
1082{
1083 int memId;
1084 int width;
1085 int height;
1086 int lockId;
1087 QImage::Format format;
1088 SurfaceFlags flags;
1089
1090 const int *ptr = reinterpret_cast<const int*>(data.constData());
1091
1092 memId = ptr[0];
1093 width = ptr[1];
1094 height = ptr[2];
1095 lockId = ptr[3];
1096 format = QImage::Format(ptr[4]);
1097 flags = SurfaceFlags(ptr[5]);
1098
1099 setSurfaceFlags(flags);
1100 setMemory(memId);
1101 setLock(lockId);
1102
1103#ifdef QT_QWS_CLIENTBLIT
1104 uchar *base = static_cast<uchar*>(mem.address()) + sizeof(uint);
1105#else
1106 uchar *base = static_cast<uchar*>(mem.address());
1107#endif
1108 const int bpl = nextMulOf4(bytesPerPixel(format) * width);
1109 QWSMemorySurface::img = QImage(base, width, height, bpl, format);
1110}
1111
1112void QWSSharedMemSurface::setGeometry(const QRect &rect)
1113{
1114 const QSize size = rect.size();
1115 if (img.size() != size) {
1116 if (size.isEmpty()) {
1117 mem.detach();
1118 img = QImage();
1119 } else {
1120 mem.detach();
1121
1122 QWidget *win = window();
1123 const QImage::Format format = preferredImageFormat(win);
1124 const int bpl = nextMulOf4(bytesPerPixel(format) * size.width());
1125#ifdef QT_QWS_CLIENTBLIT
1126 const int imagesize = bpl * size.height() + sizeof(uint);
1127#else
1128 const int imagesize = bpl * size.height();
1129#endif
1130 if (!mem.create(imagesize)) {
1131 perror("QWSSharedMemSurface::setGeometry allocating shared memory");
1132 qFatal("Error creating shared memory of size %d", imagesize);
1133 }
1134#ifdef QT_QWS_CLIENTBLIT
1135 *((uint *)mem.address()) = 0;
1136 uchar *base = static_cast<uchar*>(mem.address()) + sizeof(uint);
1137#else
1138 uchar *base = static_cast<uchar*>(mem.address());
1139#endif
1140 img = QImage(base, size.width(), size.height(), bpl, format);
1141 setImageMetrics(img, win);
1142 }
1143 }
1144
1145 QWSWindowSurface::setGeometry(rect);
1146}
1147
1148QByteArray QWSSharedMemSurface::permanentState() const
1149{
1150 QByteArray array;
1151 array.resize(6 * sizeof(int));
1152
1153 int *ptr = reinterpret_cast<int*>(array.data());
1154
1155 ptr[0] = mem.id();
1156 ptr[1] = img.width();
1157 ptr[2] = img.height();
1158 ptr[3] = (memlock ? memlock->id() : -1);
1159 ptr[4] = int(img.format());
1160 ptr[5] = int(surfaceFlags());
1161
1162 return array;
1163}
1164
1165void QWSSharedMemSurface::releaseSurface()
1166{
1167 mem.detach();
1168 img = QImage();
1169}
1170
1171#endif // QT_NO_QWS_MULTIPROCESS
1172
1173#ifndef QT_NO_PAINTONSCREEN
1174
1175QWSOnScreenSurface::QWSOnScreenSurface(QWidget *w)
1176 : QWSMemorySurface(w)
1177{
1178 attachToScreen(getScreen(w));
1179 setSurfaceFlags(Opaque);
1180}
1181
1182QWSOnScreenSurface::QWSOnScreenSurface()
1183 : QWSMemorySurface()
1184{
1185 setSurfaceFlags(Opaque);
1186}
1187
1188void QWSOnScreenSurface::attachToScreen(const QScreen *s)
1189{
1190 screen = s;
1191 uchar *base = screen->base();
1192 QImage::Format format = screen->pixelFormat();
1193
1194 if (format == QImage::Format_Invalid || format == QImage::Format_Indexed8) {
1195 //### currently we have no paint engine for indexed image formats
1196 qFatal("QWSOnScreenSurface::attachToScreen(): screen depth %d "
1197 "not implemented", screen->depth());
1198 return;
1199 }
1200 QWSMemorySurface::img = QImage(base, screen->width(), screen->height(),
1201 screen->linestep(), format );
1202}
1203
1204QWSOnScreenSurface::~QWSOnScreenSurface()
1205{
1206}
1207
1208QPoint QWSOnScreenSurface::painterOffset() const
1209{
1210 return geometry().topLeft() + QWSWindowSurface::painterOffset();
1211}
1212
1213bool QWSOnScreenSurface::isValid() const
1214{
1215 const QWidget *win = window();
1216 if (screen != getScreen(win))
1217 return false;
1218 if (img.isNull())
1219 return false;
1220 return QScreen::isWidgetPaintOnScreen(win);
1221}
1222
1223QByteArray QWSOnScreenSurface::permanentState() const
1224{
1225 QByteArray array;
1226 array.resize(sizeof(int));
1227 int *ptr = reinterpret_cast<int*>(array.data());
1228 ptr[0] = QApplication::desktop()->screenNumber(window());
1229 return array;
1230}
1231
1232void QWSOnScreenSurface::setPermanentState(const QByteArray &data)
1233{
1234 const int *ptr = reinterpret_cast<const int*>(data.constData());
1235 const int screenNo = ptr[0];
1236
1237 QScreen *screen = qt_screen;
1238 if (screenNo > 0)
1239 screen = qt_screen->subScreens().at(screenNo);
1240 attachToScreen(screen);
1241}
1242
1243#endif // QT_NO_PAINTONSCREEN
1244
1245#ifndef QT_NO_PAINT_DEBUG
1246
1247QWSYellowSurface::QWSYellowSurface(bool isClient)
1248 : QWSWindowSurface(), delay(10)
1249{
1250 if (isClient) {
1251 setWinId(QWidget::qwsDisplay()->takeId());
1252 QWidget::qwsDisplay()->nameRegion(winId(),
1253 QLatin1String("Debug flush paint"),
1254 QLatin1String("Silly yellow thing"));
1255 QWidget::qwsDisplay()->setAltitude(winId(), 1, true);
1256 }
1257 setSurfaceFlags(Buffered);
1258}
1259
1260QWSYellowSurface::~QWSYellowSurface()
1261{
1262}
1263
1264QByteArray QWSYellowSurface::permanentState() const
1265{
1266 QByteArray array;
1267 array.resize(2 * sizeof(int));
1268
1269 int *ptr = reinterpret_cast<int*>(array.data());
1270 ptr[0] = surfaceSize.width();
1271 ptr[1] = surfaceSize.height();
1272
1273 return array;
1274}
1275
1276void QWSYellowSurface::setPermanentState(const QByteArray &data)
1277{
1278 const int *ptr = reinterpret_cast<const int*>(data.constData());
1279
1280 const int width = ptr[0];
1281 const int height = ptr[1];
1282
1283 img = QImage(width, height, QImage::Format_ARGB32);
1284 img.fill(qRgba(255,255,31,127));
1285}
1286
1287void QWSYellowSurface::flush(QWidget *widget, const QRegion &region,
1288 const QPoint &offset)
1289{
1290 Q_UNUSED(offset);
1291
1292 QWSDisplay *display = QWidget::qwsDisplay();
1293 QRegion rgn = region;
1294
1295 if (widget)
1296 rgn.translate(widget->mapToGlobal(QPoint(0, 0)));
1297
1298 surfaceSize = region.boundingRect().size();
1299
1300 const int id = winId();
1301 display->requestRegion(id, key(), permanentState(), rgn);
1302 display->setAltitude(id, 1, true);
1303 display->repaintRegion(id, 0, false, rgn);
1304
1305 ::usleep(500 * delay);
1306 display->requestRegion(id, key(), permanentState(), QRegion());
1307 ::usleep(500 * delay);
1308}
1309
1310#endif // QT_NO_PAINT_DEBUG
1311
1312#ifndef QT_NO_DIRECTPAINTER
1313
1314static inline QScreen *getPrimaryScreen()
1315{
1316 QScreen *screen = QScreen::instance();
1317 if (!screen->base()) {
1318 QList<QScreen*> subScreens = screen->subScreens();
1319 if (subScreens.size() < 1)
1320 return 0;
1321 screen = subScreens.at(0);
1322 }
1323 return screen;
1324}
1325
1326QWSDirectPainterSurface::QWSDirectPainterSurface(bool isClient,
1327 QDirectPainter::SurfaceFlag flags)
1328 : QWSWindowSurface(), flushingRegionEvents(false), doLocking(false)
1329{
1330 setSurfaceFlags(Opaque);
1331 synchronous = (flags == QDirectPainter::ReservedSynchronous);
1332
1333 if (isClient) {
1334 setWinId(QWidget::qwsDisplay()->takeId());
1335 QWidget::qwsDisplay()->nameRegion(winId(),
1336 QLatin1String("QDirectPainter reserved space"),
1337 QLatin1String("reserved"));
1338 } else {
1339 setWinId(0);
1340 }
1341 _screen = QScreen::instance();
1342 if (!_screen->base()) {
1343 QList<QScreen*> subScreens = _screen->subScreens();
1344 if (subScreens.size() < 1)
1345 _screen = 0;
1346 else
1347 _screen = subScreens.at(0);
1348 }
1349}
1350
1351QWSDirectPainterSurface::~QWSDirectPainterSurface()
1352{
1353 if (winId() && QWSDisplay::instance()) // make sure not in QApplication destructor
1354 QWidget::qwsDisplay()->destroyRegion(winId());
1355}
1356
1357void QWSDirectPainterSurface::setRegion(const QRegion &region)
1358{
1359 const int id = winId();
1360 QWidget::qwsDisplay()->requestRegion(id, key(), permanentState(), region);
1361#ifndef QT_NO_QWS_MULTIPROCESS
1362 if (synchronous)
1363 QWSDisplay::instance()->d->waitForRegionAck(id);
1364#endif
1365}
1366
1367void QWSDirectPainterSurface::flush(QWidget *, const QRegion &r, const QPoint &)
1368{
1369 QWSDisplay::instance()->repaintRegion(winId(), 0, true, r);
1370}
1371
1372QByteArray QWSDirectPainterSurface::permanentState() const
1373{
1374 QByteArray res;
1375 if (isRegionReserved())
1376 res.append( 'r');
1377 return res;
1378}
1379
1380void QWSDirectPainterSurface::setPermanentState(const QByteArray &ba)
1381{
1382 if (ba.size() > 0 && ba.at(0) == 'r')
1383 setReserved();
1384 setSurfaceFlags(surfaceFlags() | Opaque);
1385}
1386
1387void QWSDirectPainterSurface::beginPaint(const QRegion &region)
1388{
1389 QWSWindowSurface::beginPaint(region);
1390#ifndef QT_NO_QWS_MULTIPROCESS
1391 if (!synchronous) {
1392 flushingRegionEvents = true;
1393 QWSDisplay::instance()->d->waitForRegionEvents(winId(), doLocking);
1394 flushingRegionEvents = false;
1395 }
1396#endif
1397}
1398
1399bool QWSDirectPainterSurface::hasPendingRegionEvents() const
1400{
1401#ifndef QT_NO_QWS_MULTIPROCESS
1402 if (synchronous)
1403 return false;
1404
1405 return QWSDisplay::instance()->d->hasPendingRegionEvents();
1406#else
1407 return false;
1408#endif
1409}
1410
1411bool QWSDirectPainterSurface::lock(int timeout)
1412{
1413#ifndef QT_NO_THREAD
1414 threadLock.lock();
1415#endif
1416 Q_UNUSED(timeout);
1417 if (doLocking)
1418 QWSDisplay::grab(true);
1419 return true;
1420}
1421
1422void QWSDirectPainterSurface::unlock()
1423{
1424 if (doLocking)
1425 QWSDisplay::ungrab();
1426#ifndef QT_NO_THREAD
1427 threadLock.unlock();
1428#endif
1429}
1430
1431#endif // QT_NO_DIRECTPAINTER
1432
1433QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.