diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-09-18 12:54:44 (GMT) |
---|---|---|
committer | Lars Knoll <lars.knoll@nokia.com> | 2009-09-18 12:54:44 (GMT) |
commit | 0e7e62eb6afbc1f20d08b837643009cec8eaacb9 (patch) | |
tree | 1eb5f9fb0194b8a9ffa1d9ab961a0ac68db7508a /src/gui | |
parent | b88bcd68a62ab8ed348bc698f7342346963bb7c0 (diff) | |
parent | 421e02d7b48b4a852a4aa1e6feb781a64f0981b4 (diff) | |
download | Qt-0e7e62eb6afbc1f20d08b837643009cec8eaacb9.zip Qt-0e7e62eb6afbc1f20d08b837643009cec8eaacb9.tar.gz Qt-0e7e62eb6afbc1f20d08b837643009cec8eaacb9.tar.bz2 |
Merge commit 'origin/4.6' into kinetic-declarativeui
Conflicts:
configure.exe
Diffstat (limited to 'src/gui')
55 files changed, 1832 insertions, 565 deletions
diff --git a/src/gui/egl/egl.pri b/src/gui/egl/egl.pri index 22c8bd7..ba991bd 100644 --- a/src/gui/egl/egl.pri +++ b/src/gui/egl/egl.pri @@ -26,3 +26,4 @@ for(p, QMAKE_LIBDIR_EGL) { !isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL !isEmpty(QMAKE_LIBS_EGL): LIBS_PRIVATE += $$QMAKE_LIBS_EGL +!isEmpty(QMAKE_LFLAGS_EGL): LIBS += $$QMAKE_LFLAGS_EGL diff --git a/src/gui/egl/qegl_symbian.cpp b/src/gui/egl/qegl_symbian.cpp index 3355f0e..fa0b5cb 100644 --- a/src/gui/egl/qegl_symbian.cpp +++ b/src/gui/egl/qegl_symbian.cpp @@ -98,6 +98,9 @@ EGLDisplay QEglContext::getDisplay(QPaintDevice *device) // Set pixel format and other properties based on a paint device. void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) { + if(!dev) + return; + int devType = dev->devType(); if (devType == QInternal::Image) setPixelFormat(static_cast<QImage *>(dev)->format()); diff --git a/src/gui/embedded/directfb.pri b/src/gui/embedded/directfb.pri index 7dae9d5..43ff0c7 100644 --- a/src/gui/embedded/directfb.pri +++ b/src/gui/embedded/directfb.pri @@ -8,7 +8,7 @@ #DEFINES += QT_DIRECTFB_IMAGECACHE #DEFINES += QT_NO_DIRECTFB_WM #DEFINES += QT_NO_DIRECTFB_LAYER -#DEFINES += QT_NO_DIRECTFB_PALETTE +#DEFINES += QT_DIRECTFB_PALETTE #DEFINES += QT_NO_DIRECTFB_PREALLOCATED #DEFINES += QT_NO_DIRECTFB_MOUSE #DEFINES += QT_NO_DIRECTFB_KEYBOARD diff --git a/src/gui/graphicsview/qgraphicsanchorlayout.cpp b/src/gui/graphicsview/qgraphicsanchorlayout.cpp index 5897ae4..78b6b53 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout.cpp @@ -194,7 +194,7 @@ QGraphicsAnchorLayout::addAnchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge) { Q_D(QGraphicsAnchorLayout); - QGraphicsAnchor *a = d->anchor(firstItem, firstEdge, secondItem, secondEdge); + QGraphicsAnchor *a = d->addAnchor(firstItem, firstEdge, secondItem, secondEdge); invalidate(); return a; } @@ -246,12 +246,12 @@ void QGraphicsAnchorLayout::addCornerAnchors(QGraphicsLayoutItem *firstItem, // Horizontal anchor Qt::AnchorPoint firstEdge = (firstCorner & 1 ? Qt::AnchorRight: Qt::AnchorLeft); Qt::AnchorPoint secondEdge = (secondCorner & 1 ? Qt::AnchorRight: Qt::AnchorLeft); - d->anchor(firstItem, firstEdge, secondItem, secondEdge); + d->addAnchor(firstItem, firstEdge, secondItem, secondEdge); // Vertical anchor firstEdge = (firstCorner & 2 ? Qt::AnchorBottom: Qt::AnchorTop); secondEdge = (secondCorner & 2 ? Qt::AnchorBottom: Qt::AnchorTop); - d->anchor(firstItem, firstEdge, secondItem, secondEdge); + d->addAnchor(firstItem, firstEdge, secondItem, secondEdge); invalidate(); } @@ -288,6 +288,18 @@ void QGraphicsAnchorLayout::addAnchors(QGraphicsLayoutItem *firstItem, } /*! + Returns true if there are no arrangement that satisfies all constraints. + Otherwise returns false. + + \sa addAnchor() +*/ +bool QGraphicsAnchorLayout::hasConflicts() const +{ + Q_D(const QGraphicsAnchorLayout); + return d->hasConflicts(); +} + +/*! Sets the default horizontal spacing for the anchor layout to \a spacing. \sa horizontalSpacing(), setVerticalSpacing(), setSpacing() @@ -422,7 +434,6 @@ void QGraphicsAnchorLayout::invalidate() */ QSizeF QGraphicsAnchorLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const { - Q_UNUSED(which); Q_UNUSED(constraint); Q_D(const QGraphicsAnchorLayout); diff --git a/src/gui/graphicsview/qgraphicsanchorlayout.h b/src/gui/graphicsview/qgraphicsanchorlayout.h index d9a87ba..44074d1 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout.h @@ -93,6 +93,7 @@ public: QGraphicsLayoutItem *secondItem, Qt::Orientations orientations = Qt::Horizontal | Qt::Vertical); + bool hasConflicts() const; void setHorizontalSpacing(qreal spacing); void setVerticalSpacing(qreal spacing); void setSpacing(qreal spacing); diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index a37ec96..7041d58 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -59,7 +59,7 @@ QGraphicsAnchorPrivate::QGraphicsAnchorPrivate(int version) QGraphicsAnchorPrivate::~QGraphicsAnchorPrivate() { - layoutPrivate->deleteAnchorData(data); + layoutPrivate->removeAnchor(data->from, data->to); } void QGraphicsAnchorPrivate::setSpacing(qreal value) @@ -95,23 +95,50 @@ qreal QGraphicsAnchorPrivate::spacing() const void AnchorData::refreshSizeHints(qreal effectiveSpacing) { if (!isLayoutAnchor && from->m_item == to->m_item) { - bool hasCenter = false; QGraphicsLayoutItem *item = from->m_item; - if (QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge) - == QGraphicsAnchorLayoutPrivate::Horizontal) { - minSize = item->minimumWidth(); - prefSize = item->preferredWidth(); - maxSize = item->maximumWidth(); - hasCenter = (from->m_edge == Qt::AnchorHorizontalCenter - || to->m_edge == Qt::AnchorHorizontalCenter); + const QGraphicsAnchorLayoutPrivate::Orientation orient = QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge); + const Qt::AnchorPoint centerEdge = QGraphicsAnchorLayoutPrivate::pickEdge(Qt::AnchorHorizontalCenter, orient); + + QSizePolicy::Policy policy; + qreal minSizeHint, prefSizeHint, maxSizeHint; + if (orient == QGraphicsAnchorLayoutPrivate::Horizontal) { + policy = item->sizePolicy().horizontalPolicy(); + minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).width(); + prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).width(); + maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).width(); } else { - minSize = item->minimumHeight(); - prefSize = item->preferredHeight(); - maxSize = item->maximumHeight(); - hasCenter = (from->m_edge == Qt::AnchorVerticalCenter - || to->m_edge == Qt::AnchorVerticalCenter); + policy = item->sizePolicy().verticalPolicy(); + minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).height(); + prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).height(); + maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).height(); } + // minSize, prefSize and maxSize are initialized + // with item's preferred Size: this is QSizePolicy::Fixed. + // + // Then we check each flag to find the resultant QSizePolicy, + // according to the following table: + // + // constant value + // QSizePolicy::Fixed 0 + // QSizePolicy::Minimum GrowFlag + // QSizePolicy::Maximum ShrinkFlag + // QSizePolicy::Preferred GrowFlag | ShrinkFlag + // QSizePolicy::Ignored GrowFlag | ShrinkFlag | IgnoreFlag + prefSize = prefSizeHint; + minSize = prefSize; + maxSize = prefSize; + + if (policy & QSizePolicy::GrowFlag) + maxSize = maxSizeHint; + + if (policy & QSizePolicy::ShrinkFlag) + minSize = minSizeHint; + + if (policy & QSizePolicy::IgnoreFlag) + prefSize = minSize; + + bool hasCenter = (from->m_edge == centerEdge || to->m_edge == centerEdge); if (hasCenter) { minSize /= 2; @@ -332,6 +359,7 @@ QGraphicsAnchorLayoutPrivate::QGraphicsAnchorLayoutPrivate() for (int i = 0; i < NOrientations; ++i) { spacings[i] = -1; graphSimplified[i] = false; + graphHasConflicts[i] = false; } } @@ -790,7 +818,7 @@ void QGraphicsAnchorLayoutPrivate::createLayoutEdges() // Horizontal AnchorData *data = new AnchorData(0, 0, QWIDGETSIZE_MAX); - addAnchor(layout, Qt::AnchorLeft, layout, + addAnchor_helper(layout, Qt::AnchorLeft, layout, Qt::AnchorRight, data); data->skipInPreferred = 1; @@ -800,7 +828,7 @@ void QGraphicsAnchorLayoutPrivate::createLayoutEdges() // Vertical data = new AnchorData(0, 0, QWIDGETSIZE_MAX); - addAnchor(layout, Qt::AnchorTop, layout, + addAnchor_helper(layout, Qt::AnchorTop, layout, Qt::AnchorBottom, data); data->skipInPreferred = 1; @@ -816,8 +844,10 @@ void QGraphicsAnchorLayoutPrivate::deleteLayoutEdges() Q_ASSERT(internalVertex(q, Qt::AnchorHorizontalCenter) == NULL); Q_ASSERT(internalVertex(q, Qt::AnchorVerticalCenter) == NULL); - removeAnchor(q, Qt::AnchorLeft, q, Qt::AnchorRight); - removeAnchor(q, Qt::AnchorTop, q, Qt::AnchorBottom); + removeAnchor_helper(internalVertex(q, Qt::AnchorLeft), + internalVertex(q, Qt::AnchorRight)); + removeAnchor_helper(internalVertex(q, Qt::AnchorTop), + internalVertex(q, Qt::AnchorBottom)); } void QGraphicsAnchorLayoutPrivate::createItemEdges(QGraphicsLayoutItem *item) @@ -826,22 +856,18 @@ void QGraphicsAnchorLayoutPrivate::createItemEdges(QGraphicsLayoutItem *item) items.append(item); - // Horizontal - int minimumSize = item->minimumWidth(); - int preferredSize = item->preferredWidth(); - int maximumSize = item->maximumWidth(); + QSizeF minSize = item->effectiveSizeHint(Qt::MinimumSize); + QSizeF prefSize = item->effectiveSizeHint(Qt::PreferredSize); + QSizeF maxSize = item->effectiveSizeHint(Qt::MaximumSize); - AnchorData *data = new AnchorData(minimumSize, preferredSize, maximumSize); - addAnchor(item, Qt::AnchorLeft, item, + // Horizontal + AnchorData *data = new AnchorData(minSize.width(), prefSize.width(), maxSize.width()); + addAnchor_helper(item, Qt::AnchorLeft, item, Qt::AnchorRight, data); // Vertical - minimumSize = item->minimumHeight(); - preferredSize = item->preferredHeight(); - maximumSize = item->maximumHeight(); - - data = new AnchorData(minimumSize, preferredSize, maximumSize); - addAnchor(item, Qt::AnchorTop, item, + data = new AnchorData(minSize.height(), prefSize.height(), maxSize.height()); + addAnchor_helper(item, Qt::AnchorTop, item, Qt::AnchorBottom, data); } @@ -897,23 +923,23 @@ void QGraphicsAnchorLayoutPrivate::createCenterAnchors( // Create new anchors AnchorData *oldData = graph[orientation].edgeData(first, last); - int minimumSize = oldData->minSize / 2; - int preferredSize = oldData->prefSize / 2; - int maximumSize = oldData->maxSize / 2; + qreal minimumSize = oldData->minSize / 2; + qreal preferredSize = oldData->prefSize / 2; + qreal maximumSize = oldData->maxSize / 2; QSimplexConstraint *c = new QSimplexConstraint; AnchorData *data = new AnchorData(minimumSize, preferredSize, maximumSize); c->variables.insert(data, 1.0); - addAnchor(item, firstEdge, item, centerEdge, data); + addAnchor_helper(item, firstEdge, item, centerEdge, data); data = new AnchorData(minimumSize, preferredSize, maximumSize); c->variables.insert(data, -1.0); - addAnchor(item, centerEdge, item, lastEdge, data); + addAnchor_helper(item, centerEdge, item, lastEdge, data); itemCenterConstraints[orientation].append(c); // Remove old one - removeAnchor(item, firstEdge, item, lastEdge); + removeAnchor_helper(first, last); } void QGraphicsAnchorLayoutPrivate::removeCenterAnchors( @@ -971,16 +997,16 @@ void QGraphicsAnchorLayoutPrivate::removeCenterAnchors( // Create the new anchor that should substitute the left-center-right anchors. AnchorData *oldData = g.edgeData(first, center); - int minimumSize = oldData->minSize * 2; - int preferredSize = oldData->prefSize * 2; - int maximumSize = oldData->maxSize * 2; + qreal minimumSize = oldData->minSize * 2; + qreal preferredSize = oldData->prefSize * 2; + qreal maximumSize = oldData->maxSize * 2; AnchorData *data = new AnchorData(minimumSize, preferredSize, maximumSize); - addAnchor(item, firstEdge, item, lastEdge, data); + addAnchor_helper(item, firstEdge, item, lastEdge, data); // Remove old anchors - removeAnchor(item, firstEdge, item, centerEdge); - removeAnchor(item, centerEdge, item, lastEdge); + removeAnchor_helper(first, center); + removeAnchor_helper(center, internalVertex(item, lastEdge)); } else { // this is only called from removeAnchors() @@ -989,13 +1015,13 @@ void QGraphicsAnchorLayoutPrivate::removeCenterAnchors( for (int i = 0; i < adjacents.count(); ++i) { AnchorVertex *v = adjacents.at(i); if (v->m_item != item) { - removeAnchor(item, centerEdge, v->m_item, v->m_edge); + removeAnchor_helper(center, internalVertex(v->m_item, v->m_edge)); } } // when all non-internal anchors is removed it will automatically merge the // center anchor into a left-right (or top-bottom) anchor. We must also delete that. // by this time, the center vertex is deleted and merged into a non-centered internal anchor - removeAnchor(item, firstEdge, item, lastEdge); + removeAnchor_helper(first, internalVertex(item, lastEdge)); } } @@ -1039,7 +1065,7 @@ void QGraphicsAnchorLayoutPrivate::removeCenterConstraints(QGraphicsLayoutItem * * Helper function that is called from the anchor functions in the public API. * If \a spacing is 0, it will pick up the spacing defined by the style. */ -QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::anchor(QGraphicsLayoutItem *firstItem, +QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge, QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge, @@ -1112,18 +1138,18 @@ QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::anchor(QGraphicsLayoutItem *first } else { data = new AnchorData(0); // spacing should be 0 } - addAnchor(firstItem, firstEdge, secondItem, secondEdge, data); + addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data); } else if (*spacing >= 0) { data = new AnchorData(*spacing); - addAnchor(firstItem, firstEdge, secondItem, secondEdge, data); + addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data); } else { data = new AnchorData(-*spacing); - addAnchor(secondItem, secondEdge, firstItem, firstEdge, data); + addAnchor_helper(secondItem, secondEdge, firstItem, firstEdge, data); } return acquireGraphicsAnchor(data); } -void QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *firstItem, +void QGraphicsAnchorLayoutPrivate::addAnchor_helper(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge, QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge, @@ -1142,8 +1168,9 @@ void QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *firstItem, // Remove previous anchor // ### Could we update the existing edgeData rather than creating a new one? - if (graph[edgeOrientation(firstEdge)].edgeData(v1, v2)) - removeAnchor(firstItem, firstEdge, secondItem, secondEdge); + if (graph[edgeOrientation(firstEdge)].edgeData(v1, v2)) { + removeAnchor_helper(v1, v2); + } // Create a bi-directional edge in the sense it can be transversed both // from v1 or v2. "data" however is shared between the two references @@ -1178,15 +1205,82 @@ QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::getAnchor(QGraphicsLayoutItem *fi return graphicsAnchor; } -void QGraphicsAnchorLayoutPrivate::removeAnchor(QGraphicsLayoutItem *firstItem, - Qt::AnchorPoint firstEdge, - QGraphicsLayoutItem *secondItem, - Qt::AnchorPoint secondEdge) +/*! + * \internal + * + * Implements the high level "removeAnchor" feature. Called by + * the QAnchorData destructor. + */ +void QGraphicsAnchorLayoutPrivate::removeAnchor(AnchorVertex *firstVertex, + AnchorVertex *secondVertex) { - removeAnchor_helper(internalVertex(firstItem, firstEdge), - internalVertex(secondItem, secondEdge)); + Q_Q(QGraphicsAnchorLayout); + + // Actually delete the anchor + removeAnchor_helper(firstVertex, secondVertex); + + QGraphicsLayoutItem *firstItem = firstVertex->m_item; + QGraphicsLayoutItem *secondItem = secondVertex->m_item; + + // Checking if the item stays in the layout or not + bool keepFirstItem = false; + bool keepSecondItem = false; + + QPair<AnchorVertex *, int> v; + int refcount = -1; + + if (firstItem != q) { + for (int i = Qt::AnchorLeft; i <= Qt::AnchorBottom; ++i) { + v = m_vertexList.value(qMakePair(firstItem, static_cast<Qt::AnchorPoint>(i))); + if (v.first) { + if (i == Qt::AnchorHorizontalCenter || i == Qt::AnchorVerticalCenter) + refcount = 2; + else + refcount = 1; + + if (v.second > refcount) { + keepFirstItem = true; + break; + } + } + } + } else + keepFirstItem = true; + + if (secondItem != q) { + for (int i = Qt::AnchorLeft; i <= Qt::AnchorBottom; ++i) { + v = m_vertexList.value(qMakePair(secondItem, static_cast<Qt::AnchorPoint>(i))); + if (v.first) { + if (i == Qt::AnchorHorizontalCenter || i == Qt::AnchorVerticalCenter) + refcount = 2; + else + refcount = 1; + + if (v.second > refcount) { + keepSecondItem = true; + break; + } + } + } + } else + keepSecondItem = true; + + if (!keepFirstItem) + q->removeAt(items.indexOf(firstItem)); + + if (!keepSecondItem) + q->removeAt(items.indexOf(secondItem)); + + // Removing anchors invalidates the layout + q->invalidate(); } +/* + \internal + + Implements the low level "removeAnchor" feature. Called by + private methods. +*/ void QGraphicsAnchorLayoutPrivate::removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2) { Q_ASSERT(v1 && v2); @@ -1207,17 +1301,6 @@ void QGraphicsAnchorLayoutPrivate::removeAnchor_helper(AnchorVertex *v1, AnchorV \internal Only called from outside. (calls invalidate()) */ -void QGraphicsAnchorLayoutPrivate::deleteAnchorData(AnchorData *data) -{ - Q_Q(QGraphicsAnchorLayout); - removeAnchor_helper(data->from, data->to); - q->invalidate(); -} - -/*! - \internal - Only called from outside. (calls invalidate()) -*/ void QGraphicsAnchorLayoutPrivate::setAnchorSize(AnchorData *data, const qreal *anchorSize) { Q_Q(QGraphicsAnchorLayout); @@ -1225,12 +1308,35 @@ void QGraphicsAnchorLayoutPrivate::setAnchorSize(AnchorData *data, const qreal * // search recursively through all composite anchors Q_ASSERT(data); restoreSimplifiedGraph(edgeOrientation(data->from->m_edge)); + + QGraphicsLayoutItem *firstItem = data->from->m_item; + QGraphicsLayoutItem *secondItem = data->to->m_item; + Qt::AnchorPoint firstEdge = data->from->m_edge; + Qt::AnchorPoint secondEdge = data->to->m_edge; + + // Use heuristics to find out what the user meant with this anchor. + correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge); + if (data->from->m_item != firstItem) + qSwap(data->from, data->to); + if (anchorSize) { - data->setFixedSize(*anchorSize); + // ### The current implementation makes "setAnchorSize" behavior + // dependent on the argument order for cases where we have + // no heuristic. Ie. two widgets, same anchor point. + + // We cannot have negative sizes inside the graph. This would cause + // the simplex solver to fail because all simplex variables are + // positive by definition. + // "negative spacing" is handled by inverting the standard item order. + if (*anchorSize >= 0) { + data->setFixedSize(*anchorSize); + } else { + data->setFixedSize(-*anchorSize); + qSwap(data->from, data->to); + } } else { data->unsetSize(); } - q->invalidate(); } @@ -1360,25 +1466,23 @@ void QGraphicsAnchorLayoutPrivate::correctEdgeDirection(QGraphicsLayoutItem *&fi { Q_Q(QGraphicsAnchorLayout); - Qt::AnchorPoint effectiveFirst = firstEdge; - Qt::AnchorPoint effectiveSecond = secondEdge; - - if (firstItem == q) - effectiveFirst = QGraphicsAnchorLayoutPrivate::oppositeEdge(firstEdge); - if (secondItem == q) - effectiveSecond = QGraphicsAnchorLayoutPrivate::oppositeEdge(secondEdge); - - if (effectiveFirst < effectiveSecond) { - - // ### DEBUG - /* printf("Swapping Anchor from %s %d --to--> %s %d\n", - firstItem->isLayout() ? "<layout>" : - qPrintable(static_cast<QGraphicsWidget *>(firstItem)->data(0).toString()), - firstEdge, - secondItem->isLayout() ? "<layout>" : - qPrintable(static_cast<QGraphicsWidget *>(secondItem)->data(0).toString()), - secondEdge); - */ + if ((firstItem != q) && (secondItem != q)) { + // If connection is between widgets (not the layout itself) + // Ensure that "right-edges" sit to the left of "left-edges". + if (firstEdge < secondEdge) { + qSwap(firstItem, secondItem); + qSwap(firstEdge, secondEdge); + } + } else if (firstItem == q) { + // If connection involves the right or bottom of a layout, ensure + // the layout is the second item. + if ((firstEdge == Qt::AnchorRight) || (firstEdge == Qt::AnchorBottom)) { + qSwap(firstItem, secondItem); + qSwap(firstEdge, secondEdge); + } + } else if ((secondEdge != Qt::AnchorRight) && (secondEdge != Qt::AnchorBottom)) { + // If connection involves the left, center or top of layout, ensure + // the layout is the first item. qSwap(firstItem, secondItem); qSwap(firstEdge, secondEdge); } @@ -1507,6 +1611,7 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( AnchorVertex *v = internalVertex(q, pickEdge(Qt::AnchorRight, orientation)); GraphPath trunkPath = graphPaths[orientation].value(v); + bool feasible = true; if (!trunkConstraints.isEmpty()) { #if 0 qDebug("Simplex used for trunk of %s", @@ -1514,33 +1619,37 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( #endif // Solve min and max size hints for trunk - QPair<qreal, qreal> minMax = solveMinMax(trunkConstraints, trunkPath); - sizeHints[orientation][Qt::MinimumSize] = minMax.first; - sizeHints[orientation][Qt::MaximumSize] = minMax.second; + qreal min, max; + feasible = solveMinMax(trunkConstraints, trunkPath, &min, &max); // Solve for preferred. The objective function is calculated from the constraints // and variables internally. - solvePreferred(trunkConstraints); + feasible &= solvePreferred(trunkConstraints); - // Propagate the new sizes down the simplified graph, ie. tell the - // group anchors to set their children anchors sizes. + if (feasible) { + // Propagate the new sizes down the simplified graph, ie. tell the + // group anchors to set their children anchors sizes. - // ### we calculated variables already a few times, can't we reuse that? - QList<AnchorData *> trunkVariables = getVariables(trunkConstraints); + // ### we calculated variables already a few times, can't we reuse that? + QList<AnchorData *> trunkVariables = getVariables(trunkConstraints); - for (int i = 0; i < trunkVariables.count(); ++i) - trunkVariables.at(i)->updateChildrenSizes(); + for (int i = 0; i < trunkVariables.count(); ++i) + trunkVariables.at(i)->updateChildrenSizes(); + + // Calculate and set the preferred size for the layout from the edge sizes that + // were calculated above. + qreal pref(0.0); + foreach (const AnchorData *ad, trunkPath.positives) { + pref += ad->sizeAtPreferred; + } + foreach (const AnchorData *ad, trunkPath.negatives) { + pref -= ad->sizeAtPreferred; + } + sizeHints[orientation][Qt::MinimumSize] = min; + sizeHints[orientation][Qt::PreferredSize] = pref; + sizeHints[orientation][Qt::MaximumSize] = max; - // Calculate and set the preferred size for the layout from the edge sizes that - // were calculated above. - qreal pref(0.0); - foreach (const AnchorData *ad, trunkPath.positives) { - pref += ad->sizeAtPreferred; - } - foreach (const AnchorData *ad, trunkPath.negatives) { - pref -= ad->sizeAtPreferred; } - sizeHints[orientation][Qt::PreferredSize] = pref; } else { #if 0 qDebug("Simplex NOT used for trunk of %s", @@ -1574,29 +1683,34 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( // layout. // Solve the other only for preferred, skip trunk - for (int i = 1; i < parts.count(); ++i) { - QList<QSimplexConstraint *> partConstraints = parts[i]; - QList<AnchorData *> partVariables = getVariables(partConstraints); - Q_ASSERT(!partVariables.isEmpty()); - - sizeHintConstraints = constraintsFromSizeHints(partVariables); - partConstraints += sizeHintConstraints; - solvePreferred(partConstraints); - - // Propagate size at preferred to other sizes. Semi-floats - // always will be in their sizeAtPreferred. - for (int j = 0; j < partVariables.count(); ++j) { - AnchorData *ad = partVariables[j]; - Q_ASSERT(ad); - ad->sizeAtMinimum = ad->sizeAtPreferred; - ad->sizeAtMaximum = ad->sizeAtPreferred; - ad->updateChildrenSizes(); - } + if (feasible) { + for (int i = 1; i < parts.count(); ++i) { + QList<QSimplexConstraint *> partConstraints = parts[i]; + QList<AnchorData *> partVariables = getVariables(partConstraints); + Q_ASSERT(!partVariables.isEmpty()); + + sizeHintConstraints = constraintsFromSizeHints(partVariables); + partConstraints += sizeHintConstraints; + feasible &= solvePreferred(partConstraints); + if (!feasible) + break; + + // Propagate size at preferred to other sizes. Semi-floats + // always will be in their sizeAtPreferred. + for (int j = 0; j < partVariables.count(); ++j) { + AnchorData *ad = partVariables[j]; + Q_ASSERT(ad); + ad->sizeAtMinimum = ad->sizeAtPreferred; + ad->sizeAtMaximum = ad->sizeAtPreferred; + ad->updateChildrenSizes(); + } - // Delete the constraints, we won't use them anymore. - qDeleteAll(sizeHintConstraints); - sizeHintConstraints.clear(); + // Delete the constraints, we won't use them anymore. + qDeleteAll(sizeHintConstraints); + sizeHintConstraints.clear(); + } } + graphHasConflicts[orientation] = !feasible; // Clean up our data structures. They are not needed anymore since // distribution uses just interpolation. @@ -2061,47 +2175,48 @@ void QGraphicsAnchorLayoutPrivate::interpolateSequentialEdges( interpolateEdge(prev, data->m_edges.last(), orientation); } -QPair<qreal, qreal> -QGraphicsAnchorLayoutPrivate::solveMinMax(QList<QSimplexConstraint *> constraints, - GraphPath path) +bool QGraphicsAnchorLayoutPrivate::solveMinMax(QList<QSimplexConstraint *> constraints, + GraphPath path, qreal *min, qreal *max) { QSimplex simplex; - simplex.setConstraints(constraints); - - // Obtain the objective constraint - QSimplexConstraint objective; - QSet<AnchorData *>::const_iterator iter; - for (iter = path.positives.constBegin(); iter != path.positives.constEnd(); ++iter) - objective.variables.insert(*iter, 1.0); - - for (iter = path.negatives.constBegin(); iter != path.negatives.constEnd(); ++iter) - objective.variables.insert(*iter, -1.0); - - simplex.setObjective(&objective); - - // Calculate minimum values - qreal min = simplex.solveMin(); - - // Save sizeAtMinimum results - QList<QSimplexVariable *> variables = simplex.constraintsVariables(); - for (int i = 0; i < variables.size(); ++i) { - AnchorData *ad = static_cast<AnchorData *>(variables[i]); - ad->sizeAtMinimum = ad->result; - } + bool feasible = simplex.setConstraints(constraints); + if (feasible) { + // Obtain the objective constraint + QSimplexConstraint objective; + QSet<AnchorData *>::const_iterator iter; + for (iter = path.positives.constBegin(); iter != path.positives.constEnd(); ++iter) + objective.variables.insert(*iter, 1.0); + + for (iter = path.negatives.constBegin(); iter != path.negatives.constEnd(); ++iter) + objective.variables.insert(*iter, -1.0); + + simplex.setObjective(&objective); + + // Calculate minimum values + *min = simplex.solveMin(); + + // Save sizeAtMinimum results + QList<QSimplexVariable *> variables = simplex.constraintsVariables(); + for (int i = 0; i < variables.size(); ++i) { + AnchorData *ad = static_cast<AnchorData *>(variables[i]); + Q_ASSERT(ad->result >= ad->minSize || qFuzzyCompare(ad->result, ad->minSize)); + ad->sizeAtMinimum = ad->result; + } - // Calculate maximum values - qreal max = simplex.solveMax(); + // Calculate maximum values + *max = simplex.solveMax(); - // Save sizeAtMaximum results - for (int i = 0; i < variables.size(); ++i) { - AnchorData *ad = static_cast<AnchorData *>(variables[i]); - ad->sizeAtMaximum = ad->result; + // Save sizeAtMaximum results + for (int i = 0; i < variables.size(); ++i) { + AnchorData *ad = static_cast<AnchorData *>(variables[i]); + Q_ASSERT(ad->result <= ad->maxSize || qFuzzyCompare(ad->result, ad->maxSize)); + ad->sizeAtMaximum = ad->result; + } } - - return qMakePair<qreal, qreal>(min, max); + return feasible; } -void QGraphicsAnchorLayoutPrivate::solvePreferred(QList<QSimplexConstraint *> constraints) +bool QGraphicsAnchorLayoutPrivate::solvePreferred(QList<QSimplexConstraint *> constraints) { QList<AnchorData *> variables = getVariables(constraints); QList<QSimplexConstraint *> preferredConstraints; @@ -2148,25 +2263,35 @@ void QGraphicsAnchorLayoutPrivate::solvePreferred(QList<QSimplexConstraint *> co QSimplex *simplex = new QSimplex; - simplex->setConstraints(constraints + preferredConstraints); - simplex->setObjective(&objective); - - // Calculate minimum values - simplex->solveMin(); + bool feasible = simplex->setConstraints(constraints + preferredConstraints); + if (feasible) { + simplex->setObjective(&objective); - // Save sizeAtPreferred results - for (int i = 0; i < variables.size(); ++i) { - AnchorData *ad = static_cast<AnchorData *>(variables[i]); - ad->sizeAtPreferred = ad->result; - } + // Calculate minimum values + simplex->solveMin(); - // Make sure we delete the simplex solver -before- we delete the - // constraints used by it. - delete simplex; + // Save sizeAtPreferred results + for (int i = 0; i < variables.size(); ++i) { + AnchorData *ad = static_cast<AnchorData *>(variables[i]); + ad->sizeAtPreferred = ad->result; + } + // Make sure we delete the simplex solver -before- we delete the + // constraints used by it. + delete simplex; + } // Delete constraints and variables we created. qDeleteAll(preferredConstraints); qDeleteAll(preferredVariables); + + return feasible; +} + +bool QGraphicsAnchorLayoutPrivate::hasConflicts() const +{ + QGraphicsAnchorLayoutPrivate *that = const_cast<QGraphicsAnchorLayoutPrivate*>(this); + that->calculateGraphs(); + return graphHasConflicts[0] || graphHasConflicts[1]; } #ifdef QT_DEBUG diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index f701c3f..4e1bcd4 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -403,15 +403,15 @@ public: return data->graphicsAnchor; } - // helper function used by the 4 API functions - QGraphicsAnchor *anchor(QGraphicsLayoutItem *firstItem, + // function used by the 4 API functions + QGraphicsAnchor *addAnchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge, QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge, qreal *spacing = 0); - // Anchor Manipulation methods - void addAnchor(QGraphicsLayoutItem *firstItem, + // Helper for Anchor Manipulation methods + void addAnchor_helper(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge, QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge, @@ -420,12 +420,8 @@ public: QGraphicsAnchor *getAnchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge, QGraphicsLayoutItem *secondItem, Qt::AnchorPoint secondEdge); - void removeAnchor(QGraphicsLayoutItem *firstItem, - Qt::AnchorPoint firstEdge, - QGraphicsLayoutItem *secondItem, - Qt::AnchorPoint secondEdge); + void removeAnchor(AnchorVertex *firstVertex, AnchorVertex *secondVertex); void removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2); - void deleteAnchorData(AnchorData *data); void setAnchorSize(AnchorData *data, const qreal *anchorSize); void anchorSize(const AnchorData *data, qreal *minSize = 0, @@ -482,9 +478,10 @@ public: Orientation orientation); // Linear Programming solver methods - QPair<qreal, qreal> solveMinMax(QList<QSimplexConstraint *> constraints, - GraphPath path); - void solvePreferred(QList<QSimplexConstraint *> constraints); + bool solveMinMax(QList<QSimplexConstraint *> constraints, + GraphPath path, qreal *min, qreal *max); + bool solvePreferred(QList<QSimplexConstraint *> constraints); + bool hasConflicts() const; #ifdef QT_DEBUG void dumpGraph(); @@ -518,6 +515,7 @@ public: // ### bool graphSimplified[2]; + bool graphHasConflicts[2]; uint calculateGraphCacheDirty : 1; }; diff --git a/src/gui/graphicsview/qsimplex_p.cpp b/src/gui/graphicsview/qsimplex_p.cpp index 3bd6b5a..e3a991e 100644 --- a/src/gui/graphicsview/qsimplex_p.cpp +++ b/src/gui/graphicsview/qsimplex_p.cpp @@ -84,12 +84,12 @@ void QSimplex::clearDataStructures() objective = 0; } -void QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints) +bool QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints) { clearDataStructures(); if (newConstraints.isEmpty()) - return; + return true; // we are ok with no constraints constraints = newConstraints; // Set Variables direct mapping @@ -153,7 +153,7 @@ void QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints) matrix = (qreal *)malloc(sizeof(qreal) * columns * rows); if (!matrix) { qWarning() << "QSimplex: Unable to allocate memory!"; - return; + return false; } for (int i = columns * rows - 1; i >= 0; --i) matrix[i] = 0.0; @@ -198,11 +198,12 @@ void QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints) if (valueAt(0, columns - 1) != 0.0) { qWarning() << "QSimplex: No feasible solution!"; clearDataStructures(); - return; + return false; } // Remove artificial variables clearColumns(firstArtificial, columns - 2); + return true; } void QSimplex::solveMaxHelper() diff --git a/src/gui/graphicsview/qsimplex_p.h b/src/gui/graphicsview/qsimplex_p.h index 805ef4a..54b080d 100644 --- a/src/gui/graphicsview/qsimplex_p.h +++ b/src/gui/graphicsview/qsimplex_p.h @@ -107,7 +107,7 @@ public: qreal solveMax(); QList<QSimplexVariable *> constraintsVariables(); - void setConstraints(const QList<QSimplexConstraint *> constraints); + bool setConstraints(const QList<QSimplexConstraint *> constraints); void setObjective(QSimplexConstraint *objective); void dumpMatrix(); diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 7c24002..83ac5fe 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -54,4 +54,4 @@ DEFINES += Q_INTERNAL_QAPP_SRC symbian:TARGET.UID3=0x2001B2DD # ro-section in gui can exceed default allocated space, so more rw-section little further -symbian-sbsv2: MMP_RULES += "LINKEROPTION armcc --rw-base 0x800000" +symbian-sbsv2: MMP_RULES += "LINKEROPTION armcc --rw-base 0x800000"
\ No newline at end of file diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index 0970385..b67be55 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -24,7 +24,7 @@ HEADERS += \ image/qpixmap.h \ image/qpixmap_raster_p.h \ image/qpixmapcache.h \ - image/qpixmapcache_p.h \ + image/qpixmapcache_p.h \ image/qpixmapdata_p.h \ image/qpixmapdatafactory_p.h \ image/qpixmapfilter_p.h \ @@ -70,6 +70,7 @@ mac { SOURCES += image/qpixmap_mac.cpp } symbian { + HEADERS += image/qpixmap_s60_p.h SOURCES += image/qpixmap_s60.cpp } diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index eb38b85..4f145af 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -1557,8 +1557,8 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) premultiplied alpha format. If the image has an alpha channel, and if the system allows, the preferred format is premultiplied alpha. Note also that QPixmap, unlike QImage, may be hardware dependent. - On X11 and Mac, a QPixmap is stored on the server side while a - QImage is stored on the client side (on Windows, these two classes + On X11, Mac and Symbian, a QPixmap is stored on the server side while + a QImage is stored on the client side (on Windows, these two classes have an equivalent internal representation, i.e. both QImage and QPixmap are stored on the client side and don't use any GDI resources). @@ -1577,7 +1577,8 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) screen. Alternatively, if no manipulation is desired, the image file can be loaded directly into a QPixmap. On Windows, the QPixmap class also supports conversion between \c HBITMAP and - QPixmap. + QPixmap. On Symbian, the QPixmap class also supports conversion + between CFbsBitmap and QPixmap. QPixmap provides a collection of functions that can be used to obtain a variety of information about the pixmap. In addition, @@ -1682,6 +1683,12 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) returns the HBITMAP handle. The fromWinHBITMAP() function returns a QPixmap that is equivalent to the given bitmap which has the specified format. + + In addition, on Symbian, the QPixmap class supports conversion to + and from CFbsBitmap: the toSymbianCFbsBitmap() function creates + CFbsBitmap equivalent to the QPixmap, based on given mode and returns + a CFbsBitmap object. The fromSymbianCFbsBitmap() function returns a + QPixmap that is equivalent to the given bitmap and given mode. \section1 Pixmap Transformations diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index 1eaafdc..54e89ff 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -54,6 +54,7 @@ QT_BEGIN_HEADER #if defined(Q_OS_SYMBIAN) class CFbsBitmap; +class RSgImage; #endif QT_BEGIN_NAMESPACE @@ -157,8 +158,12 @@ public: #endif #if defined(Q_OS_SYMBIAN) - CFbsBitmap *toSymbianCFbsBitmap() const; - static QPixmap fromSymbianCFbsBitmap(CFbsBitmap *bitmap); + enum ConversionMode { CopyData, DuplicateHandle }; + + CFbsBitmap *toSymbianCFbsBitmap(ConversionMode mode = DuplicateHandle) const; + static QPixmap fromSymbianCFbsBitmap(CFbsBitmap *bitmap, ConversionMode mode = DuplicateHandle); + RSgImage* toSymbianRSgImage() const; + static QPixmap fromSymbianRSgImage(RSgImage *sgImage); #endif inline QPixmap copy(int x, int y, int width, int height) const; @@ -254,6 +259,7 @@ private: friend class QPixmapData; friend class QX11PixmapData; friend class QMacPixmapData; + friend class QS60PixmapData; friend class QBitmap; friend class QPaintDevice; friend class QPainter; diff --git a/src/gui/image/qpixmap_raster_p.h b/src/gui/image/qpixmap_raster_p.h index 5add5ed..2af2399 100644 --- a/src/gui/image/qpixmap_raster_p.h +++ b/src/gui/image/qpixmap_raster_p.h @@ -83,13 +83,13 @@ public: protected: int metric(QPaintDevice::PaintDeviceMetric metric) const; + QImage image; private: friend class QPixmap; friend class QBitmap; friend class QDetachedPixmap; friend class QRasterPaintEngine; - QImage image; }; QT_END_NAMESPACE diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp index 666e557..303e923 100644 --- a/src/gui/image/qpixmap_s60.cpp +++ b/src/gui/image/qpixmap_s60.cpp @@ -42,14 +42,217 @@ #include <w32std.h> #include <fbs.h> +#include <private/qapplication_p.h> +#include <private/qgraphicssystem_p.h> #include <private/qt_s60_p.h> +#include <private/qpaintengine_s60_p.h> + #include "qpixmap.h" #include "qpixmap_raster_p.h" #include <qwidget.h> +#include "qpixmap_s60_p.h" +#include "qnativeimage_p.h" +#include "qbitmap.h" +#include "qimage.h" +#include "qimage_p.h" + +#include <fbs.h> QT_BEGIN_NAMESPACE -QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h ) +const uchar qt_pixmap_bit_mask[] = { 0x01, 0x02, 0x04, 0x08, + 0x10, 0x20, 0x40, 0x80 }; + + + +/*! + \since 4.6 + + Symbian Font And Bitmap server client that is + used to lock the global bitmap heap. Only used in + S60 v3.1 and S60 v3.2. +*/ +class QSymbianFbsClient +{ +public: + + QSymbianFbsClient() : heapLock(0), heapLocked(false) + { + QT_TRAP_THROWING(heapLock = new(ELeave) CFbsBitmap); + heapLock->Create(TSize(0,0), S60->screenDevice()->DisplayMode()); + } + + ~QSymbianFbsClient() + { + delete heapLock; + } + + bool lockHeap() + { + bool wasLocked = heapLocked; + + if (heapLock && !heapLocked) { + heapLock->LockHeap(ETrue); + heapLocked = true; + } + + return wasLocked; + } + + bool unlockHeap() + { + bool wasLocked = heapLocked; + + if (heapLock && heapLocked) { + heapLock->UnlockHeap(ETrue); + heapLocked = false; + } + + return wasLocked; + } + + +private: + + CFbsBitmap *heapLock; + bool heapLocked; +}; + +Q_GLOBAL_STATIC(QSymbianFbsClient, qt_symbianFbsClient); + + + +// QSymbianFbsHeapLock + +QSymbianFbsHeapLock::QSymbianFbsHeapLock(LockAction a) +: action(a), wasLocked(false) +{ + QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion(); + if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3) + wasLocked = qt_symbianFbsClient()->unlockHeap(); +} + +QSymbianFbsHeapLock::~QSymbianFbsHeapLock() +{ + // Do nothing +} + +void QSymbianFbsHeapLock::relock() +{ + QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion(); + if (wasLocked && (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3)) + qt_symbianFbsClient()->lockHeap(); +} + +/*! + \since 4.6 + + Data access class that is used to locks/unlocks pixel data + when drawing or modifying CFbsBitmap pixel data. +*/ +class QSymbianBitmapDataAccess +{ +public: + + bool heapWasLocked; + QSysInfo::SymbianVersion symbianVersion; + + explicit QSymbianBitmapDataAccess() : heapWasLocked(false) + { + symbianVersion = QSysInfo::symbianVersion(); + }; + + ~QSymbianBitmapDataAccess() {}; + + inline void beginDataAccess(CFbsBitmap *bitmap) + { + if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3) + heapWasLocked = qt_symbianFbsClient()->lockHeap(); + else + bitmap->LockHeap(ETrue); + } + + inline void endDataAccess(CFbsBitmap *bitmap) + { + if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3) { + if (!heapWasLocked) + qt_symbianFbsClient()->unlockHeap(); + } else { + bitmap->UnlockHeap(ETrue); + } + } +}; + + +#define UPDATE_BUFFER() \ + { \ + beginDataAccess(); \ + endDataAccess(); \ +} + + +static CFbsBitmap* createSymbianCFbsBitmap(const TSize& size, TDisplayMode mode) +{ + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + + CFbsBitmap* bitmap = 0; + QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap); + + if (bitmap->Create(size, mode) != KErrNone) { + delete bitmap; + bitmap = 0; + } + + lock.relock(); + + return bitmap; +} + +static CFbsBitmap* uncompress(CFbsBitmap* bitmap) +{ + if(bitmap->IsCompressedInRAM()) { + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + + CFbsBitmap *uncompressed = 0; + QT_TRAP_THROWING(uncompressed = new (ELeave) CFbsBitmap); + + if (uncompressed->Create(bitmap->SizeInPixels(), bitmap->DisplayMode()) != KErrNone) { + delete bitmap; + bitmap = 0; + lock.relock(); + + return bitmap; + } + + lock.relock(); + + CBitmapContext *bitmapContext = 0; + CFbsBitmapDevice* bitmapDevice = 0; + QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(uncompressed)); + TInt err = bitmapDevice->CreateBitmapContext(bitmapContext); + if (err != KErrNone) { + delete bitmap; + delete bitmapDevice; + bitmap = 0; + bitmapDevice = 0; + + lock.relock(); + + return bitmap; + } + + bitmapContext->DrawBitmap(TPoint(), bitmap); + + delete bitmapContext; + delete bitmapDevice; + + return uncompressed; + } else { + return bitmap; + } +} + +QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h) { CWsScreenDevice* screenDevice = S60->screenDevice(); TSize screenSize = screenDevice->SizeInPixels(); @@ -81,164 +284,674 @@ QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h ) if (srcRect.IsEmpty()) return QPixmap(); - TDisplayMode displayMode = screenDevice->DisplayMode(); - CFbsBitmap* temporary = q_check_ptr(new CFbsBitmap()); // CBase derived object needs check on new - TInt error = temporary->Create(srcRect.Size(), displayMode); - if (error == KErrNone) - error = screenDevice->CopyScreenToBitmap(temporary, srcRect); + CFbsBitmap* temporary = createSymbianCFbsBitmap(srcRect.Size(), screenDevice->DisplayMode()); - if (error != KErrNone) { - CBase::Delete(temporary); - return QPixmap(); + QPixmap pix; + + if (temporary && screenDevice->CopyScreenToBitmap(temporary, srcRect) == KErrNone) { + pix = QPixmap::fromSymbianCFbsBitmap(temporary); } - QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(temporary); - CBase::Delete(temporary); - return pixmap; + delete temporary; + return pix; } /*! -\since 4.6 + \enum QPixmap::ConversionMode -Returns a \c CFbsBitmap that is equivalent to the QPixmap by copying the data. + \bold{Symbian only:} This enum defines how the conversion between \c + CFbsBitmap and QPixmap is performed. -It is the caller's responsibility to delete the \c CFbsBitmap after use. + \warning This enum is only available on Symbian. -\warning This function is only available on Symbian OS. + \value CopyData Copied CFbsBitmap data. + + \value DuplicateHandle Duplicates CFbsBitmap handle. This also means + that pixmap data will be explicitly shared. -\sa fromSymbianCFbsBitmap() + \sa fromSymbianCFbsBitmap(), toSymbianCFbsBitmap() */ -CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const + +/*! + \fn CFbsBitmap *QPixmap::toSymbianCFbsBitmap(ConversionMode mode) + \since 4.6 + + Creates \c CFbsBitmap that is equivalent to the QPixmap, based on + the given \a mode. If the creation then this function returns 0. + + It is the caller's responsibility to release the \c CFbsBitmap data + after use either by deleting the bitmap or calling \c Reset(). + + \warning On S60 3.1 and S60 3.2 conversion mode will always be CopyData + if QPixmap pixels have alpha values. + \warning This function is only available on Symbian OS. + + \sa fromSymbianCFbsBitmap() +*/ +CFbsBitmap *QPixmap::toSymbianCFbsBitmap(ConversionMode mode) const { - if (isNull()) + QS60PixmapData *s60data = static_cast<QS60PixmapData *>(data.data()); + + if (isNull() || !s60data->cfbsBitmap) return 0; + bool convertToArgb32 = false; + + QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion(); + if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3) { + // Convert argb32_premultiplied to argb32 since Symbian 9.2 and Symbian 9.3 do + // not support premultipied format. + + if (s60data->image.format() == QImage::Format_ARGB32_Premultiplied) { + mode = CopyData; + convertToArgb32 = true; + } + } + + CFbsBitmap *bitmap = 0; + + TDisplayMode displayMode = s60data->cfbsBitmap->DisplayMode(); + + if(displayMode == EGray2) { + //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid + //So invert mono bitmaps so that masks work correctly. + s60data->image.invertPixels(); + mode = CopyData; + } + + if (mode == CopyData) { + QImage source; + + if (convertToArgb32) { + source = s60data->image.convertToFormat(QImage::Format_ARGB32); + displayMode = EColor16MA; + } else { + source = s60data->image; + } + + CFbsBitmap *newBitmap = createSymbianCFbsBitmap(TSize(source.width(), source.height()), displayMode); + const uchar *sptr = source.bits(); + s60data->symbianBitmapDataAccess->beginDataAccess(newBitmap); + + uchar *dptr = (uchar*)newBitmap->DataAddress(); + Mem::Copy(dptr, sptr, source.numBytes()); + + s60data->symbianBitmapDataAccess->endDataAccess(newBitmap); + + bitmap = newBitmap; + } else { + + QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap); + + TInt err = bitmap->Duplicate(s60data->cfbsBitmap->Handle()); + if (err != KErrNone) { + qWarning("Could not duplicate CFbsBitmap"); + delete bitmap; + bitmap = 0; + } + } + + if(displayMode == EGray2) { + // restore pixels + s60data->image.invertPixels(); + } + + return bitmap; +} + +/*! + \fn QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap, ConversionMode mode) + \since 4.6 + + Creates a QPixmap from native \c CFbsBitmap \a bitmap. The conversion + is based on the specified \a mode. Conversion mode is always QPixmap::CopyData + if given \a bitmap does not have display mode of TDisplayMode::EGray2, + \c TDisplayMode::EColor16MU or \c TDisplayMode::EColor16MAP. + + If the CFbsBitmap is not valid this function will return a null QPixmap. + + \warning This function is only available on Symbian OS. + + \sa toSymbianCFbsBitmap(), {QPixmap#Pixmap Conversion}{Pixmap Conversion} +*/ +QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap, ConversionMode mode) +{ + if (bitmap) { + + bool deleteSourceBitmap = false; + +#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE + + // Rasterize extended bitmaps + + TUid extendedBitmapType = bitmap->ExtendedBitmapType(); + if (extendedBitmapType != KNullUid) { + CFbsBitmap *rasterBitmap = createSymbianCFbsBitmap(bitmap->SizeInPixels(), EColor16MA); + + CFbsBitmapDevice *rasterBitmapDev = 0; + QT_TRAP_THROWING(rasterBitmapDev = CFbsBitmapDevice::NewL(rasterBitmap)); + + CFbsBitGc *rasterBitmapGc = 0; + TInt err = rasterBitmapDev->CreateContext(rasterBitmapGc); + if (err != KErrNone) { + delete rasterBitmap; + delete rasterBitmapDev; + rasterBitmapDev = 0; + return QPixmap(); + } + + rasterBitmapGc->BitBlt(TPoint( 0, 0), bitmap); + + bitmap = rasterBitmap; + + delete rasterBitmapDev; + delete rasterBitmapGc; + + rasterBitmapDev = 0; + rasterBitmapGc = 0; + + deleteSourceBitmap = true; + } +#endif + + + deleteSourceBitmap = bitmap->IsCompressedInRAM(); + CFbsBitmap *sourceBitmap = uncompress(bitmap); + + TDisplayMode displayMode = sourceBitmap->DisplayMode(); + QImage::Format format = qt_TDisplayMode2Format(displayMode); + + QImage::Format opaqueFormat = QNativeImage::systemFormat(); + QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied; + + if (format != opaqueFormat && format != alphaFormat && format != QImage::Format_MonoLSB) + mode = CopyData; + + + QPixmapData::PixelType type = (format!=QImage::Format_MonoLSB) + ? QPixmapData::PixmapType + : QPixmapData::BitmapType; + + QS60PixmapData *pixmapData = 0; + + if (mode == CopyData) { + + TSize size = sourceBitmap->SizeInPixels(); + + QSymbianBitmapDataAccess da; + da.beginDataAccess(sourceBitmap); + uchar *bytes = (uchar*)sourceBitmap->DataAddress(); + QImage img = QImage(bytes, size.iWidth, size.iHeight, format); + da.endDataAccess(sourceBitmap); + + pixmapData = new QS60PixmapData(type); + pixmapData->fromImage(img, Qt::AutoColor); + + if(deleteSourceBitmap) + delete sourceBitmap; + + if(displayMode == EGray2) { + //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid + //So invert mono bitmaps so that masks work correctly. + pixmapData->image.invertPixels(); + } + } else { + CFbsBitmap* duplicate = 0; + QT_TRAP_THROWING(duplicate = new (ELeave) CFbsBitmap); + + TInt err = duplicate->Duplicate(sourceBitmap->Handle()); + if (err != KErrNone) { + qWarning("Could not duplicate CFbsBitmap"); + + if(deleteSourceBitmap) + delete sourceBitmap; + + delete duplicate; + return QPixmap(); + } + + pixmapData = new QS60PixmapData(type); + pixmapData->fromSymbianBitmap(duplicate); + + if(deleteSourceBitmap) + delete sourceBitmap; + } + + return QPixmap(pixmapData); + } + + return QPixmap(); +} + +QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type), + symbianBitmapDataAccess(new QSymbianBitmapDataAccess), + cfbsBitmap(0), + bitmapDevice(0), + bitmapContext(0), + pengine(0), + bytes(0) +{ + +} + +QS60PixmapData::~QS60PixmapData() +{ + release(); +} + +void QS60PixmapData::resize(int width, int height) +{ + if (width <= 0 || height <= 0) { + w = width; + h = height; + is_null = true; + + release(); + return; + } else if (!cfbsBitmap) { + TDisplayMode mode; + if (pixelType() == BitmapType) + mode = EGray2; + else + mode = EColor16MU; + + CFbsBitmap* bitmap = createSymbianCFbsBitmap(TSize(width, height), mode); + fromSymbianBitmap(bitmap); + } else { + + TSize newSize(width, height); + + if(cfbsBitmap->SizeInPixels() != newSize) { + cfbsBitmap->Resize(TSize(width, height)); + if(pengine) { + delete pengine; + pengine = 0; + } + } + + UPDATE_BUFFER(); + } +} + +bool QS60PixmapData::initSymbianBitmapContext() +{ + QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(cfbsBitmap)); + TInt err = bitmapDevice->CreateBitmapContext(bitmapContext); + if (err != KErrNone) { + delete bitmapDevice; + bitmapDevice = 0; + return false; + } + return true; +} + +void QS60PixmapData::release() +{ + if (cfbsBitmap) { + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + delete bitmapContext; + delete bitmapDevice; + delete cfbsBitmap; + lock.relock(); + } + + delete pengine; + image = QImage(); + cfbsBitmap = 0; + bitmapContext = 0; + bitmapDevice = 0; + pengine = 0; + bytes = 0; +} + +/*! + * Takes ownership of bitmap + */ +void QS60PixmapData::fromSymbianBitmap(CFbsBitmap* bitmap) +{ + cfbsBitmap = bitmap; + + if(!initSymbianBitmapContext()) { + qWarning("Could not create CBitmapContext"); + release(); + return; + } + + setSerialNumber(cfbsBitmap->Handle()); + + UPDATE_BUFFER(); + + // Create default palette if needed + if (cfbsBitmap->DisplayMode() == EGray2) { + image.setNumColors(2); + image.setColor(0, QColor(Qt::color0).rgba()); + image.setColor(1, QColor(Qt::color1).rgba()); + + //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid + //So invert mono bitmaps so that masks work correctly. + image.invertPixels(); + } else if (cfbsBitmap->DisplayMode() == EGray256) { + for (int i=0; i < 256; ++i) + image.setColor(i, qRgb(i, i, i)); + }else if (cfbsBitmap->DisplayMode() == EColor256) { + const TColor256Util *palette = TColor256Util::Default(); + for (int i=0; i < 256; ++i) + image.setColor(i, (QRgb)(palette->Color256(i).Value())); + } +} + +void QS60PixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags) +{ + QImage sourceImage; + + if (pixelType() == BitmapType) { + sourceImage = img.convertToFormat(QImage::Format_MonoLSB); + } else { + if (img.depth() == 1) { + image = img.hasAlphaChannel() + ? img.convertToFormat(QImage::Format_ARGB32_Premultiplied) + : img.convertToFormat(QImage::Format_RGB32); + } else { + + QImage::Format opaqueFormat = QNativeImage::systemFormat(); + QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied; + + if (!img.hasAlphaChannel() + || ((flags & Qt::NoOpaqueDetection) == 0 + && !const_cast<QImage &>(img).data_ptr()->checkForAlphaPixels())) { + sourceImage = img.convertToFormat(opaqueFormat); + } else { + sourceImage = img.convertToFormat(alphaFormat); + } + } + } + + + QImage::Format destFormat = sourceImage.format(); TDisplayMode mode; - const QImage img = toImage(); - QImage::Format destFormat = img.format(); - switch (img.format()) { - case QImage::Format_Mono: - destFormat = QImage::Format_MonoLSB; - // Fall through intended + switch (destFormat) { case QImage::Format_MonoLSB: mode = EGray2; break; - case QImage::Format_Indexed8: - if (img.isGrayscale()) - mode = EGray256; - else - mode = EColor256; - break; case QImage::Format_RGB32: mode = EColor16MU; break; - case QImage::Format_ARGB6666_Premultiplied: - case QImage::Format_ARGB8565_Premultiplied: - case QImage::Format_ARGB8555_Premultiplied: - destFormat = QImage::Format_ARGB32_Premultiplied; - // Fall through intended case QImage::Format_ARGB32_Premultiplied: #if !defined(__SERIES60_31__) && !defined(__S60_32__) - // ### TODO: Add runtime detection as well? mode = EColor16MAP; - break; + break; #endif destFormat = QImage::Format_ARGB32; // Fall through intended case QImage::Format_ARGB32: mode = EColor16MA; break; - case QImage::Format_RGB555: - destFormat = QImage::Format_RGB16; - // Fall through intended - case QImage::Format_RGB16: - mode = EColor64K; - break; - case QImage::Format_RGB666: - destFormat = QImage::Format_RGB888; - // Fall through intended - case QImage::Format_RGB888: - mode = EColor16M; - break; - case QImage::Format_RGB444: - mode = EColor4K; - break; case QImage::Format_Invalid: - return 0; + return; default: - qWarning("Image format not supported: %d", img.format()); - return 0; + qWarning("Image format not supported: %d", image.format()); + return; } - CFbsBitmap* bitmap = q_check_ptr(new CFbsBitmap()); // CBase derived object needs check on new - TSize size(width(), height()); - if (bitmap->Create(size, mode) != KErrNone) { - CBase::Delete(bitmap); + cfbsBitmap = createSymbianCFbsBitmap(TSize(sourceImage.width(), sourceImage.height()), mode); + if (!(cfbsBitmap && initSymbianBitmapContext())) { + qWarning("Could not create CFbsBitmap and/or CBitmapContext"); + release(); + return; + } + + setSerialNumber(cfbsBitmap->Handle()); + + const uchar *sptr = const_cast<const QImage &>(sourceImage).bits(); + symbianBitmapDataAccess->beginDataAccess(cfbsBitmap); + uchar *dptr = (uchar*)cfbsBitmap->DataAddress(); + Mem::Copy(dptr, sptr, sourceImage.numBytes()); + symbianBitmapDataAccess->endDataAccess(cfbsBitmap); + + UPDATE_BUFFER(); + + if (destFormat == QImage::Format_MonoLSB) { + image.setNumColors(2); + image.setColor(0, QColor(Qt::color0).rgba()); + image.setColor(1, QColor(Qt::color1).rgba()); + } else { + image.setColorTable(sourceImage.colorTable()); + } +} + +void QS60PixmapData::copy(const QPixmapData *data, const QRect &rect) +{ + if (data->pixelType() == BitmapType) { + QBitmap::fromImage(data->toImage().copy(rect)); + return; + } + + const QS60PixmapData *s60Data = static_cast<const QS60PixmapData*>(data); + + resize(rect.width(), rect.height()); + cfbsBitmap->SetDisplayMode(s60Data->cfbsBitmap->DisplayMode()); + + bitmapContext->BitBlt(TPoint(0, 0), s60Data->cfbsBitmap, qt_QRect2TRect(rect)); +} + +bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect) +{ + bitmapContext->CopyRect(TPoint(dx, dy), qt_QRect2TRect(rect)); + return true; +} + +int QS60PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const +{ + if (!cfbsBitmap) return 0; + + switch (metric) { + case QPaintDevice::PdmWidth: + return cfbsBitmap->SizeInPixels().iWidth; + case QPaintDevice::PdmHeight: + return cfbsBitmap->SizeInPixels().iHeight; + case QPaintDevice::PdmWidthMM: { + TInt twips = cfbsBitmap->SizeInTwips().iWidth; + return (int)(twips * (25.4/KTwipsPerInch)); + } + case QPaintDevice::PdmHeightMM: { + TInt twips = cfbsBitmap->SizeInTwips().iHeight; + return (int)(twips * (25.4/KTwipsPerInch)); + } + case QPaintDevice::PdmNumColors: + return TDisplayModeUtils::NumDisplayModeColors(cfbsBitmap->DisplayMode()); + case QPaintDevice::PdmDpiX: + case QPaintDevice::PdmPhysicalDpiX: { + TReal inches = cfbsBitmap->SizeInTwips().iWidth / (TReal)KTwipsPerInch; + TInt pixels = cfbsBitmap->SizeInPixels().iWidth; + return pixels / inches; + } + case QPaintDevice::PdmDpiY: + case QPaintDevice::PdmPhysicalDpiY: { + TReal inches = cfbsBitmap->SizeInTwips().iHeight / (TReal)KTwipsPerInch; + TInt pixels = cfbsBitmap->SizeInPixels().iHeight; + return pixels / inches; + } + case QPaintDevice::PdmDepth: + return TDisplayModeUtils::NumDisplayModeBitsPerPixel(cfbsBitmap->DisplayMode()); + default: + qWarning("QPixmap::metric: Invalid metric command"); + } + return 0; + +} + +void QS60PixmapData::fill(const QColor &color) +{ + if (color.alpha() != 255) { + QImage im(width(), height(), QImage::Format_ARGB32_Premultiplied); + im.fill(PREMUL(color.rgba())); + release(); + fromImage(im, Qt::AutoColor | Qt::OrderedAlphaDither); + } else { + beginDataAccess(); + QRasterPixmapData::fill(color); + endDataAccess(); } +} + +void QS60PixmapData::setMask(const QBitmap &mask) +{ + if (mask.size().isEmpty()) { + if (image.depth() != 1) { + QImage newImage = image.convertToFormat(QImage::Format_RGB32); + release(); + fromImage(newImage, Qt::AutoColor | Qt::OrderedAlphaDither); + } + } else if (image.depth() == 1) { + beginDataAccess(); + QRasterPixmapData::setMask(mask); + endDataAccess(); + } else { + const int w = image.width(); + const int h = image.height(); - QImage converted = img.convertToFormat(destFormat); + const QImage imageMask = mask.toImage().convertToFormat(QImage::Format_MonoLSB); + QImage newImage = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + for (int y = 0; y < h; ++y) { + const uchar *mscan = imageMask.scanLine(y); + QRgb *tscan = (QRgb *)newImage.scanLine(y); + for (int x = 0; x < w; ++x) { + if (!(mscan[x>>3] & qt_pixmap_bit_mask[x&7])) + tscan[x] = 0; + } + } + release(); + fromImage(newImage, Qt::AutoColor | Qt::OrderedAlphaDither); + } +} - //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid - //So invert mono bitmaps so that masks work correctly. - if (mode == EGray2) - converted.invertPixels(); +void QS60PixmapData::setAlphaChannel(const QPixmap &alphaChannel) +{ + QImage img(toImage()); + img.setAlphaChannel(alphaChannel.toImage()); + release(); + fromImage(img, Qt::OrderedDither | Qt::OrderedAlphaDither); +} - bitmap->LockHeap(); - const uchar *sptr = converted.bits(); - uchar *dptr = (uchar*)bitmap->DataAddress(); - Mem::Copy(dptr, sptr, converted.numBytes()); - bitmap->UnlockHeap(); - return bitmap; +QImage QS60PixmapData::toImage() const +{ + return image; +} + +QPaintEngine* QS60PixmapData::paintEngine() const +{ + if (!pengine) { + QS60PixmapData *that = const_cast<QS60PixmapData*>(this); + that->pengine = new QS60PaintEngine(&that->image, that); + } + return pengine; +} + +void QS60PixmapData::beginDataAccess() +{ + if(!cfbsBitmap) + return; + + symbianBitmapDataAccess->beginDataAccess(cfbsBitmap); + + uchar* newBytes = (uchar*)cfbsBitmap->DataAddress(); + + if (newBytes == bytes) + return; + + + bytes = newBytes; + TDisplayMode mode = cfbsBitmap->DisplayMode(); + QImage::Format format = qt_TDisplayMode2Format(mode); + TSize size = cfbsBitmap->SizeInPixels(); + + QVector<QRgb> savedColorTable; + if (!image.isNull()) + savedColorTable = image.colorTable(); + + image = QImage(bytes, size.iWidth, size.iHeight, format); + + // Restore the palette or create a default + if (!savedColorTable.isEmpty()) { + image.setColorTable(savedColorTable); + } + + w = size.iWidth; + h = size.iHeight; + d = image.depth(); + is_null = (w <= 0 || h <= 0); + + if (pengine) { + QS60PaintEngine *engine = static_cast<QS60PaintEngine *>(pengine); + engine->prepare(&image); + } +} + +void QS60PixmapData::endDataAccess(bool readOnly) const +{ + if(!cfbsBitmap) + return; + + symbianBitmapDataAccess->endDataAccess(cfbsBitmap); } /*! \since 4.6 - Returns a QPixmap that is equivalent to the \c CFbsBitmap \a bitmap - by copying the data. If the CFbsBitmap is not valid or is compressed - in memory, this function will return a null QPixmap. + Returns a QPixmap that wraps given \c RSgImage \a graphics resource. + The data should be valid even when original RSgImage handle has been + closed. \warning This function is only available on Symbian OS. - \sa toSymbianCFbsBitmap(), {QPixmap#Pixmap Conversion}{Pixmap Conversion} + \sa toSymbianRSgImage(), {QPixmap#Pixmap Conversion}{Pixmap Conversion} */ -QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap) +QPixmap QPixmap::fromSymbianRSgImage(RSgImage *sgImage) { - if (!bitmap) - return QPixmap(); - - int width = bitmap->SizeInPixels().iWidth; - int height = bitmap->SizeInPixels().iHeight; + // It is expected that RSgImage will + // CURRENTLY be used in conjuction with + // OpenVG graphics system + // + // Surely things might change in future - if (width <= 0 || height <= 0 || bitmap->IsCompressedInRAM()) + if (!sgImage) return QPixmap(); - TDisplayMode displayMode = bitmap->DisplayMode(); - QImage::Format format = qt_TDisplayMode2Format(displayMode); - int bytesPerLine = CFbsBitmap::ScanLineLength(width, displayMode); - bitmap->LockHeap(); - QImage image = QImage((const uchar*)bitmap->DataAddress(), width, height, bytesPerLine, format); - if (displayMode == EGray2) { - image.setNumColors(2); - image.setColor(0, QColor(Qt::color0).rgba()); - image.setColor(1, QColor(Qt::color1).rgba()); - //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid - //So invert mono bitmaps so that masks work correctly. - image.invertPixels(); - } else if (displayMode == EGray256) { - for (int i=0; i < 256; ++i) - image.setColor(i, qRgb(i, i, i)); - }else if (displayMode == EColor256) { - const TColor256Util *palette = TColor256Util::Default(); - for (int i=0; i < 256; ++i) - image.setColor(i, (QRgb)(palette->Color256(i).Value())); - } - QPixmap pixmap = QPixmap::fromImage(image.copy()); - bitmap->UnlockHeap(); + QPixmap pixmap; + pixmap.pixmapData()->fromRSgImage(sgImage); + return pixmap; } +/*! +\since 4.6 + +Returns a \c RSgImage that is equivalent to the QPixmap by copying the data. + +It is the caller's responsibility to close/delete the \c RSgImage after use. + +\warning This function is only available on Symbian OS. + +\sa fromSymbianRSgImage() +*/ + +RSgImage *QPixmap::toSymbianRSgImage() const +{ + // It is expected that RSgImage will + // CURRENTLY be used in conjuction with + // OpenVG graphics system + // + // Surely things might change in future + + if (isNull()) + return 0; + + RSgImage *sgImage = pixmapData()->toRSgImage(); + + return sgImage; +} + QT_END_NAMESPACE diff --git a/src/gui/image/qpixmap_s60_p.h b/src/gui/image/qpixmap_s60_p.h new file mode 100644 index 0000000..b56b270 --- /dev/null +++ b/src/gui/image/qpixmap_s60_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QPIXMAPDATA_S60_P_H +#define QPIXMAPDATA_S60_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGui/private/qpixmap_raster_p.h> + +QT_BEGIN_NAMESPACE + +class CFbsBitmap; +class CFbsBitmapDevice; +class CBitmapContext; + +class QSymbianBitmapDataAccess; + +class QSymbianFbsHeapLock +{ +public: + + enum LockAction { + Unlock + }; + + explicit QSymbianFbsHeapLock(LockAction a); + ~QSymbianFbsHeapLock(); + void relock(); + +private: + + LockAction action; + bool wasLocked; +}; + +class QS60PixmapData : public QRasterPixmapData +{ +public: + QS60PixmapData(PixelType type); + ~QS60PixmapData(); + + void resize(int width, int height); + void fromImage(const QImage &image, Qt::ImageConversionFlags flags); + void copy(const QPixmapData *data, const QRect &rect); + bool scroll(int dx, int dy, const QRect &rect); + + int metric(QPaintDevice::PaintDeviceMetric metric) const; + void fill(const QColor &color); + void setMask(const QBitmap &mask); + void setAlphaChannel(const QPixmap &alphaChannel); + QImage toImage() const; + QPaintEngine* paintEngine() const; + + void beginDataAccess(); + void endDataAccess(bool readOnly=false) const; + +private: + void release(); + void fromSymbianBitmap(CFbsBitmap* bitmap); + bool initSymbianBitmapContext(); + + QSymbianBitmapDataAccess *symbianBitmapDataAccess; + + CFbsBitmap *cfbsBitmap; + CFbsBitmapDevice *bitmapDevice; + CBitmapContext *bitmapContext; + QPaintEngine *pengine; + uchar* bytes; + + friend class QPixmap; + friend class QS60WindowSurface; + friend class QS60PaintEngine; + friend class QS60Data; +}; + +QT_END_NAMESPACE + +#endif // QPIXMAPDATA_S60_P_H + diff --git a/src/gui/image/qpixmapdata.cpp b/src/gui/image/qpixmapdata.cpp index 8ce5447..65899a4 100644 --- a/src/gui/image/qpixmapdata.cpp +++ b/src/gui/image/qpixmapdata.cpp @@ -223,4 +223,15 @@ QImage* QPixmapData::buffer() return 0; } +#if defined(Q_OS_SYMBIAN) +RSgImage* QPixmapData::toRSgImage() +{ + return 0; +} + +void QPixmapData::fromRSgImage(RSgImage* rsgImage) +{ + return; +} +#endif QT_END_NAMESPACE diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h index 0af2af8..bac5065 100644 --- a/src/gui/image/qpixmapdata_p.h +++ b/src/gui/image/qpixmapdata_p.h @@ -56,6 +56,10 @@ #include <QtGui/qpixmap.h> #include <QtCore/qatomic.h> +#if defined(Q_OS_SYMBIAN) +class RSgImage; +#endif + QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QPixmapData @@ -109,6 +113,11 @@ public: inline int depth() const { return d; } inline bool isNull() const { return is_null; } +#if defined(Q_OS_SYMBIAN) + virtual RSgImage* toRSgImage(); + virtual void fromRSgImage(RSgImage* rsgImage); +#endif + protected: void setSerialNumber(int serNo); int w; diff --git a/src/gui/image/qpixmapdatafactory.cpp b/src/gui/image/qpixmapdatafactory.cpp index e3d2e6c..806883d 100644 --- a/src/gui/image/qpixmapdatafactory.cpp +++ b/src/gui/image/qpixmapdatafactory.cpp @@ -47,12 +47,15 @@ #ifdef Q_WS_X11 # include <private/qpixmap_x11_p.h> #endif -#if defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) +#if defined(Q_WS_WIN) # include <private/qpixmap_raster_p.h> #endif #ifdef Q_WS_MAC # include <private/qpixmap_mac_p.h> #endif +#ifdef Q_WS_S60 +# include <private/qpixmap_s60_p.h> +#endif #include "private/qapplication_p.h" #include "private/qgraphicssystem_p.h" @@ -75,10 +78,12 @@ QPixmapData* QSimplePixmapDataFactory::create(QPixmapData::PixelType type) #if defined(Q_WS_X11) return new QX11PixmapData(type); -#elif defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) +#elif defined(Q_WS_WIN) return new QRasterPixmapData(type); #elif defined(Q_WS_MAC) return new QMacPixmapData(type); +#elif defined(Q_WS_S60) + return new QS60PixmapData(type); #else #error QSimplePixmapDataFactory::create() not implemented #endif diff --git a/src/gui/image/qpixmapfilter.cpp b/src/gui/image/qpixmapfilter.cpp index 4fa2e6c..4fb650f 100644 --- a/src/gui/image/qpixmapfilter.cpp +++ b/src/gui/image/qpixmapfilter.cpp @@ -418,13 +418,12 @@ void QPixmapConvolutionFilter::draw(QPainter *painter, const QPointF &p, const Q return; QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ? - static_cast<QPaintEngineEx *>(painter->paintEngine())->createPixmapFilter(type()) : 0; + static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0; QPixmapConvolutionFilter *convolutionFilter = static_cast<QPixmapConvolutionFilter*>(filter); if (convolutionFilter) { convolutionFilter->setConvolutionKernel(d->convolutionKernel, d->kernelWidth, d->kernelHeight); convolutionFilter->d_func()->convoluteAlpha = d->convoluteAlpha; convolutionFilter->draw(painter, p, src, srcRect); - delete convolutionFilter; return; } @@ -669,13 +668,12 @@ void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap } QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ? - static_cast<QPaintEngineEx *>(painter->paintEngine())->createPixmapFilter(type()) : 0; + static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0; QPixmapBlurFilter *blurFilter = static_cast<QPixmapBlurFilter*>(filter); if (blurFilter) { blurFilter->setRadius(d->radius); blurFilter->setQuality(d->quality); blurFilter->draw(painter, p, src, srcRect); - delete blurFilter; return; } @@ -836,13 +834,12 @@ void QPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const Q { Q_D(const QPixmapColorizeFilter); QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ? - static_cast<QPaintEngineEx *>(painter->paintEngine())->createPixmapFilter(type()) : 0; + static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0; QPixmapColorizeFilter *colorizeFilter = static_cast<QPixmapColorizeFilter*>(filter); if (colorizeFilter) { colorizeFilter->setColor(d->color); colorizeFilter->setStrength(d->strength); colorizeFilter->draw(painter, dest, src, srcRect); - delete colorizeFilter; return; } diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 9d977a5..757ded9 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -69,6 +69,7 @@ QAbstractItemViewPrivate::QAbstractItemViewPrivate() : model(QAbstractItemModelPrivate::staticEmptyModel()), itemDelegate(0), selectionModel(0), + ctrlDragSelectionFlag(QItemSelectionModel::NoUpdate), selectionMode(QAbstractItemView::ExtendedSelection), selectionBehavior(QAbstractItemView::SelectItems), currentlyCommittingEditor(0), @@ -1589,6 +1590,11 @@ void QAbstractItemView::mousePressEvent(QMouseEvent *event) d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate); d->autoScroll = autoScroll; QRect rect(d->pressedPosition - offset, pos); + if (command.testFlag(QItemSelectionModel::Toggle)) { + command &= ~QItemSelectionModel::Toggle; + d->ctrlDragSelectionFlag = d->selectionModel->isSelected(index) ? QItemSelectionModel::Deselect : QItemSelectionModel::Select; + command |= d->ctrlDragSelectionFlag; + } setSelection(rect, command); // signal handlers may change the model @@ -1659,6 +1665,10 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) if ((event->buttons() & Qt::LeftButton) && d->selectionAllowed(index) && d->selectionModel) { setState(DragSelectingState); QItemSelectionModel::SelectionFlags command = selectionCommand(index, event); + if (command.testFlag(QItemSelectionModel::Toggle)) { + command &= ~QItemSelectionModel::Toggle; + command |= d->ctrlDragSelectionFlag; + } // Do the normalize ourselves, since QRect::normalized() is flawed QRect selectionRect = QRect(topLeft, bottomRight); @@ -1699,6 +1709,8 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event) EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers); bool edited = edit(index, trigger, event); + d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate; + //in the case the user presses on no item we might decide to clear the selection if (d->selectionModel && !index.isValid()) d->selectionModel->select(QModelIndex(), selectionCommand(index, event)); diff --git a/src/gui/itemviews/qabstractitemview_p.h b/src/gui/itemviews/qabstractitemview_p.h index 725d0a9..6b1ec8e 100644 --- a/src/gui/itemviews/qabstractitemview_p.h +++ b/src/gui/itemviews/qabstractitemview_p.h @@ -342,6 +342,7 @@ public: QMap<int, QPointer<QAbstractItemDelegate> > rowDelegates; QMap<int, QPointer<QAbstractItemDelegate> > columnDelegates; QPointer<QItemSelectionModel> selectionModel; + QItemSelectionModel::SelectionFlag ctrlDragSelectionFlag; QAbstractItemView::SelectionMode selectionMode; QAbstractItemView::SelectionBehavior selectionBehavior; diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp index 684da3f..f1ffaa6 100644 --- a/src/gui/itemviews/qtableview.cpp +++ b/src/gui/itemviews/qtableview.cpp @@ -2519,9 +2519,21 @@ void QTableViewPrivate::selectRow(int row, bool anchor) QModelIndex index = model->index(row, column, root); QItemSelectionModel::SelectionFlags command = q->selectionCommand(index); selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate); - if ((!(command & QItemSelectionModel::Current) && anchor) + if ((anchor && !(command & QItemSelectionModel::Current)) || (q->selectionMode() == QTableView::SingleSelection)) rowSectionAnchor = row; + + if (q->selectionMode() != QTableView::SingleSelection + && command.testFlag(QItemSelectionModel::Toggle)) { + if (anchor) + ctrlDragSelectionFlag = verticalHeader->selectionModel()->selectedRows().contains(index) + ? QItemSelectionModel::Deselect : QItemSelectionModel::Select; + command &= ~QItemSelectionModel::Toggle; + command |= ctrlDragSelectionFlag; + if (!anchor) + command |= QItemSelectionModel::Current; + } + QModelIndex tl = model->index(qMin(rowSectionAnchor, row), 0, root); QModelIndex br = model->index(qMax(rowSectionAnchor, row), model->columnCount(root) - 1, root); if (verticalHeader->sectionsMoved() && tl.row() != br.row()) @@ -2545,9 +2557,21 @@ void QTableViewPrivate::selectColumn(int column, bool anchor) QModelIndex index = model->index(row, column, root); QItemSelectionModel::SelectionFlags command = q->selectionCommand(index); selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate); - if ((!(command & QItemSelectionModel::Current) && anchor) + if ((anchor && !(command & QItemSelectionModel::Current)) || (q->selectionMode() == QTableView::SingleSelection)) columnSectionAnchor = column; + + if (q->selectionMode() != QTableView::SingleSelection + && command.testFlag(QItemSelectionModel::Toggle)) { + if (anchor) + ctrlDragSelectionFlag = horizontalHeader->selectionModel()->selectedColumns().contains(index) + ? QItemSelectionModel::Deselect : QItemSelectionModel::Select; + command &= ~QItemSelectionModel::Toggle; + command |= ctrlDragSelectionFlag; + if (!anchor) + command |= QItemSelectionModel::Current; + } + QModelIndex tl = model->index(0, qMin(columnSectionAnchor, column), root); QModelIndex br = model->index(model->rowCount(root) - 1, qMax(columnSectionAnchor, column), root); diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 1fd2d39..0ff7314 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -4773,7 +4773,7 @@ void QApplicationPrivate::emitLastWindowClosed() #ifdef QT_KEYPAD_NAVIGATION /*! - Sets what kind of focus navigation Qt should use. + Sets the kind of focus navigation Qt should use to \a mode. This feature is available in Qt for Embedded Linux, Symbian and Windows CE only. diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index fd889fc..6a381f5 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -439,7 +439,7 @@ void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) } } S60->lastCursorPos = globalPos; -#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS +#if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS) if (S60->brokenPointerCursors) qt_symbian_move_cursor_sprite(); #endif @@ -855,7 +855,6 @@ void qt_init(QApplicationPrivate * /* priv */, int) //Check if mouse interaction is supported (either EMouse=1 in the HAL, or EMachineUID is one of the phones known to support this) const TInt KMachineUidSamsungI8510 = 0x2000C51E; - const TInt KMachineUidSamsungI550 = 0x2000A678; TInt machineUID; TInt mouse; TInt touch; @@ -888,6 +887,7 @@ void qt_init(QApplicationPrivate * /* priv */, int) QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional; } +#ifndef QT_NO_CURSOR //Check if window server pointer cursors are supported or not #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS //In generic binary, use the HAL and OS version @@ -912,6 +912,7 @@ void qt_init(QApplicationPrivate * /* priv */, int) #endif S60->wsSession().SetPointerCursorMode(EPointerCursorNormal); } +#endif /* ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag @@ -1275,7 +1276,7 @@ int QApplication::s60ProcessEvent(TWsEvent *event) } break; case EEventFocusGained: - RDebug::Printf("focus gained %x", control); +#ifndef QT_NO_CURSOR //re-enable mouse interaction if (S60->mouseInteractionEnabled) { #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS @@ -1285,9 +1286,10 @@ int QApplication::s60ProcessEvent(TWsEvent *event) #endif S60->wsSession().SetPointerCursorMode(EPointerCursorNormal); } +#endif break; case EEventFocusLost: - RDebug::Printf("focus lost %x", control); +#ifndef QT_NO_CURSOR //disable mouse as may be moving to application that does not support it if (S60->mouseInteractionEnabled) { #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS @@ -1297,6 +1299,7 @@ int QApplication::s60ProcessEvent(TWsEvent *event) #endif S60->wsSession().SetPointerCursorMode(EPointerCursorNone); } +#endif break; default: break; @@ -1534,7 +1537,9 @@ void QApplication::restoreOverrideCursor() QListIterator<WId> iter(QWidgetPrivate::mapper->uniqueKeys()); while (iter.hasNext()) { CCoeControl *ctrl = iter.next(); - ctrl->DrawableWindow()->ClearPointerCursor(); + if(ctrl->OwnsWindow()) { + ctrl->DrawableWindow()->ClearPointerCursor(); + } } if (w) qt_symbian_setWindowCursor(w->cursor(), w->effectiveWinId()); diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 601cd11..bbce438 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -190,10 +190,12 @@ static const char * x11_atomnames = { "TARGETS\0" "MULTIPLE\0" "TIMESTAMP\0" + "SAVE_TARGETS\0" "CLIP_TEMPORARY\0" "_QT_SELECTION\0" "_QT_CLIPBOARD_SENTINEL\0" "_QT_SELECTION_SENTINEL\0" + "CLIPBOARD_MANAGER\0" "RESOURCE_MANAGER\0" diff --git a/src/gui/kernel/qclipboard_x11.cpp b/src/gui/kernel/qclipboard_x11.cpp index b2f682b..9621944 100644 --- a/src/gui/kernel/qclipboard_x11.cpp +++ b/src/gui/kernel/qclipboard_x11.cpp @@ -787,6 +787,7 @@ static Atom send_targets_selection(QClipboardData *d, Window window, Atom proper types.append(ATOM(TARGETS)); types.append(ATOM(MULTIPLE)); types.append(ATOM(TIMESTAMP)); + types.append(ATOM(SAVE_TARGETS)); XChangeProperty(X11->display, window, property, XA_ATOM, 32, PropModeReplace, (uchar *) types.data(), types.size()); @@ -911,8 +912,31 @@ bool QClipboard::event(QEvent *e) XEvent *xevent = (XEvent *)(((QClipboardEvent *)e)->data()); Display *dpy = X11->display; - if (!xevent) + if (!xevent) { + // That means application exits and we need to give clipboard + // content to the clipboard manager. + // First we check if there is a clipboard manager. + if (XGetSelectionOwner(X11->display, ATOM(CLIPBOARD_MANAGER)) == XNone + || !owner) + return true; + + Window ownerId = owner->internalWinId(); + Q_ASSERT(ownerId); + // we delete the property so the manager saves all TARGETS. + XDeleteProperty(X11->display, ownerId, ATOM(_QT_SELECTION)); + XConvertSelection(X11->display, ATOM(CLIPBOARD_MANAGER), ATOM(SAVE_TARGETS), + ATOM(_QT_SELECTION), ownerId, X11->time); + XSync(dpy, false); + + XEvent event; + // waiting until the clipboard manager fetches the content. + if (!X11->clipboardWaitForEvent(ownerId, SelectionNotify, &event, 10000)) { + qWarning("QClipboard: Unable to receive an event from the " + "clipboard manager in a reasonable time"); + } + return true; + } switch (xevent->type) { diff --git a/src/gui/kernel/qcursor_s60.cpp b/src/gui/kernel/qcursor_s60.cpp index 757eaa8..0d8283d 100644 --- a/src/gui/kernel/qcursor_s60.cpp +++ b/src/gui/kernel/qcursor_s60.cpp @@ -52,8 +52,10 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_CURSOR static QCursor cursorSprite; -static int cursorSpriteVisible; +static int cursorSpriteVisible; +#endif //pos and setpos are required whether cursors are configured or not. QPoint QCursor::pos() @@ -520,8 +522,10 @@ void qt_symbian_setGlobalCursor(const QCursor &cursor) while(iter.hasNext()) { CCoeControl *ctrl = iter.next(); - RWindowTreeNode *node = ctrl->DrawableWindow(); - qt_symbian_setWindowGroupCursor(cursor, *node); + if(ctrl->OwnsWindow()) { + RWindowTreeNode *node = ctrl->DrawableWindow(); + qt_symbian_setWindowGroupCursor(cursor, *node); + } } } } diff --git a/src/gui/kernel/qdnd_s60.cpp b/src/gui/kernel/qdnd_s60.cpp index 2456185..3d6ecd2 100644 --- a/src/gui/kernel/qdnd_s60.cpp +++ b/src/gui/kernel/qdnd_s60.cpp @@ -214,11 +214,13 @@ bool QDragManager::eventFilter(QObject *o, QEvent *e) case QEvent::MouseButtonRelease: { qApp->removeEventFilter(this); +#ifndef QT_NO_CURSOR if (restoreCursor) { QApplication::restoreOverrideCursor(); willDrop = false; restoreCursor = false; } +#endif if (object && object->target()) { QMouseEvent *me = (QMouseEvent *)e; @@ -267,7 +269,9 @@ Qt::DropAction QDragManager::drag(QDrag *o) updatePixmap(); updateCursor(); +#ifndef QT_NO_CURSOR qt_symbian_set_cursor_visible(true); //force cursor on even for touch phone +#endif object->d_func()->target = 0; @@ -282,10 +286,12 @@ Qt::DropAction QDragManager::drag(QDrag *o) delete eventLoop; eventLoop = 0; +#ifndef QT_NO_CURSOR qt_symbian_set_cursor_visible(false); overrideCursor = QCursor(); //deref the cursor data qt_symbian_dnd_dragging = false; +#endif return global_accepted_action; } @@ -306,10 +312,12 @@ void QDragManager::cancel(bool deleteSource) drag_object = object = 0; } +#ifndef QT_NO_CURSOR if (restoreCursor) { QApplication::restoreOverrideCursor(); restoreCursor = false; } +#endif global_accepted_action = Qt::IgnoreAction; } @@ -317,10 +325,12 @@ void QDragManager::cancel(bool deleteSource) void QDragManager::drop() { +#ifndef QT_NO_CURSOR if (restoreCursor) { QApplication::restoreOverrideCursor(); restoreCursor = false; } +#endif } QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type type) const diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index 794d15a..b43c950 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -108,7 +108,7 @@ public: bool virtualMouseRequired; int qtOwnsS60Environment : 1; static inline void updateScreenSize(); - static inline RWsSession& wsSession(); + static inline RWsSession& wsSession(); static inline RWindowGroup& windowGroup(); static inline CWsScreenDevice* screenDevice(); static inline CCoeAppUi* appUi(); @@ -284,7 +284,7 @@ static inline QImage::Format qt_TDisplayMode2Format(TDisplayMode mode) format = QImage::Format_RGB16; break; case EColor16M: - format = QImage::Format_RGB666; + format = QImage::Format_RGB888; break; case EColor16MU: format = QImage::Format_RGB32; @@ -304,11 +304,13 @@ static inline QImage::Format qt_TDisplayMode2Format(TDisplayMode mode) return format; } +#ifndef QT_NO_CURSOR void qt_symbian_setWindowCursor(const QCursor &cursor, const CCoeControl* wid); void qt_symbian_setWindowGroupCursor(const QCursor &cursor, RWindowTreeNode &node); void qt_symbian_setGlobalCursor(const QCursor &cursor); void qt_symbian_set_cursor_visible(bool visible); bool qt_symbian_is_cursor_visible(); +#endif QT_END_NAMESPACE diff --git a/src/gui/kernel/qt_x11_p.h b/src/gui/kernel/qt_x11_p.h index 1b02ed3..61acbac 100644 --- a/src/gui/kernel/qt_x11_p.h +++ b/src/gui/kernel/qt_x11_p.h @@ -544,10 +544,12 @@ struct QX11Data TARGETS, MULTIPLE, TIMESTAMP, + SAVE_TARGETS, CLIP_TEMPORARY, _QT_SELECTION, _QT_CLIPBOARD_SENTINEL, _QT_SELECTION_SENTINEL, + CLIPBOARD_MANAGER, RESOURCE_MANAGER, diff --git a/src/gui/kernel/qtooltip.cpp b/src/gui/kernel/qtooltip.cpp index a480195..2d0d209 100644 --- a/src/gui/kernel/qtooltip.cpp +++ b/src/gui/kernel/qtooltip.cpp @@ -290,8 +290,8 @@ void QTipLabel::timerEvent(QTimerEvent *e) // Fade out tip on mac (makes it invisible). // The tip will not be deleted until a new tip is shown. - // DRSWAT - Cocoa - macWindowFade(qt_mac_window_for(this)); + // DRSWAT - Cocoa + macWindowFade(qt_mac_window_for(this)); QTipLabel::instance->fadingOut = true; // will never be false again. } else @@ -431,7 +431,7 @@ bool QTipLabel::tipChanged(const QPoint &pos, const QString &text, QObject *o) void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect) { - if (QTipLabel::instance){ // a tip does already exist + if (QTipLabel::instance && QTipLabel::instance->isVisible()){ // a tip does already exist if (text.isEmpty()){ // empty text means hide current tip QTipLabel::instance->hideTip(); return; diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index 522ce33..3744377 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -1222,8 +1222,9 @@ void QWidget::releaseMouse() WId id = effectiveWinId(); id->SetPointerCapture(false); QWidgetPrivate::mouseGrabber = 0; - +#ifndef QT_NO_CURSOR QApplication::restoreOverrideCursor(); +#endif } } diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 5abac2f..c35c33a 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -14,7 +14,7 @@ HEADERS += \ painting/qoutlinemapper_p.h \ painting/qpaintdevice.h \ painting/qpaintengine.h \ - painting/qpaintengine_p.h \ + painting/qpaintengine_p.h \ painting/qpaintengine_alpha_p.h \ painting/qpaintengine_preview_p.h \ painting/qpaintengineex_p.h \ @@ -22,6 +22,7 @@ HEADERS += \ painting/qpainter_p.h \ painting/qpainterpath.h \ painting/qpainterpath_p.h \ + painting/qvectorpath_p.h \ painting/qpathclipper_p.h \ painting/qpdf_p.h \ painting/qpen.h \ @@ -178,8 +179,12 @@ embedded { symbian { SOURCES += \ + painting/qpaintengine_s60.cpp \ painting/qregion_s60.cpp \ painting/qcolormap_s60.cpp + + HEADERS += \ + painting/qpaintengine_s60_p.h } x11|embedded { diff --git a/src/gui/painting/qdrawutil.cpp b/src/gui/painting/qdrawutil.cpp index c4a9373..0a82a9f 100644 --- a/src/gui/painting/qdrawutil.cpp +++ b/src/gui/painting/qdrawutil.cpp @@ -1066,8 +1066,9 @@ void qDrawItem(QPainter *p, Qt::GUIStyle gs, /*! \fn void qDrawBorderPixmap(QPainter *painter, const QRect &target, const QMargins &margins, const QPixmap &pixmap) - \since 4.6 \relates <qdrawutil.h> + \since 4.6 + \overload Draws the given \a pixmap into the given \a target rectangle, using the given \a painter. The pixmap will be split into nine segments and drawn diff --git a/src/gui/painting/qgraphicssystem.cpp b/src/gui/painting/qgraphicssystem.cpp index 20d6f22..2d9603d 100644 --- a/src/gui/painting/qgraphicssystem.cpp +++ b/src/gui/painting/qgraphicssystem.cpp @@ -44,12 +44,15 @@ #ifdef Q_WS_X11 # include <private/qpixmap_x11_p.h> #endif -#if defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) +#if defined(Q_WS_WIN) # include <private/qpixmap_raster_p.h> #endif #ifdef Q_WS_MAC # include <private/qpixmap_mac_p.h> #endif +#ifdef Q_WS_S60 +# include <private/qpixmap_s60_p.h> +#endif QT_BEGIN_NAMESPACE @@ -64,10 +67,12 @@ QPixmapData *QGraphicsSystem::createDefaultPixmapData(QPixmapData::PixelType typ #endif #if defined(Q_WS_X11) return new QX11PixmapData(type); -#elif defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) +#elif defined(Q_WS_WIN) return new QRasterPixmapData(type); #elif defined(Q_WS_MAC) return new QMacPixmapData(type); +#elif defined(Q_WS_S60) + return new QS60PixmapData(type); #elif !defined(Q_WS_QWS) #error QGraphicsSystem::createDefaultPixmapData() not implemented #endif diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index bac0a76..f41d7b4 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3551,7 +3551,7 @@ void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line, if (dash >= length) { dash = length; - *dashOffset += dash; + *dashOffset += dash / width; length = 0; } else { *dashOffset = 0; diff --git a/src/gui/painting/qpaintengine_s60.cpp b/src/gui/painting/qpaintengine_s60.cpp new file mode 100644 index 0000000..2aa179a --- /dev/null +++ b/src/gui/painting/qpaintengine_s60.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include <private/qpaintengine_s60_p.h> +#include <private/qpixmap_s60_p.h> +#include <private/qt_s60_p.h> + +QT_BEGIN_NAMESPACE + +class QS60PaintEnginePrivate : public QRasterPaintEnginePrivate +{ +public: + QS60PaintEnginePrivate(QS60PaintEngine *engine) { } +}; + +QS60PaintEngine::QS60PaintEngine(QPaintDevice *device, QS60PixmapData *data) + : QRasterPaintEngine(*(new QS60PaintEnginePrivate(this)), device), pixmapData(data) +{ +} + +bool QS60PaintEngine::begin(QPaintDevice *device) +{ + pixmapData->beginDataAccess(); + return QRasterPaintEngine::begin(device); +} + +bool QS60PaintEngine::end() +{ + bool ret = QRasterPaintEngine::end(); + pixmapData->endDataAccess(); + return ret; +} + +void QS60PaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm) +{ + QS60PixmapData *srcData = static_cast<QS60PixmapData *>(pm.pixmapData()); + srcData->beginDataAccess(); + QRasterPaintEngine::drawPixmap(p, pm); + srcData->endDataAccess(); +} + +void QS60PaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) +{ + QS60PixmapData *srcData = static_cast<QS60PixmapData *>(pm.pixmapData()); + srcData->beginDataAccess(); + QRasterPaintEngine::drawPixmap(r, pm, sr); + srcData->endDataAccess(); +} + +void QS60PaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr) +{ + QS60PixmapData *srcData = static_cast<QS60PixmapData *>(pm.pixmapData()); + srcData->beginDataAccess(); + QRasterPaintEngine::drawTiledPixmap(r, pm, sr); + srcData->endDataAccess(); +} + +void QS60PaintEngine::prepare(QImage *image) +{ + QRasterBuffer *buffer = d_func()->rasterBuffer.data(); + if (buffer) + buffer->prepare(image); +} + +QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintengine_s60_p.h b/src/gui/painting/qpaintengine_s60_p.h new file mode 100644 index 0000000..b38ef93 --- /dev/null +++ b/src/gui/painting/qpaintengine_s60_p.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTENGINE_S60_P_H +#define QPAINTENGINE_S60_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qpaintengine_raster_p.h" + +QT_BEGIN_NAMESPACE + +class QS60PaintEnginePrivate; +class QS60PixmapData; + +class QS60PaintEngine : public QRasterPaintEngine +{ + Q_DECLARE_PRIVATE(QS60PaintEngine) + +public: + QS60PaintEngine(QPaintDevice *device, QS60PixmapData* data); + bool begin(QPaintDevice *device); + bool end(); + + void drawPixmap(const QPointF &p, const QPixmap &pm); + void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); + void drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr); + + void prepare(QImage* image); + +private: + QS60PixmapData *pixmapData; +}; + +QT_END_NAMESPACE + +#endif // QPAINTENGINE_S60_P_H diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 656f383..e5da392 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -280,6 +280,29 @@ static QPainterPath::ElementType qpaintengineex_rect4_types_32[] = { QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 32 }; + +static QPainterPath::ElementType qpaintengineex_roundedrect_types[] = { + QPainterPath::MoveToElement, + QPainterPath::LineToElement, + QPainterPath::CurveToElement, + QPainterPath::CurveToDataElement, + QPainterPath::CurveToDataElement, + QPainterPath::LineToElement, + QPainterPath::CurveToElement, + QPainterPath::CurveToDataElement, + QPainterPath::CurveToDataElement, + QPainterPath::LineToElement, + QPainterPath::CurveToElement, + QPainterPath::CurveToDataElement, + QPainterPath::CurveToDataElement, + QPainterPath::LineToElement, + QPainterPath::CurveToElement, + QPainterPath::CurveToDataElement, + QPainterPath::CurveToDataElement +}; + + + static void qpaintengineex_moveTo(qreal x, qreal y, void *data) { ((StrokeHandler *) data)->pts.add(x); ((StrokeHandler *) data)->pts.add(y); @@ -679,6 +702,49 @@ void QPaintEngineEx::drawRects(const QRectF *rects, int rectCount) } } + +void QPaintEngineEx::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, + Qt::SizeMode mode) +{ + qreal x1 = rect.left(); + qreal x2 = rect.right(); + qreal y1 = rect.top(); + qreal y2 = rect.bottom(); + + if (mode == Qt::RelativeSize) { + xRadius = xRadius * rect.width() / 200.; + yRadius = yRadius * rect.height() / 200.; + } + + xRadius = qMin(xRadius, rect.width() / 2); + yRadius = qMin(yRadius, rect.height() / 2); + + qreal pts[] = { + x1 + xRadius, y1, // MoveTo + x2 - xRadius, y1, // LineTo + x2 - (1 - KAPPA) * xRadius, y1, // CurveTo + x2, y1 + (1 - KAPPA) * yRadius, + x2, y1 + yRadius, + x2, y2 - yRadius, // LineTo + x2, y2 - (1 - KAPPA) * yRadius, // CurveTo + x2 - (1 - KAPPA) * xRadius, y2, + x2 - xRadius, y2, + x1 + xRadius, y2, // LineTo + x1 + (1 - KAPPA) * xRadius, y2, // CurveTo + x1, y2 - (1 - KAPPA) * yRadius, + x1, y2 - yRadius, + x1, y1 + yRadius, // LineTo + x1, y1 + KAPPA * yRadius, // CurveTo + x1 + (1 - KAPPA) * xRadius, y1, + x1 + xRadius, y1 + }; + + QVectorPath path(pts, 17, qpaintengineex_roundedrect_types); + draw(path); +} + + + void QPaintEngineEx::drawLines(const QLine *lines, int lineCount) { int elementCount = lineCount << 1; diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index 9f0d84a..814a0f0 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -170,6 +170,8 @@ public: virtual void fillRect(const QRectF &rect, const QBrush &brush); virtual void fillRect(const QRectF &rect, const QColor &color); + virtual void drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode); + virtual void drawRects(const QRect *rects, int rectCount); virtual void drawRects(const QRectF *rects, int rectCount); @@ -207,7 +209,12 @@ public: virtual void beginNativePainting() {} virtual void endNativePainting() {} - virtual QPixmapFilter *createPixmapFilter(int /*type*/) const { return 0; } + // Return a pixmap filter of "type" that can render the parameters + // in "prototype". The returned filter is owned by the engine and + // will be destroyed when the engine is destroyed. The "prototype" + // allows the engine to pick different filters based on the parameters + // that will be requested, and not just the "type". + virtual QPixmapFilter *pixmapFilter(int /*type*/, const QPixmapFilter * /*prototype*/) { return 0; } // These flags are needed in the implementation of paint buffers. enum Flags diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index b3aef71..ed1b5d1 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -4038,7 +4038,6 @@ const QFont &QPainter::font() const \sa drawRect(), QPen */ -// FALCON: Should we add a specialized method in QPaintEngineEx? void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode) { #ifdef QT_DEBUG_DRAW @@ -4056,61 +4055,7 @@ void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, } if (d->extended) { - QPainterPath::ElementType types[] = { - QPainterPath::MoveToElement, - QPainterPath::LineToElement, - QPainterPath::CurveToElement, - QPainterPath::CurveToDataElement, - QPainterPath::CurveToDataElement, - QPainterPath::LineToElement, - QPainterPath::CurveToElement, - QPainterPath::CurveToDataElement, - QPainterPath::CurveToDataElement, - QPainterPath::LineToElement, - QPainterPath::CurveToElement, - QPainterPath::CurveToDataElement, - QPainterPath::CurveToDataElement, - QPainterPath::LineToElement, - QPainterPath::CurveToElement, - QPainterPath::CurveToDataElement, - QPainterPath::CurveToDataElement - }; - - qreal x1 = rect.left(); - qreal x2 = rect.right(); - qreal y1 = rect.top(); - qreal y2 = rect.bottom(); - - if (mode == Qt::RelativeSize) { - xRadius = xRadius * rect.width() / 200.; - yRadius = yRadius * rect.height() / 200.; - } - - xRadius = qMin(xRadius, rect.width() / 2); - yRadius = qMin(yRadius, rect.height() / 2); - - qreal pts[] = { - x1 + xRadius, y1, // MoveTo - x2 - xRadius, y1, // LineTo - x2 - (1 - KAPPA) * xRadius, y1, // CurveTo - x2, y1 + (1 - KAPPA) * yRadius, - x2, y1 + yRadius, - x2, y2 - yRadius, // LineTo - x2, y2 - (1 - KAPPA) * yRadius, // CurveTo - x2 - (1 - KAPPA) * xRadius, y2, - x2 - xRadius, y2, - x1 + xRadius, y2, // LineTo - x1 + (1 - KAPPA) * xRadius, y2, // CurveTo - x1, y2 - (1 - KAPPA) * yRadius, - x1, y2 - yRadius, - x1, y1 + yRadius, // LineTo - x1, y1 + KAPPA * yRadius, // CurveTo - x1 + (1 - KAPPA) * xRadius, y1, - x1 + xRadius, y1 - }; - - QVectorPath path(pts, 17, types); - d->extended->draw(path); + d->extended->drawRoundedRect(rect, xRadius, yRadius, mode); return; } @@ -4152,23 +4097,7 @@ void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, */ void QPainter::drawRoundRect(const QRectF &r, int xRnd, int yRnd) { -#ifdef QT_DEBUG_DRAW - if (qt_show_painter_debug_output) - printf("QPainter::drawRoundRectangle(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height()); -#endif - Q_D(QPainter); - - if (!d->engine) - return; - - if(xRnd <= 0 || yRnd <= 0) { // draw normal rectangle - drawRect(r); - return; - } - - QPainterPath path; - path.addRoundRect(r, xRnd, yRnd); - drawPath(path); + drawRoundedRect(r, xRnd, yRnd, Qt::RelativeSize); } @@ -7535,7 +7464,11 @@ void qt_format_text(const QFont &fnt, const QRectF &_r, bool hidemnmemonic = (tf & Qt::TextHideMnemonic); Qt::LayoutDirection layout_direction; - if(option) + if (tf & Qt::TextForceLeftToRight) + layout_direction = Qt::LeftToRight; + else if (tf & Qt::TextForceRightToLeft) + layout_direction = Qt::RightToLeft; + else if (option) layout_direction = option->textDirection(); else if (painter) layout_direction = painter->layoutDirection(); diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp index 0b33369..66d0c9d 100644 --- a/src/gui/painting/qrasterizer.cpp +++ b/src/gui/painting/qrasterizer.cpp @@ -707,10 +707,12 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, if (a == b || width == 0 || d->clipRect.isEmpty()) return; + Q_ASSERT(width > 0.0); + QPointF pa = a; QPointF pb = b; - QPointF offs = QPointF(qAbs(b.y() - a.y()), qAbs(b.x() - a.x())) * width * 0.5; + QPointF offs = QPointF(qAbs(b.y() - a.y()), qAbs(b.x() - a.x())) * width * 0.5; if (squareCap) offs += QPointF(offs.y(), offs.x()); const QRectF clip(d->clipRect.topLeft() - offs, d->clipRect.bottomRight() + QPoint(1, 1) + offs); diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp index f56902a..664ad48 100644 --- a/src/gui/painting/qwindowsurface_s60.cpp +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -44,6 +44,7 @@ #include <QtGui/qpaintdevice.h> #include <private/qwidget_p.h> #include "qwindowsurface_s60_p.h" +#include "qpixmap_s60_p.h" #include "qt_s60_p.h" #include "private/qdrawhelper_p.h" @@ -51,20 +52,13 @@ QT_BEGIN_NAMESPACE struct QS60WindowSurfacePrivate { - QImage device; - CFbsBitmap *bitmap; - uchar* bytes; - - // Since only one CFbsBitmap is allowed to be locked at a time, this is static. - static QS60WindowSurface* lockedSurface; + QPixmap device; + QList<QImage*> bufferImages; }; -QS60WindowSurface* QS60WindowSurfacePrivate::lockedSurface = NULL; QS60WindowSurface::QS60WindowSurface(QWidget* widget) : QWindowSurface(widget), d_ptr(new QS60WindowSurfacePrivate) { - d_ptr->bytes = 0; - d_ptr->bitmap = 0; TDisplayMode mode = S60->screenDevice()->DisplayMode(); bool isOpaque = qt_widget_private(widget)->isOpaque; @@ -73,39 +67,27 @@ QS60WindowSurface::QS60WindowSurface(QWidget* widget) else if (mode == EColor16MU && !isOpaque) mode = EColor16MA; // Try for transparency anyway - // We create empty CFbsBitmap here -> it will be resized in setGeometry - d_ptr->bitmap = q_check_ptr(new CFbsBitmap); // CBase derived object needs check on new - qt_symbian_throwIfError( d_ptr->bitmap->Create(TSize(0, 0), mode ) ); - - updatePaintDeviceOnBitmap(); - + CFbsBitmap *bitmap = q_check_ptr(new CFbsBitmap); // CBase derived object needs check on new + qt_symbian_throwIfError( bitmap->Create( TSize(0, 0), mode ) ); + + QS60PixmapData *data = new QS60PixmapData(QPixmapData::PixmapType); + data->fromSymbianBitmap(bitmap); + d_ptr->device = QPixmap(data); + setStaticContentsSupport(true); } - QS60WindowSurface::~QS60WindowSurface() { - if (QS60WindowSurfacePrivate::lockedSurface == this) - unlockBitmapHeap(); - - delete d_ptr->bitmap; delete d_ptr; } void QS60WindowSurface::beginPaint(const QRegion &rgn) { - if(!d_ptr->bitmap) - return; - - if (QS60WindowSurfacePrivate::lockedSurface) - unlockBitmapHeap(); - - QS60WindowSurfacePrivate::lockedSurface = this; - lockBitmapHeap(); - if (!qt_widget_private(window())->isOpaque) { - QRgb *data = reinterpret_cast<QRgb *>(d_ptr->device.bits()); - const int row_stride = d_ptr->device.bytesPerLine() / 4; + QImage image = static_cast<QS60PixmapData *>(d_ptr->device.data_ptr().data())->image; + QRgb *data = reinterpret_cast<QRgb *>(image.bits()); + const int row_stride = image.bytesPerLine() / 4; const QVector<QRect> rects = rgn.rects(); for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) { @@ -124,6 +106,38 @@ void QS60WindowSurface::beginPaint(const QRegion &rgn) } } +void QS60WindowSurface::endPaint(const QRegion &) +{ + qDeleteAll(d_ptr->bufferImages); + d_ptr->bufferImages.clear(); +} + +QImage* QS60WindowSurface::buffer(const QWidget *widget) +{ + if (widget->window() != window()) + return 0; + + QPaintDevice *pdev = paintDevice(); + if (!pdev) + return 0; + + const QPoint off = offset(widget); + QImage *img = &(static_cast<QS60PixmapData *>(d_ptr->device.data_ptr().data())->image); + + QRect rect(off, widget->size()); + rect &= QRect(QPoint(), img->size()); + + if (rect.isEmpty()) + return 0; + + img = new QImage(img->scanLine(rect.y()) + rect.x() * img->depth() / 8, + rect.width(), rect.height(), + img->bytesPerLine(), img->format()); + d_ptr->bufferImages.append(img); + + return img; +} + void QS60WindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &) { const QVector<QRect> subRects = region.rects(); @@ -143,28 +157,10 @@ bool QS60WindowSurface::scroll(const QRegion &area, int dx, int dy) if (d_ptr->device.isNull()) return false; - CFbsBitmapDevice *bitmapDevice = 0; - QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(d_ptr->bitmap)); - CBitmapContext *bitmapContext; - TInt err = bitmapDevice->CreateBitmapContext(bitmapContext); - if (err != KErrNone) { - CBase::Delete(bitmapDevice); - return false; - } - bitmapContext->CopyRect(TPoint(dx, dy), qt_QRect2TRect(rect)); - CBase::Delete(bitmapContext); - CBase::Delete(bitmapDevice); - return true; -} - -void QS60WindowSurface::endPaint(const QRegion & /* rgn */) -{ - if(!d_ptr->bitmap) - return; + QS60PixmapData *data = static_cast<QS60PixmapData*>(d_ptr->device.data_ptr().data()); + data->scroll(dx, dy, rect); - Q_ASSERT(QS60WindowSurfacePrivate::lockedSurface); - unlockBitmapHeap(); - QS60WindowSurfacePrivate::lockedSurface = NULL; + return true; } QPaintDevice* QS60WindowSurface::paintDevice() @@ -177,61 +173,17 @@ void QS60WindowSurface::setGeometry(const QRect& rect) if (rect == geometry()) return; - QWindowSurface::setGeometry(rect); - - TRect nativeRect(qt_QRect2TRect(rect)); - qt_symbian_throwIfError(d_ptr->bitmap->Resize(nativeRect.Size())); - - if (!rect.isNull()) - updatePaintDeviceOnBitmap(); -} - -void QS60WindowSurface::lockBitmapHeap() -{ - if (!QS60WindowSurfacePrivate::lockedSurface) - return; - - // Get some local variables to make later code lines more clear to read - CFbsBitmap*& bitmap = QS60WindowSurfacePrivate::lockedSurface->d_ptr->bitmap; - QImage& device = QS60WindowSurfacePrivate::lockedSurface->d_ptr->device; - uchar*& bytes = QS60WindowSurfacePrivate::lockedSurface->d_ptr->bytes; - - bitmap->LockHeap(); - uchar *newBytes = (uchar*)bitmap->DataAddress(); - if (newBytes != bytes) { - bytes = newBytes; - - // Get some values for QImage creation - TDisplayMode mode = bitmap->DisplayMode(); - if (mode == EColor16MA - && qt_widget_private(QS60WindowSurfacePrivate::lockedSurface->window())->isOpaque) - mode = EColor16MU; - QImage::Format format = qt_TDisplayMode2Format( mode ); - TSize bitmapSize = bitmap->SizeInPixels(); - int bytesPerLine = CFbsBitmap::ScanLineLength( bitmapSize.iWidth, mode); - - device = QImage( bytes, bitmapSize.iWidth, bitmapSize.iHeight, bytesPerLine, format ); - } -} - -void QS60WindowSurface::unlockBitmapHeap() -{ - if (!QS60WindowSurfacePrivate::lockedSurface) - return; - - QS60WindowSurfacePrivate::lockedSurface->d_ptr->bitmap->UnlockHeap(); -} + QS60PixmapData *data = static_cast<QS60PixmapData*>(d_ptr->device.data_ptr().data()); + data->resize(rect.width(), rect.height()); -void QS60WindowSurface::updatePaintDeviceOnBitmap() -{ - // This forces the actual device to be updated based on CFbsBitmap - beginPaint(QRegion()); - endPaint(QRegion()); + QWindowSurface::setGeometry(rect); } -CFbsBitmap *QS60WindowSurface::symbianBitmap() const +CFbsBitmap* QS60WindowSurface::symbianBitmap() const { - return d_ptr->bitmap; + QS60PixmapData *data = static_cast<QS60PixmapData*>(d_ptr->device.data_ptr().data()); + return data->cfbsBitmap; } QT_END_NAMESPACE + diff --git a/src/gui/painting/qwindowsurface_s60_p.h b/src/gui/painting/qwindowsurface_s60_p.h index f9b6b60..3c4059f 100644 --- a/src/gui/painting/qwindowsurface_s60_p.h +++ b/src/gui/painting/qwindowsurface_s60_p.h @@ -75,17 +75,13 @@ public: void beginPaint(const QRegion &); void endPaint(const QRegion &); - void setGeometry(const QRect &rect); + QImage* buffer(const QWidget *widget); - static void lockBitmapHeap(); - static void unlockBitmapHeap(); + void setGeometry(const QRect &rect); CFbsBitmap *symbianBitmap() const; private: - void updatePaintDeviceOnBitmap(); - -private: QS60WindowSurfacePrivate* d_ptr; }; diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp index 4fdf48b..131d8bc 100644 --- a/src/gui/styles/qs60style_s60.cpp +++ b/src/gui/styles/qs60style_s60.cpp @@ -44,8 +44,8 @@ #include "qpainter.h" #include "qstyleoption.h" #include "qstyle.h" -#include "private/qwindowsurface_s60_p.h" #include "private/qt_s60_p.h" +#include "private/qpixmap_s60_p.h" #include "private/qcore_symbian_p.h" #include "qapplication.h" @@ -1136,11 +1136,13 @@ QPixmap QS60StyleModeSpecifics::generateMissingThemeGraphic(QS60StyleEnums::Skin QPixmap QS60StylePrivate::part(QS60StyleEnums::SkinParts part, const QSize &size, SkinElementFlags flags) { - QS60WindowSurface::unlockBitmapHeap(); + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + QPixmap result = (flags & SF_ColorSkinned)? QS60StyleModeSpecifics::colorSkinnedGraphics(part, size, flags) : QS60StyleModeSpecifics::skinnedGraphics(part, size, flags); - QS60WindowSurface::lockBitmapHeap(); + + lock.relock(); if (flags & SF_StateDisabled && !QS60StyleModeSpecifics::disabledPartGraphic(part)) { QStyleOption opt; @@ -1158,9 +1160,9 @@ QPixmap QS60StylePrivate::part(QS60StyleEnums::SkinParts part, QPixmap QS60StylePrivate::frame(SkinFrameElements frame, const QSize &size, SkinElementFlags flags) { - QS60WindowSurface::unlockBitmapHeap(); + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); QPixmap result = QS60StyleModeSpecifics::skinnedGraphics(frame, size, flags); - QS60WindowSurface::lockBitmapHeap(); + lock.relock(); if (flags & SF_StateDisabled && !QS60StyleModeSpecifics::disabledFrameGraphic(frame)) { QStyleOption opt; diff --git a/src/gui/styles/qstyle.cpp b/src/gui/styles/qstyle.cpp index 2614bfb..eef1573 100644 --- a/src/gui/styles/qstyle.cpp +++ b/src/gui/styles/qstyle.cpp @@ -463,7 +463,7 @@ QRect QStyle::itemTextRect(const QFontMetrics &metrics, const QRect &rect, int a rect.getRect(&x, &y, &w, &h); if (!text.isEmpty()) { result = metrics.boundingRect(x, y, w, h, alignment, text); - if (!enabled && styleHint(SH_EtchDisabledText)) { + if (!enabled && proxy()->styleHint(SH_EtchDisabledText)) { result.setWidth(result.width()+1); result.setHeight(result.height()+1); } @@ -525,12 +525,12 @@ void QStyle::drawItemText(QPainter *painter, const QRect &rect, int alignment, c painter->setPen(QPen(pal.brush(textRole), savedPen.widthF())); } if (!enabled) { - if (styleHint(SH_DitherDisabledText)) { + if (proxy()->styleHint(SH_DitherDisabledText)) { QRect br; painter->drawText(rect, alignment, text, &br); painter->fillRect(br, QBrush(painter->background().color(), Qt::Dense5Pattern)); return; - } else if (styleHint(SH_EtchDisabledText)) { + } else if (proxy()->styleHint(SH_EtchDisabledText)) { QPen pen = painter->pen(); painter->setPen(pal.light().color()); painter->drawText(rect.adjusted(1, 1, 1, 1), alignment, text); diff --git a/src/gui/text/qfont_s60.cpp b/src/gui/text/qfont_s60.cpp index 30e00ff..277d88f 100644 --- a/src/gui/text/qfont_s60.cpp +++ b/src/gui/text/qfont_s60.cpp @@ -41,7 +41,7 @@ #include "qfont.h" #include "qt_s60_p.h" -#include <private/qwindowsurface_s60_p.h> +#include "qpixmap_s60_p.h" #include "qmutex.h" QT_BEGIN_NAMESPACE @@ -57,14 +57,17 @@ QString QFont::lastResortFamily() const QMutexLocker locker(lastResortFamilyMutex()); static QString family; if (family.isEmpty()) { - QS60WindowSurface::unlockBitmapHeap(); + + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + CFont *font; const TInt err = S60->screenDevice()->GetNearestFontInTwips(font, TFontSpec()); Q_ASSERT(err == KErrNone); const TFontSpec spec = font->FontSpecInTwips(); family = QString((const QChar *)spec.iTypeface.iName.Ptr(), spec.iTypeface.iName.Length()); S60->screenDevice()->ReleaseFont(font); - QS60WindowSurface::lockBitmapHeap(); + + lock.relock(); } return family; #else diff --git a/src/gui/text/qfontdatabase_mac.cpp b/src/gui/text/qfontdatabase_mac.cpp index d65910c..2584003 100644 --- a/src/gui/text/qfontdatabase_mac.cpp +++ b/src/gui/text/qfontdatabase_mac.cpp @@ -308,6 +308,21 @@ void QFontDatabase::load(const QFontPrivate *d, int script) if (familyRef) { fontRef = ATSFontFindFromName(QCFString(db->families[k]->name), kATSOptionFlagsDefault); goto FamilyFound; + } else { +#if defined(QT_MAC_USE_COCOA) + // ATS and CT disagrees on what the family name should be, + // use CT to look up the font if ATS fails. + QCFString familyName = QString::fromAscii(family_name); + QCFType<CTFontRef> CTfontRef = CTFontCreateWithName(familyName, 12, NULL); + QCFType<CTFontDescriptorRef> fontDescriptor = CTFontCopyFontDescriptor(CTfontRef); + QCFString displayName = (CFStringRef)CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontDisplayNameAttribute); + + familyRef = ATSFontFamilyFindFromName(displayName, kATSOptionFlagsDefault); + if (familyRef) { + fontRef = ATSFontFindFromName(displayName, kATSOptionFlagsDefault); + goto FamilyFound; + } +#endif } } } @@ -456,11 +471,27 @@ static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) return; fnt->families.clear(); +#if defined(QT_MAC_USE_COCOA) + // Make sure that the family name set on the font matches what + // kCTFontFamilyNameAttribute returns in initializeDb(). + // So far the best solution seems find the installed font + // using CoreText and get the family name from it. + // (ATSFontFamilyGetName appears to be the correct API, but also + // returns the font display name.) + for(int i = 0; i < containedFonts.size(); ++i) { + QCFString fontPostScriptName; + ATSFontGetPostScriptName(containedFonts[i], kATSOptionFlagsDefault, &fontPostScriptName); + QCFType<CTFontDescriptorRef> font = CTFontDescriptorCreateWithNameAndSize(fontPostScriptName, 14); + QCFString familyName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute); + fnt->families.append(familyName); + } +#else for(int i = 0; i < containedFonts.size(); ++i) { QCFString family; ATSFontGetName(containedFonts[i], kATSOptionFlagsDefault, &family); fnt->families.append(family); } +#endif fnt->handle = handle; } diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp index e1a2c47..1a6bb11 100644 --- a/src/gui/text/qfontdatabase_s60.cpp +++ b/src/gui/text/qfontdatabase_s60.cpp @@ -45,9 +45,9 @@ #include "qfontengine_s60_p.h" #include "qabstractfileengine.h" #include "qdesktopservices.h" +#include "qpixmap_s60_p.h" #include "qt_s60_p.h" #include "qendian.h" -#include <private/qwindowsurface_s60_p.h> #include <private/qcore_symbian_p.h> #if defined(QT_NO_FREETYPE) #include <OPENFONT.H> @@ -217,7 +217,8 @@ static void initializeDb() if (!db->s60Store) db->s60Store = new QFontDatabaseS60StoreImplementation; - QS60WindowSurface::unlockBitmapHeap(); + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + const int numTypeFaces = QS60Data::screenDevice()->NumTypefaces(); const QFontDatabaseS60StoreImplementation *store = dynamic_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store); Q_ASSERT(store); @@ -271,8 +272,11 @@ static void initializeDb() } QS60Data::screenDevice()->ReleaseFont(font); } + Q_ASSERT(fontAdded); - QS60WindowSurface::lockBitmapHeap(); + + lock.relock(); + #else // defined(QT_NO_FREETYPE) QDir dir(QDesktopServices::storageLocation(QDesktopServices::FontsLocation)); dir.setNameFilters(QStringList() << QLatin1String("*.ttf") diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 8dd01d7..e5a88fc 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -946,48 +946,60 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy if (maps + 8 * numTables > endPtr) return 0; + enum { + Invalid, + Symbol, + AppleRoman, + Unicode11, + Unicode, + MicrosoftUnicode, + MicrosoftUnicodeExtended + }; + + int symbolTable = -1; int tableToUse = -1; - int score = 0; + int score = Invalid; for (int n = 0; n < numTables; ++n) { const quint16 platformId = qFromBigEndian<quint16>(maps + 8 * n); const quint16 platformSpecificId = qFromBigEndian<quint16>(maps + 8 * n + 2); switch (platformId) { case 0: // Unicode - if (score < 4 && + if (score < Unicode && (platformSpecificId == 0 || platformSpecificId == 2 || platformSpecificId == 3)) { tableToUse = n; - score = 4; - } else if (score < 3 && platformSpecificId == 1) { + score = Unicode; + } else if (score < Unicode11 && platformSpecificId == 1) { tableToUse = n; - score = 3; + score = Unicode11; } break; case 1: // Apple - if (score < 2 && platformSpecificId == 0) { // Apple Roman + if (score < AppleRoman && platformSpecificId == 0) { // Apple Roman tableToUse = n; - score = 2; + score = AppleRoman; } break; case 3: // Microsoft switch (platformSpecificId) { case 0: - if (score < 1) { + symbolTable = n; + if (score < Symbol) { tableToUse = n; - score = 1; + score = Symbol; } break; case 1: - if (score < 5) { + if (score < MicrosoftUnicode) { tableToUse = n; - score = 5; + score = MicrosoftUnicode; } break; case 0xa: - if (score < 6) { + if (score < MicrosoftUnicodeExtended) { tableToUse = n; - score = 6; + score = MicrosoftUnicodeExtended; } break; default: @@ -999,7 +1011,9 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy } if(tableToUse < 0) return 0; - *isSymbolFont = (score == 1); + +resolveTable: + *isSymbolFont = (score == Symbol); unsigned int unicode_table = qFromBigEndian<quint32>(maps + 8*tableToUse + 4); @@ -1019,6 +1033,41 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy if (table + unicode_table + length > endPtr) return 0; *cmapSize = length; + + // To support symbol fonts that contain a unicode table for the symbol area + // we check the cmap tables and fall back to symbol font unless that would + // involve losing information from the unicode table + if (symbolTable > -1 && ((score == Unicode) || (score == Unicode11))) { + const uchar *selectedTable = table + unicode_table; + + // Check that none of the latin1 range are in the unicode table + bool unicodeTableHasLatin1 = false; + for (int uc=0x00; uc<0x100; ++uc) { + if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) { + unicodeTableHasLatin1 = true; + break; + } + } + + // Check that at least one symbol char is in the unicode table + bool unicodeTableHasSymbols = false; + if (!unicodeTableHasLatin1) { + for (int uc=0xf000; uc<0xf100; ++uc) { + if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) { + unicodeTableHasSymbols = true; + break; + } + } + } + + // Fall back to symbol table + if (!unicodeTableHasLatin1 && unicodeTableHasSymbols) { + tableToUse = symbolTable; + score = Symbol; + goto resolveTable; + } + } + return table + unicode_table; } diff --git a/src/gui/text/qfontengine_s60.cpp b/src/gui/text/qfontengine_s60.cpp index ab2506c..88ae8f6 100644 --- a/src/gui/text/qfontengine_s60.cpp +++ b/src/gui/text/qfontengine_s60.cpp @@ -43,9 +43,9 @@ #include "qtextengine_p.h" #include "qglobal.h" #include <private/qapplication_p.h> -#include <private/qwindowsurface_s60_p.h> #include "qimage.h" #include "qt_s60_p.h" +#include "qpixmap_s60_p.h" #include <e32base.h> #include <e32std.h> @@ -136,7 +136,9 @@ QFontEngineS60::QFontEngineS60(const QFontDef &request, const QFontEngineS60Exte QFontEngine::fontDef = request; m_fontSizeInPixels = (request.pixelSize >= 0)? request.pixelSize:pointsToPixels(request.pointSize); - QS60WindowSurface::unlockBitmapHeap(); + + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + m_textRenderBitmap = q_check_ptr(new CFbsBitmap()); // CBase derived object needs check on new const TSize bitmapSize(1, 1); // It is just a dummy bitmap that I need to keep the font alive (or maybe not) qt_symbian_throwIfError(m_textRenderBitmap->Create(bitmapSize, EGray256)); @@ -151,12 +153,14 @@ QFontEngineS60::QFontEngineS60(const QFontDef &request, const QFontEngineS60Exte const TInt errorCode = m_textRenderBitmapDevice->GetNearestFontInPixels(m_font, fontSpec); Q_ASSERT(errorCode == 0); m_textRenderBitmapGc->UseFont(m_font); - QS60WindowSurface::lockBitmapHeap(); + + lock.relock(); } QFontEngineS60::~QFontEngineS60() { - QS60WindowSurface::unlockBitmapHeap(); + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + m_textRenderBitmapGc->DiscardFont(); delete m_textRenderBitmapGc; m_textRenderBitmapGc = NULL; @@ -165,7 +169,8 @@ QFontEngineS60::~QFontEngineS60() m_textRenderBitmapDevice = NULL; delete m_textRenderBitmap; m_textRenderBitmap = NULL; - QS60WindowSurface::lockBitmapHeap(); + + lock.relock(); } bool QFontEngineS60::stringToCMap(const QChar *characters, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index b2784d6..ce122aa 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -528,13 +528,15 @@ int QFontMetrics::rightBearing(QChar ch) const int QFontMetrics::width(const QString &text, int len) const { int pos = text.indexOf(QLatin1Char('\x9c')); - QString txt = (pos == -1) ? text : text.left(pos); - if (len < 0) - len = txt.length(); + if (pos != -1) { + len = (len < 0) ? pos : qMin(pos, len); + } else if (len < 0) { + len = text.length(); + } if (len == 0) return 0; - QTextEngine layout(txt, d); + QTextEngine layout(text, d); layout.ignoreBidi = true; return qRound(layout.width(0, len)); } diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index b43bd06..81c9142 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1396,8 +1396,12 @@ void QTextEngine::itemize() const int length = layoutData->string.length(); if (!length) return; - +#if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA) + // ATSUI requires RTL flags to correctly identify the character stops. + bool ignore = false; +#else bool ignore = ignoreBidi; +#endif if (!ignore && option.textDirection() == Qt::LeftToRight) { ignore = true; const QChar *start = layoutData->string.unicode(); diff --git a/src/gui/widgets/qdockwidget.cpp b/src/gui/widgets/qdockwidget.cpp index 0e434be..a574262f 100644 --- a/src/gui/widgets/qdockwidget.cpp +++ b/src/gui/widgets/qdockwidget.cpp @@ -1136,7 +1136,7 @@ void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect /*! \property QDockWidget::windowTitle - \internal + \brief the dock widget title (caption) By default, this property contains an empty string. */ |