backport memory leak fix from Qt 4.8.0
[qt:qt-chloride.git] / src / gui / painting / qwindowsurface_qws.cpp
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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
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
59 QT_BEGIN_NAMESPACE
60
61 #ifdef Q_BACKINGSTORE_SUBSURFACES
62
63 typedef QMap<int, QWSWindowSurface*> SurfaceMap;
64 Q_GLOBAL_STATIC(SurfaceMap, winIdToSurfaceMap);
65
66 QWSWindowSurface* qt_findWindowSurface(int winId)
67 {
68     return winIdToSurfaceMap()->value(winId);
69 }
70
71 static 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
81 inline bool isWidgetOpaque(const QWidget *w)
82 {
83     return w->d_func()->isOpaque && !w->testAttribute(Qt::WA_TranslucentBackground);
84 }
85
86 static 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
97 static 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
134 static inline int nextMulOf4(int n)
135 {
136     return ((n + 3) & 0xfffffffc);
137 }
138
139 static 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
149 void 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
165 QWSWindowSurfacePrivate::QWSWindowSurfacePrivate()
166     : flags(0),
167 #ifdef QT_QWS_CLIENTBLIT
168     directId(-1),
169 #endif
170     winId(0)
171 {
172 }
173
174 void QWSWindowSurfacePrivate::setWinId(int id)
175 {
176     winId = id;
177 }
178
179 int 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
207 void 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 */
408 QWSWindowSurface::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 */
416 QWSWindowSurface::QWSWindowSurface(QWidget *widget)
417     : QWindowSurface(widget), d_ptr(new QWSWindowSurfacePrivate)
418 {
419 }
420
421 QWSWindowSurface::~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 */
436 QPoint 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
444 void QWSWindowSurface::beginPaint(const QRegion &)
445 {
446     lock();
447 }
448
449 void QWSWindowSurface::endPaint(const QRegion &)
450 {
451     unlock();
452 }
453
454 // XXX: documentation!!!
455 QByteArray QWSWindowSurface::transientState() const
456 {
457     return QByteArray();
458 }
459
460 QByteArray QWSWindowSurface::permanentState() const
461 {
462     return QByteArray();
463 }
464
465 void QWSWindowSurface::setTransientState(const QByteArray &state)
466 {
467     Q_UNUSED(state);
468 }
469
470 void QWSWindowSurface::setPermanentState(const QByteArray &state)
471 {
472     Q_UNUSED(state);
473 }
474
475 bool QWSWindowSurface::lock(int timeout)
476 {
477     Q_UNUSED(timeout);
478     return true;
479 }
480
481 void QWSWindowSurface::unlock()
482 {
483 }
484
485 #ifdef QT_QWS_CLIENTBLIT
486 /*! \internal */
487 const QRegion QWSWindowSurface::directRegion() const
488 {
489     return d_ptr->direct;
490 }
491
492 /*! \internal */
493 int QWSWindowSurface::directRegionId() const
494 {
495     return d_ptr->directId;
496 }
497
498 /*! \internal */
499 void 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 */
511 const 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 */
522 void 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 */
568 QWSWindowSurface::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 */
579 void QWSWindowSurface::setSurfaceFlags(SurfaceFlags flags)
580 {
581     d_ptr->flags = flags;
582 }
583
584 void 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
611 void 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
642 static 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
664 void 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 */
729 bool 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 */
750 QRegion 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
757 void QWSWindowSurface::releaseSurface()
758 {
759 }
760
761 bool 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
774 void 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
785 QWSMemorySurface::QWSMemorySurface()
786     : QWSWindowSurface()
787 #ifndef QT_NO_QWS_MULTIPROCESS
788     , memlock(0)
789 #endif
790 {
791     setSurfaceFlags(Buffered);
792 }
793
794 QWSMemorySurface::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
807 QWSMemorySurface::~QWSMemorySurface()
808 {
809 }
810
811
812 QImage::Format
813 QWSMemorySurface::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
851 void 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
861 bool 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
877 void 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
896 extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
897
898 bool 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
907 QPoint 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
921 QWSLocalMemSurface::QWSLocalMemSurface()
922     : QWSMemorySurface(), mem(0), memsize(0)
923 {
924 }
925
926 QWSLocalMemSurface::QWSLocalMemSurface(QWidget *w)
927     : QWSMemorySurface(w), mem(0), memsize(0)
928 {
929 }
930
931 QWSLocalMemSurface::~QWSLocalMemSurface()
932 {
933     if (memsize)
934         delete[] mem;
935 }
936
937 void 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
950     if (img.size() != size) {
951         if (size.isEmpty()) {
952             if (memsize) {
953                 // In case of a Hide event we need to delete the memory after sending the
954                 // event to the server in order to let the server animate the event.
955                 deleteLater = mem;
956                 memsize = 0;
957             }
958             mem = 0;
959             img = QImage();
960         } else {
961             const QImage::Format format = preferredImageFormat(win);
962             const int bpl = nextMulOf4(bytesPerPixel(format) * size.width());
963             const int imagesize = bpl * size.height();
964             if (memsize < imagesize) {
965                 delete[] mem;
966                 memsize = imagesize;
967                 mem = new uchar[memsize];
968             }
969             img = QImage(mem, size.width(), size.height(), bpl, format);
970             setImageMetrics(img, win);
971         }
972     }
973
974     QWSWindowSurface::setGeometry(rect);
975     delete[] deleteLater;
976 }
977
978 QByteArray QWSLocalMemSurface::permanentState() const
979 {
980     QByteArray array;
981     array.resize(sizeof(uchar*) + 3 * sizeof(int) +
982                  sizeof(SurfaceFlags));
983
984     char *ptr = array.data();
985
986     *reinterpret_cast<uchar**>(ptr) = mem;
987     ptr += sizeof(uchar*);
988
989     reinterpret_cast<int*>(ptr)[0] = img.width();
990     reinterpret_cast<int*>(ptr)[1] = img.height();
991     ptr += 2 * sizeof(int);
992
993     *reinterpret_cast<int *>(ptr) = img.format();
994     ptr += sizeof(int);
995
996     *reinterpret_cast<SurfaceFlags*>(ptr) = surfaceFlags();
997
998     return array;
999 }
1000
1001 void QWSLocalMemSurface::setPermanentState(const QByteArray &data)
1002 {
1003     int width;
1004     int height;
1005     QImage::Format format;
1006     SurfaceFlags flags;
1007
1008     const char *ptr = data.constData();
1009
1010     mem = *reinterpret_cast<uchar* const*>(ptr);
1011     ptr += sizeof(uchar*);
1012
1013     width = reinterpret_cast<const int*>(ptr)[0];
1014     height = reinterpret_cast<const int*>(ptr)[1];
1015     ptr += 2 * sizeof(int);
1016
1017     format = QImage::Format(*reinterpret_cast<const int*>(ptr));
1018     ptr += sizeof(int);
1019
1020     flags = *reinterpret_cast<const SurfaceFlags*>(ptr);
1021
1022     const int bpl = nextMulOf4(bytesPerPixel(format) * width);
1023     QWSMemorySurface::img = QImage(mem, width, height, bpl, format);
1024     setSurfaceFlags(flags);
1025 }
1026
1027 void QWSLocalMemSurface::releaseSurface()
1028 {
1029     if (memsize) {
1030         delete[] mem;
1031         memsize = 0;
1032     }
1033     mem = 0;
1034     img = QImage();
1035 }
1036
1037 #ifndef QT_NO_QWS_MULTIPROCESS
1038
1039 QWSSharedMemSurface::QWSSharedMemSurface()
1040     : QWSMemorySurface()
1041 {
1042 }
1043
1044 QWSSharedMemSurface::QWSSharedMemSurface(QWidget *widget)
1045     : QWSMemorySurface(widget)
1046 {
1047 }
1048
1049 QWSSharedMemSurface::~QWSSharedMemSurface()
1050 {
1051     // mem.detach() is done automatically by ~QSharedMemory
1052 }
1053
1054 bool QWSSharedMemSurface::setMemory(int memId)
1055 {
1056     if (mem.id() == memId)
1057         return true;
1058
1059     mem.detach();
1060     if (!mem.attach(memId)) {
1061         perror("QWSSharedMemSurface: attaching to shared memory");
1062         qCritical("QWSSharedMemSurface: Error attaching to"
1063                   " shared memory 0x%x", memId);
1064         return false;
1065     }
1066
1067     return true;
1068 }
1069
1070 #ifdef QT_QWS_CLIENTBLIT
1071 void QWSSharedMemSurface::setDirectRegion(const QRegion &r, int id)
1072 {
1073     QWSMemorySurface::setDirectRegion(r, id);
1074     if(mem.address())
1075         *(uint *)mem.address() = id;
1076 }
1077
1078 const QRegion QWSSharedMemSurface::directRegion() const
1079 {
1080     QWSSharedMemory *cmem = const_cast<QWSSharedMemory *>(&mem);
1081     if (cmem->address() && ((int*)cmem->address())[0] == directRegionId())
1082         return QWSMemorySurface::directRegion();
1083     else
1084         return QRegion();
1085 }
1086 #endif
1087
1088 void QWSSharedMemSurface::setPermanentState(const QByteArray &data)
1089 {
1090     int memId;
1091     int width;
1092     int height;
1093     int lockId;
1094     QImage::Format format;
1095     SurfaceFlags flags;
1096
1097     const int *ptr = reinterpret_cast<const int*>(data.constData());
1098
1099     memId = ptr[0];
1100     width = ptr[1];
1101     height = ptr[2];
1102     lockId = ptr[3];
1103     format = QImage::Format(ptr[4]);
1104     flags = SurfaceFlags(ptr[5]);
1105
1106     setSurfaceFlags(flags);
1107     setMemory(memId);
1108     setLock(lockId);
1109
1110 #ifdef QT_QWS_CLIENTBLIT
1111     uchar *base = static_cast<uchar*>(mem.address()) + sizeof(uint);
1112 #else
1113     uchar *base = static_cast<uchar*>(mem.address());
1114 #endif
1115     const int bpl = nextMulOf4(bytesPerPixel(format) * width);
1116     QWSMemorySurface::img = QImage(base, width, height, bpl, format);
1117 }
1118
1119 void QWSSharedMemSurface::setGeometry(const QRect &rect)
1120 {
1121     const QSize size = rect.size();
1122     if (img.size() != size) {
1123         if (size.isEmpty()) {
1124             mem.detach();
1125             img = QImage();
1126         } else {
1127             mem.detach();
1128
1129             QWidget *win = window();
1130             const QImage::Format format = preferredImageFormat(win);
1131             const int bpl = nextMulOf4(bytesPerPixel(format) * size.width());
1132 #ifdef QT_QWS_CLIENTBLIT
1133             const int imagesize = bpl * size.height() + sizeof(uint);
1134 #else
1135             const int imagesize = bpl * size.height();
1136 #endif
1137             if (!mem.create(imagesize)) {
1138                 perror("QWSSharedMemSurface::setGeometry allocating shared memory");
1139                 qFatal("Error creating shared memory of size %d", imagesize);
1140             }
1141 #ifdef QT_QWS_CLIENTBLIT
1142             *((uint *)mem.address()) = 0;
1143             uchar *base = static_cast<uchar*>(mem.address()) + sizeof(uint);
1144 #else
1145             uchar *base = static_cast<uchar*>(mem.address());
1146 #endif
1147             img = QImage(base, size.width(), size.height(), bpl, format);
1148             setImageMetrics(img, win);
1149         }
1150     }
1151
1152     QWSWindowSurface::setGeometry(rect);
1153 }
1154
1155 QByteArray QWSSharedMemSurface::permanentState() const
1156 {
1157     QByteArray array;
1158     array.resize(6 * sizeof(int));
1159
1160     int *ptr = reinterpret_cast<int*>(array.data());
1161
1162     ptr[0] = mem.id();
1163     ptr[1] = img.width();
1164     ptr[2] = img.height();
1165     ptr[3] = (memlock ? memlock->id() : -1);
1166     ptr[4] = int(img.format());
1167     ptr[5] = int(surfaceFlags());
1168
1169     return array;
1170 }
1171
1172 void QWSSharedMemSurface::releaseSurface()
1173 {
1174     mem.detach();
1175     img = QImage();
1176 }
1177
1178 #endif // QT_NO_QWS_MULTIPROCESS
1179
1180 #ifndef QT_NO_PAINTONSCREEN
1181
1182 QWSOnScreenSurface::QWSOnScreenSurface(QWidget *w)
1183     : QWSMemorySurface(w)
1184 {
1185     attachToScreen(getScreen(w));
1186     setSurfaceFlags(Opaque);
1187 }
1188
1189 QWSOnScreenSurface::QWSOnScreenSurface()
1190     : QWSMemorySurface()
1191 {
1192     setSurfaceFlags(Opaque);
1193 }
1194
1195 void QWSOnScreenSurface::attachToScreen(const QScreen *s)
1196 {
1197     screen = s;
1198     uchar *base = screen->base();
1199     QImage::Format format  = screen->pixelFormat();
1200
1201     if (format == QImage::Format_Invalid || format == QImage::Format_Indexed8) {
1202         //### currently we have no paint engine for indexed image formats
1203         qFatal("QWSOnScreenSurface::attachToScreen(): screen depth %d "
1204                "not implemented", screen->depth());
1205         return;
1206     }
1207     QWSMemorySurface::img = QImage(base, screen->width(), screen->height(),
1208                                    screen->linestep(), format );
1209 }
1210
1211 QWSOnScreenSurface::~QWSOnScreenSurface()
1212 {
1213 }
1214
1215 QPoint QWSOnScreenSurface::painterOffset() const
1216 {
1217     return geometry().topLeft() + QWSWindowSurface::painterOffset();
1218 }
1219
1220 bool QWSOnScreenSurface::isValid() const
1221 {
1222     const QWidget *win = window();
1223     if (screen != getScreen(win))
1224         return false;
1225     if (img.isNull())
1226         return false;
1227     return QScreen::isWidgetPaintOnScreen(win);
1228 }
1229
1230 QByteArray QWSOnScreenSurface::permanentState() const
1231 {
1232     QByteArray array;
1233     array.resize(sizeof(int));
1234     int *ptr = reinterpret_cast<int*>(array.data());
1235     ptr[0] = QApplication::desktop()->screenNumber(window());
1236     return array;
1237 }
1238
1239 void QWSOnScreenSurface::setPermanentState(const QByteArray &data)
1240 {
1241     const int *ptr = reinterpret_cast<const int*>(data.constData());
1242     const int screenNo = ptr[0];
1243
1244     QScreen *screen = qt_screen;
1245     if (screenNo > 0)
1246         screen = qt_screen->subScreens().at(screenNo);
1247     attachToScreen(screen);
1248 }
1249
1250 #endif // QT_NO_PAINTONSCREEN
1251
1252 #ifndef QT_NO_PAINT_DEBUG
1253
1254 QWSYellowSurface::QWSYellowSurface(bool isClient)
1255     : QWSWindowSurface(), delay(10)
1256 {
1257     if (isClient) {
1258         setWinId(QWidget::qwsDisplay()->takeId());
1259         QWidget::qwsDisplay()->nameRegion(winId(),
1260                                           QLatin1String("Debug flush paint"),
1261                                           QLatin1String("Silly yellow thing"));
1262         QWidget::qwsDisplay()->setAltitude(winId(), 1, true);
1263     }
1264     setSurfaceFlags(Buffered);
1265 }
1266
1267 QWSYellowSurface::~QWSYellowSurface()
1268 {
1269 }
1270
1271 QByteArray QWSYellowSurface::permanentState() const
1272 {
1273     QByteArray array;
1274     array.resize(2 * sizeof(int));
1275
1276     int *ptr = reinterpret_cast<int*>(array.data());
1277     ptr[0] = surfaceSize.width();
1278     ptr[1] = surfaceSize.height();
1279
1280     return array;
1281 }
1282
1283 void QWSYellowSurface::setPermanentState(const QByteArray &data)
1284 {
1285     const int *ptr = reinterpret_cast<const int*>(data.constData());
1286
1287     const int width = ptr[0];
1288     const int height = ptr[1];
1289
1290     img = QImage(width, height, QImage::Format_ARGB32);
1291     img.fill(qRgba(255,255,31,127));
1292 }
1293
1294 void QWSYellowSurface::flush(QWidget *widget, const QRegion &region,
1295                              const QPoint &offset)
1296 {
1297     Q_UNUSED(offset);
1298
1299     QWSDisplay *display = QWidget::qwsDisplay();
1300     QRegion rgn = region;
1301
1302     if (widget)
1303         rgn.translate(widget->mapToGlobal(QPoint(0, 0)));
1304
1305     surfaceSize = region.boundingRect().size();
1306
1307     const int id = winId();
1308     display->requestRegion(id, key(), permanentState(), rgn);
1309     display->setAltitude(id, 1, true);
1310     display->repaintRegion(id, 0, false, rgn);
1311
1312     ::usleep(500 * delay);
1313     display->requestRegion(id, key(), permanentState(), QRegion());
1314     ::usleep(500 * delay);
1315 }
1316
1317 #endif // QT_NO_PAINT_DEBUG
1318
1319 #ifndef QT_NO_DIRECTPAINTER
1320
1321 static inline QScreen *getPrimaryScreen()
1322 {
1323     QScreen *screen = QScreen::instance();
1324     if (!screen->base()) {
1325         QList<QScreen*> subScreens = screen->subScreens();
1326         if (subScreens.size() < 1)
1327             return 0;
1328         screen = subScreens.at(0);
1329     }
1330     return screen;
1331 }
1332
1333 QWSDirectPainterSurface::QWSDirectPainterSurface(bool isClient,
1334                                                  QDirectPainter::SurfaceFlag flags)
1335     : QWSWindowSurface(), flushingRegionEvents(false), doLocking(false)
1336 {
1337     setSurfaceFlags(Opaque);
1338     synchronous = (flags == QDirectPainter::ReservedSynchronous);
1339
1340     if (isClient) {
1341         setWinId(QWidget::qwsDisplay()->takeId());
1342         QWidget::qwsDisplay()->nameRegion(winId(),
1343                                           QLatin1String("QDirectPainter reserved space"),
1344                                           QLatin1String("reserved"));
1345     } else {
1346         setWinId(0);
1347     }
1348     _screen = QScreen::instance();
1349     if (!_screen->base()) {
1350         QList<QScreen*> subScreens = _screen->subScreens();
1351         if (subScreens.size() < 1)
1352             _screen = 0;
1353         else
1354             _screen = subScreens.at(0);
1355     }
1356 }
1357
1358 QWSDirectPainterSurface::~QWSDirectPainterSurface()
1359 {
1360     if (winId() && QWSDisplay::instance()) // make sure not in QApplication destructor
1361         QWidget::qwsDisplay()->destroyRegion(winId());
1362 }
1363
1364 void QWSDirectPainterSurface::setRegion(const QRegion &region)
1365 {
1366     const int id = winId();
1367     QWidget::qwsDisplay()->requestRegion(id, key(), permanentState(), region);
1368 #ifndef QT_NO_QWS_MULTIPROCESS
1369     if (synchronous)
1370         QWSDisplay::instance()->d->waitForRegionAck(id);
1371 #endif
1372 }
1373
1374 void QWSDirectPainterSurface::flush(QWidget *, const QRegion &r, const QPoint &)
1375 {
1376     QWSDisplay::instance()->repaintRegion(winId(), 0, true, r);
1377 }
1378
1379 QByteArray QWSDirectPainterSurface::permanentState() const
1380 {
1381     QByteArray res;
1382     if (isRegionReserved())
1383         res.append( 'r');
1384     return res;
1385 }
1386
1387 void QWSDirectPainterSurface::setPermanentState(const QByteArray &ba)
1388 {
1389     if (ba.size() > 0 && ba.at(0) == 'r')
1390         setReserved();
1391     setSurfaceFlags(surfaceFlags() | Opaque);
1392 }
1393
1394 void QWSDirectPainterSurface::beginPaint(const QRegion &region)
1395 {
1396     QWSWindowSurface::beginPaint(region);
1397 #ifndef QT_NO_QWS_MULTIPROCESS
1398     if (!synchronous) {
1399         flushingRegionEvents = true;
1400         QWSDisplay::instance()->d->waitForRegionEvents(winId(), doLocking);
1401         flushingRegionEvents = false;
1402     }
1403 #endif
1404 }
1405
1406 bool QWSDirectPainterSurface::hasPendingRegionEvents() const
1407 {
1408 #ifndef QT_NO_QWS_MULTIPROCESS
1409     if (synchronous)
1410         return false;
1411
1412     return QWSDisplay::instance()->d->hasPendingRegionEvents();
1413 #else
1414     return false;
1415 #endif
1416 }
1417
1418 bool QWSDirectPainterSurface::lock(int timeout)
1419 {
1420 #ifndef QT_NO_THREAD
1421     threadLock.lock();
1422 #endif
1423     Q_UNUSED(timeout);
1424     if (doLocking)
1425         QWSDisplay::grab(true);
1426     return true;
1427 }
1428
1429 void QWSDirectPainterSurface::unlock()
1430 {
1431     if (doLocking)
1432         QWSDisplay::ungrab();
1433 #ifndef QT_NO_THREAD
1434     threadLock.unlock();
1435 #endif
1436 }
1437
1438 #endif // QT_NO_DIRECTPAINTER
1439
1440 QT_END_NAMESPACE