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

Last change on this file since 775 was 769, checked in by Dmitry A. Kuminov, 15 years ago

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

  • Property svn:eol-style set to native
File size: 38.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
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 [email protected].
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 p.fillRect(*it, blank);
886 }
887 }
888 QWSWindowSurface::beginPaint(rgn);
889}
890
891// from qwindowsurface.cpp
892extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
893
894bool QWSMemorySurface::scroll(const QRegion &area, int dx, int dy)
895{
896 const QVector<QRect> rects = area.rects();
897 for (int i = 0; i < rects.size(); ++i)
898 qt_scrollRectInImage(img, rects.at(i), QPoint(dx, dy));
899
900 return true;
901}
902
903QPoint QWSMemorySurface::painterOffset() const
904{
905 const QWidget *w = window();
906 if (!w)
907 return QPoint();
908
909 if (w->mask().isEmpty())
910 return QWSWindowSurface::painterOffset();
911
912 const QRegion region = w->mask()
913 & w->frameGeometry().translated(-w->geometry().topLeft());
914 return -region.boundingRect().topLeft();
915}
916
917QWSLocalMemSurface::QWSLocalMemSurface()
918 : QWSMemorySurface(), mem(0), memsize(0)
919{
920}
921
922QWSLocalMemSurface::QWSLocalMemSurface(QWidget *w)
923 : QWSMemorySurface(w), mem(0), memsize(0)
924{
925}
926
927QWSLocalMemSurface::~QWSLocalMemSurface()
928{
929 if (memsize)
930 delete[] mem;
931}
932
933void QWSLocalMemSurface::setGeometry(const QRect &rect)
934{
935 QSize size = rect.size();
936
937 QWidget *win = window();
938 if (win && !win->mask().isEmpty()) {
939 const QRegion region = win->mask()
940 & rect.translated(-win->geometry().topLeft());
941 size = region.boundingRect().size();
942 }
943
944 uchar *deleteLater = 0;
945 // In case of a Hide event we need to delete the memory after sending the
946 // event to the server in order to let the server animate the event.
947 if (size.isEmpty()) {
948 deleteLater = mem;
949 mem = 0;
950 }
951
952 if (img.size() != size) {
953 delete[] mem;
954 if (size.isEmpty()) {
955 mem = 0;
956 img = QImage();
957 } else {
958 const QImage::Format format = preferredImageFormat(win);
959 const int bpl = nextMulOf4(bytesPerPixel(format) * size.width());
960 const int memsize = bpl * size.height();
961 mem = new uchar[memsize];
962 img = QImage(mem, size.width(), size.height(), bpl, format);
963 setImageMetrics(img, win);
964 }
965 }
966
967 QWSWindowSurface::setGeometry(rect);
968 delete[] deleteLater;
969}
970
971QByteArray QWSLocalMemSurface::permanentState() const
972{
973 QByteArray array;
974 array.resize(sizeof(uchar*) + 3 * sizeof(int) +
975 sizeof(SurfaceFlags));
976
977 char *ptr = array.data();
978
979 *reinterpret_cast<uchar**>(ptr) = mem;
980 ptr += sizeof(uchar*);
981
982 reinterpret_cast<int*>(ptr)[0] = img.width();
983 reinterpret_cast<int*>(ptr)[1] = img.height();
984 ptr += 2 * sizeof(int);
985
986 *reinterpret_cast<int *>(ptr) = img.format();
987 ptr += sizeof(int);
988
989 *reinterpret_cast<SurfaceFlags*>(ptr) = surfaceFlags();
990
991 return array;
992}
993
994void QWSLocalMemSurface::setPermanentState(const QByteArray &data)
995{
996 int width;
997 int height;
998 QImage::Format format;
999 SurfaceFlags flags;
1000
1001 const char *ptr = data.constData();
1002
1003 mem = *reinterpret_cast<uchar* const*>(ptr);
1004 ptr += sizeof(uchar*);
1005
1006 width = reinterpret_cast<const int*>(ptr)[0];
1007 height = reinterpret_cast<const int*>(ptr)[1];
1008 ptr += 2 * sizeof(int);
1009
1010 format = QImage::Format(*reinterpret_cast<const int*>(ptr));
1011 ptr += sizeof(int);
1012
1013 flags = *reinterpret_cast<const SurfaceFlags*>(ptr);
1014
1015 const int bpl = nextMulOf4(bytesPerPixel(format) * width);
1016 QWSMemorySurface::img = QImage(mem, width, height, bpl, format);
1017 setSurfaceFlags(flags);
1018}
1019
1020void QWSLocalMemSurface::releaseSurface()
1021{
1022 mem = 0;
1023 img = QImage();
1024}
1025
1026#ifndef QT_NO_QWS_MULTIPROCESS
1027
1028QWSSharedMemSurface::QWSSharedMemSurface()
1029 : QWSMemorySurface()
1030{
1031}
1032
1033QWSSharedMemSurface::QWSSharedMemSurface(QWidget *widget)
1034 : QWSMemorySurface(widget)
1035{
1036}
1037
1038QWSSharedMemSurface::~QWSSharedMemSurface()
1039{
1040 // mem.detach() is done automatically by ~QSharedMemory
1041}
1042
1043bool QWSSharedMemSurface::setMemory(int memId)
1044{
1045 if (mem.id() == memId)
1046 return true;
1047
1048 mem.detach();
1049 if (!mem.attach(memId)) {
1050 perror("QWSSharedMemSurface: attaching to shared memory");
1051 qCritical("QWSSharedMemSurface: Error attaching to"
1052 " shared memory 0x%x", memId);
1053 return false;
1054 }
1055
1056 return true;
1057}
1058
1059#ifdef QT_QWS_CLIENTBLIT
1060void QWSSharedMemSurface::setDirectRegion(const QRegion &r, int id)
1061{
1062 QWSMemorySurface::setDirectRegion(r, id);
1063 if(mem.address())
1064 *(uint *)mem.address() = id;
1065}
1066
1067const QRegion QWSSharedMemSurface::directRegion() const
1068{
1069 QWSSharedMemory *cmem = const_cast<QWSSharedMemory *>(&mem);
1070 if (cmem->address() && ((int*)cmem->address())[0] == directRegionId())
1071 return QWSMemorySurface::directRegion();
1072 else
1073 return QRegion();
1074}
1075#endif
1076
1077void QWSSharedMemSurface::setPermanentState(const QByteArray &data)
1078{
1079 int memId;
1080 int width;
1081 int height;
1082 int lockId;
1083 QImage::Format format;
1084 SurfaceFlags flags;
1085
1086 const int *ptr = reinterpret_cast<const int*>(data.constData());
1087
1088 memId = ptr[0];
1089 width = ptr[1];
1090 height = ptr[2];
1091 lockId = ptr[3];
1092 format = QImage::Format(ptr[4]);
1093 flags = SurfaceFlags(ptr[5]);
1094
1095 setSurfaceFlags(flags);
1096 setMemory(memId);
1097 setLock(lockId);
1098
1099#ifdef QT_QWS_CLIENTBLIT
1100 uchar *base = static_cast<uchar*>(mem.address()) + sizeof(uint);
1101#else
1102 uchar *base = static_cast<uchar*>(mem.address());
1103#endif
1104 const int bpl = nextMulOf4(bytesPerPixel(format) * width);
1105 QWSMemorySurface::img = QImage(base, width, height, bpl, format);
1106}
1107
1108void QWSSharedMemSurface::setGeometry(const QRect &rect)
1109{
1110 const QSize size = rect.size();
1111 if (img.size() != size) {
1112 if (size.isEmpty()) {
1113 mem.detach();
1114 img = QImage();
1115 } else {
1116 mem.detach();
1117
1118 QWidget *win = window();
1119 const QImage::Format format = preferredImageFormat(win);
1120 const int bpl = nextMulOf4(bytesPerPixel(format) * size.width());
1121#ifdef QT_QWS_CLIENTBLIT
1122 const int imagesize = bpl * size.height() + sizeof(uint);
1123#else
1124 const int imagesize = bpl * size.height();
1125#endif
1126 if (!mem.create(imagesize)) {
1127 perror("QWSSharedMemSurface::setGeometry allocating shared memory");
1128 qFatal("Error creating shared memory of size %d", imagesize);
1129 }
1130#ifdef QT_QWS_CLIENTBLIT
1131 *((uint *)mem.address()) = 0;
1132 uchar *base = static_cast<uchar*>(mem.address()) + sizeof(uint);
1133#else
1134 uchar *base = static_cast<uchar*>(mem.address());
1135#endif
1136 img = QImage(base, size.width(), size.height(), bpl, format);
1137 setImageMetrics(img, win);
1138 }
1139 }
1140
1141 QWSWindowSurface::setGeometry(rect);
1142}
1143
1144QByteArray QWSSharedMemSurface::permanentState() const
1145{
1146 QByteArray array;
1147 array.resize(6 * sizeof(int));
1148
1149 int *ptr = reinterpret_cast<int*>(array.data());
1150
1151 ptr[0] = mem.id();
1152 ptr[1] = img.width();
1153 ptr[2] = img.height();
1154 ptr[3] = (memlock ? memlock->id() : -1);
1155 ptr[4] = int(img.format());
1156 ptr[5] = int(surfaceFlags());
1157
1158 return array;
1159}
1160
1161void QWSSharedMemSurface::releaseSurface()
1162{
1163 mem.detach();
1164 img = QImage();
1165}
1166
1167#endif // QT_NO_QWS_MULTIPROCESS
1168
1169#ifndef QT_NO_PAINTONSCREEN
1170
1171QWSOnScreenSurface::QWSOnScreenSurface(QWidget *w)
1172 : QWSMemorySurface(w)
1173{
1174 attachToScreen(getScreen(w));
1175 setSurfaceFlags(Opaque);
1176}
1177
1178QWSOnScreenSurface::QWSOnScreenSurface()
1179 : QWSMemorySurface()
1180{
1181 setSurfaceFlags(Opaque);
1182}
1183
1184void QWSOnScreenSurface::attachToScreen(const QScreen *s)
1185{
1186 screen = s;
1187 uchar *base = screen->base();
1188 QImage::Format format = screen->pixelFormat();
1189
1190 if (format == QImage::Format_Invalid || format == QImage::Format_Indexed8) {
1191 //### currently we have no paint engine for indexed image formats
1192 qFatal("QWSOnScreenSurface::attachToScreen(): screen depth %d "
1193 "not implemented", screen->depth());
1194 return;
1195 }
1196 QWSMemorySurface::img = QImage(base, screen->width(), screen->height(),
1197 screen->linestep(), format );
1198}
1199
1200QWSOnScreenSurface::~QWSOnScreenSurface()
1201{
1202}
1203
1204QPoint QWSOnScreenSurface::painterOffset() const
1205{
1206 return geometry().topLeft() + QWSWindowSurface::painterOffset();
1207}
1208
1209bool QWSOnScreenSurface::isValid() const
1210{
1211 const QWidget *win = window();
1212 if (screen != getScreen(win))
1213 return false;
1214 if (img.isNull())
1215 return false;
1216 return QScreen::isWidgetPaintOnScreen(win);
1217}
1218
1219QByteArray QWSOnScreenSurface::permanentState() const
1220{
1221 QByteArray array;
1222 array.resize(sizeof(int));
1223 int *ptr = reinterpret_cast<int*>(array.data());
1224 ptr[0] = QApplication::desktop()->screenNumber(window());
1225 return array;
1226}
1227
1228void QWSOnScreenSurface::setPermanentState(const QByteArray &data)
1229{
1230 const int *ptr = reinterpret_cast<const int*>(data.constData());
1231 const int screenNo = ptr[0];
1232
1233 QScreen *screen = qt_screen;
1234 if (screenNo > 0)
1235 screen = qt_screen->subScreens().at(screenNo);
1236 attachToScreen(screen);
1237}
1238
1239#endif // QT_NO_PAINTONSCREEN
1240
1241#ifndef QT_NO_PAINT_DEBUG
1242
1243QWSYellowSurface::QWSYellowSurface(bool isClient)
1244 : QWSWindowSurface(), delay(10)
1245{
1246 if (isClient) {
1247 setWinId(QWidget::qwsDisplay()->takeId());
1248 QWidget::qwsDisplay()->nameRegion(winId(),
1249 QLatin1String("Debug flush paint"),
1250 QLatin1String("Silly yellow thing"));
1251 QWidget::qwsDisplay()->setAltitude(winId(), 1, true);
1252 }
1253 setSurfaceFlags(Buffered);
1254}
1255
1256QWSYellowSurface::~QWSYellowSurface()
1257{
1258}
1259
1260QByteArray QWSYellowSurface::permanentState() const
1261{
1262 QByteArray array;
1263 array.resize(2 * sizeof(int));
1264
1265 int *ptr = reinterpret_cast<int*>(array.data());
1266 ptr[0] = surfaceSize.width();
1267 ptr[1] = surfaceSize.height();
1268
1269 return array;
1270}
1271
1272void QWSYellowSurface::setPermanentState(const QByteArray &data)
1273{
1274 const int *ptr = reinterpret_cast<const int*>(data.constData());
1275
1276 const int width = ptr[0];
1277 const int height = ptr[1];
1278
1279 img = QImage(width, height, QImage::Format_ARGB32);
1280 img.fill(qRgba(255,255,31,127));
1281}
1282
1283void QWSYellowSurface::flush(QWidget *widget, const QRegion &region,
1284 const QPoint &offset)
1285{
1286 Q_UNUSED(offset);
1287
1288 QWSDisplay *display = QWidget::qwsDisplay();
1289 QRegion rgn = region;
1290
1291 if (widget)
1292 rgn.translate(widget->mapToGlobal(QPoint(0, 0)));
1293
1294 surfaceSize = region.boundingRect().size();
1295
1296 const int id = winId();
1297 display->requestRegion(id, key(), permanentState(), rgn);
1298 display->setAltitude(id, 1, true);
1299 display->repaintRegion(id, 0, false, rgn);
1300
1301 ::usleep(500 * delay);
1302 display->requestRegion(id, key(), permanentState(), QRegion());
1303 ::usleep(500 * delay);
1304}
1305
1306#endif // QT_NO_PAINT_DEBUG
1307
1308#ifndef QT_NO_DIRECTPAINTER
1309
1310static inline QScreen *getPrimaryScreen()
1311{
1312 QScreen *screen = QScreen::instance();
1313 if (!screen->base()) {
1314 QList<QScreen*> subScreens = screen->subScreens();
1315 if (subScreens.size() < 1)
1316 return 0;
1317 screen = subScreens.at(0);
1318 }
1319 return screen;
1320}
1321
1322QWSDirectPainterSurface::QWSDirectPainterSurface(bool isClient,
1323 QDirectPainter::SurfaceFlag flags)
1324 : QWSWindowSurface(), flushingRegionEvents(false), doLocking(false)
1325{
1326 setSurfaceFlags(Opaque);
1327 synchronous = (flags == QDirectPainter::ReservedSynchronous);
1328
1329 if (isClient) {
1330 setWinId(QWidget::qwsDisplay()->takeId());
1331 QWidget::qwsDisplay()->nameRegion(winId(),
1332 QLatin1String("QDirectPainter reserved space"),
1333 QLatin1String("reserved"));
1334 } else {
1335 setWinId(0);
1336 }
1337 _screen = QScreen::instance();
1338 if (!_screen->base()) {
1339 QList<QScreen*> subScreens = _screen->subScreens();
1340 if (subScreens.size() < 1)
1341 _screen = 0;
1342 else
1343 _screen = subScreens.at(0);
1344 }
1345}
1346
1347QWSDirectPainterSurface::~QWSDirectPainterSurface()
1348{
1349 if (winId() && QWSDisplay::instance()) // make sure not in QApplication destructor
1350 QWidget::qwsDisplay()->destroyRegion(winId());
1351}
1352
1353void QWSDirectPainterSurface::setRegion(const QRegion &region)
1354{
1355 const int id = winId();
1356 QWidget::qwsDisplay()->requestRegion(id, key(), permanentState(), region);
1357#ifndef QT_NO_QWS_MULTIPROCESS
1358 if (synchronous)
1359 QWSDisplay::instance()->d->waitForRegionAck(id);
1360#endif
1361}
1362
1363void QWSDirectPainterSurface::flush(QWidget *, const QRegion &r, const QPoint &)
1364{
1365 QWSDisplay::instance()->repaintRegion(winId(), 0, true, r);
1366}
1367
1368QByteArray QWSDirectPainterSurface::permanentState() const
1369{
1370 QByteArray res;
1371 if (isRegionReserved())
1372 res.append( 'r');
1373 return res;
1374}
1375
1376void QWSDirectPainterSurface::setPermanentState(const QByteArray &ba)
1377{
1378 if (ba.size() > 0 && ba.at(0) == 'r')
1379 setReserved();
1380 setSurfaceFlags(surfaceFlags() | Opaque);
1381}
1382
1383void QWSDirectPainterSurface::beginPaint(const QRegion &region)
1384{
1385 QWSWindowSurface::beginPaint(region);
1386#ifndef QT_NO_QWS_MULTIPROCESS
1387 if (!synchronous) {
1388 flushingRegionEvents = true;
1389 QWSDisplay::instance()->d->waitForRegionEvents(winId(), doLocking);
1390 flushingRegionEvents = false;
1391 }
1392#endif
1393}
1394
1395bool QWSDirectPainterSurface::hasPendingRegionEvents() const
1396{
1397#ifndef QT_NO_QWS_MULTIPROCESS
1398 if (synchronous)
1399 return false;
1400
1401 return QWSDisplay::instance()->d->hasPendingRegionEvents();
1402#else
1403 return false;
1404#endif
1405}
1406
1407bool QWSDirectPainterSurface::lock(int timeout)
1408{
1409#ifndef QT_NO_THREAD
1410 threadLock.lock();
1411#endif
1412 Q_UNUSED(timeout);
1413 if (doLocking)
1414 QWSDisplay::grab(true);
1415 return true;
1416}
1417
1418void QWSDirectPainterSurface::unlock()
1419{
1420 if (doLocking)
1421 QWSDisplay::ungrab();
1422#ifndef QT_NO_THREAD
1423 threadLock.unlock();
1424#endif
1425}
1426
1427#endif // QT_NO_DIRECTPAINTER
1428
1429QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.