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

Last change on this file since 744 was 651, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.2 sources.

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