diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:34:13 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:34:13 (GMT) |
commit | 67ad0519fd165acee4a4d2a94fa502e9e4847bd0 (patch) | |
tree | 1dbf50b3dff8d5ca7e9344733968c72704eb15ff /src/gui/embedded/qwsmanager_qws.cpp | |
download | Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.zip Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.gz Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.bz2 |
Long live Qt!
Diffstat (limited to 'src/gui/embedded/qwsmanager_qws.cpp')
-rw-r--r-- | src/gui/embedded/qwsmanager_qws.cpp | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/src/gui/embedded/qwsmanager_qws.cpp b/src/gui/embedded/qwsmanager_qws.cpp new file mode 100644 index 0000000..96abf3f --- /dev/null +++ b/src/gui/embedded/qwsmanager_qws.cpp @@ -0,0 +1,535 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwsmanager_qws.h" + +#ifndef QT_NO_QWS_MANAGER + +#include "qdrawutil.h" +#include "qapplication.h" +#include "qstyle.h" +#include "qwidget.h" +#include "qmenu.h" +#include "qpainter.h" +#include "private/qpainter_p.h" +#include "qregion.h" +#include "qevent.h" +#include "qcursor.h" +#include "qwsdisplay_qws.h" +#include "qdesktopwidget.h" + +#include <private/qapplication_p.h> +#include <private/qwidget_p.h> +#include <private/qbackingstore_p.h> +#include <private/qwindowsurface_qws_p.h> +#include "qdecorationfactory_qws.h" + +#include "qlayout.h" + +#include "qwsmanager_p.h" + +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +QWidget *QWSManagerPrivate::active = 0; +QPoint QWSManagerPrivate::mousePos; + + +QWSManagerPrivate::QWSManagerPrivate() + : QObjectPrivate(), activeRegion(QDecoration::None), managed(0), popup(0), + previousRegionType(0), previousRegionRepainted(false), entireDecorationNeedsRepaint(false) +{ + cached_region.regionType = 0; +} + +QRegion &QWSManager::cachedRegion() +{ + return d_func()->cached_region.region; +} + +/*! + \class QWSManager + \ingroup qws + \internal +*/ + +/*! + +*/ +QWSManager::QWSManager(QWidget *w) + : QObject(*new QWSManagerPrivate, (QObject*)0) +{ + d_func()->managed = w; + +} + +QWSManager::~QWSManager() +{ + Q_D(QWSManager); +#ifndef QT_NO_MENU + if (d->popup) + delete d->popup; +#endif + if (d->managed == QWSManagerPrivate::active) + QWSManagerPrivate::active = 0; +} + +QWidget *QWSManager::widget() +{ + Q_D(QWSManager); + return d->managed; +} + +QWidget *QWSManager::grabbedMouse() +{ + return QWSManagerPrivate::active; +} + +QRegion QWSManager::region() +{ + Q_D(QWSManager); + return QApplication::qwsDecoration().region(d->managed, d->managed->geometry()); +} + +bool QWSManager::event(QEvent *e) +{ + if (QObject::event(e)) + return true; + + switch (e->type()) { + case QEvent::MouseMove: + mouseMoveEvent((QMouseEvent*)e); + break; + + case QEvent::MouseButtonPress: + mousePressEvent((QMouseEvent*)e); + break; + + case QEvent::MouseButtonRelease: + mouseReleaseEvent((QMouseEvent*)e); + break; + + case QEvent::MouseButtonDblClick: + mouseDoubleClickEvent((QMouseEvent*)e); + break; + + case QEvent::Paint: + paintEvent((QPaintEvent*)e); + break; + + default: + return false; + break; + } + + return true; +} + +void QWSManager::mousePressEvent(QMouseEvent *e) +{ + Q_D(QWSManager); + d->mousePos = e->globalPos(); + d->activeRegion = QApplication::qwsDecoration().regionAt(d->managed, d->mousePos); + if(d->cached_region.regionType) + d->previousRegionRepainted |= repaintRegion(d->cached_region.regionType, QDecoration::Pressed); + + if (d->activeRegion == QDecoration::Menu) { + QPoint pos = (QApplication::layoutDirection() == Qt::LeftToRight + ? d->managed->geometry().topLeft() + : d->managed->geometry().topRight()); + menu(pos); + } + if (d->activeRegion != QDecoration::None && + d->activeRegion != QDecoration::Menu) { + d->active = d->managed; + d->managed->grabMouse(); + } + if (d->activeRegion != QDecoration::None && + d->activeRegion != QDecoration::Close && + d->activeRegion != QDecoration::Minimize && + d->activeRegion != QDecoration::Menu) { + d->managed->raise(); + } + + if (e->button() == Qt::RightButton) { + menu(e->globalPos()); + } +} + +void QWSManager::mouseReleaseEvent(QMouseEvent *e) +{ + Q_D(QWSManager); + d->managed->releaseMouse(); + if (d->cached_region.regionType && d->previousRegionRepainted && QApplication::mouseButtons() == 0) { + bool doesHover = repaintRegion(d->cached_region.regionType, QDecoration::Hover); + if (!doesHover) { + repaintRegion(d->cached_region.regionType, QDecoration::Normal); + d->previousRegionRepainted = false; + } + } + + if (e->button() == Qt::LeftButton) { + //handleMove(); + int itm = QApplication::qwsDecoration().regionAt(d->managed, e->globalPos()); + int activatedItem = d->activeRegion; + d->activeRegion = QDecoration::None; + d->active = 0; + if (activatedItem == itm) + QApplication::qwsDecoration().regionClicked(d->managed, itm); + } else if (d->activeRegion == QDecoration::None) { + d->active = 0; + } +} + +void QWSManager::mouseDoubleClickEvent(QMouseEvent *e) +{ + Q_D(QWSManager); + if (e->button() == Qt::LeftButton) + QApplication::qwsDecoration().regionDoubleClicked(d->managed, + QApplication::qwsDecoration().regionAt(d->managed, e->globalPos())); +} + +static inline Qt::CursorShape regionToShape(int region) +{ + if (region == QDecoration::None) + return Qt::ArrowCursor; + + static const struct { + int region; + Qt::CursorShape shape; + } r2s[] = { + { QDecoration::TopLeft, Qt::SizeFDiagCursor }, + { QDecoration::Top, Qt::SizeVerCursor}, + { QDecoration::TopRight, Qt::SizeBDiagCursor}, + { QDecoration::Left, Qt::SizeHorCursor}, + { QDecoration::Right, Qt::SizeHorCursor}, + { QDecoration::BottomLeft, Qt::SizeBDiagCursor}, + { QDecoration::Bottom, Qt::SizeVerCursor}, + { QDecoration::BottomRight, Qt::SizeFDiagCursor}, + { QDecoration::None, Qt::ArrowCursor} + }; + + int i = 0; + while (region != r2s[i].region && r2s[i].region) + ++i; + return r2s[i].shape; +} + +void QWSManager::mouseMoveEvent(QMouseEvent *e) +{ + Q_D(QWSManager); + if (d->newCachedRegion(e->globalPos())) { + if(d->previousRegionType && d->previousRegionRepainted) + repaintRegion(d->previousRegionType, QDecoration::Normal); + if(d->cached_region.regionType) { + d->previousRegionRepainted = repaintRegion(d->cached_region.regionType, QDecoration::Hover); + } + } + + +#ifndef QT_NO_CURSOR + QWSDisplay *qwsd = QApplication::desktop()->qwsDisplay(); + qwsd->selectCursor(d->managed, regionToShape(d->cachedRegionAt())); +#endif //QT_NO_CURSOR + + if (d->activeRegion) + handleMove(e->globalPos()); +} + +void QWSManager::handleMove(QPoint g) +{ + Q_D(QWSManager); + + // don't allow dragging to where the user probably cannot click! + QApplicationPrivate *ap = QApplicationPrivate::instance(); + const QRect maxWindowRect = ap->maxWindowRect(qt_screen); + if (maxWindowRect.isValid()) { + if (g.x() < maxWindowRect.x()) + g.setX(maxWindowRect.x()); + if (g.y() < maxWindowRect.y()) + g.setY(maxWindowRect.y()); + if (g.x() > maxWindowRect.right()) + g.setX(maxWindowRect.right()); + if (g.y() > maxWindowRect.bottom()) + g.setY(maxWindowRect.bottom()); + } + + if (g == d->mousePos) + return; + + if ( d->managed->isMaximized() ) + return; + + int x = d->managed->geometry().x(); + int y = d->managed->geometry().y(); + int w = d->managed->width(); + int h = d->managed->height(); + + QRect geom(d->managed->geometry()); + + QPoint delta = g - d->mousePos; + d->mousePos = g; + + if (d->activeRegion == QDecoration::Title) { + geom = QRect(x + delta.x(), y + delta.y(), w, h); + } else { + bool keepTop = true; + bool keepLeft = true; + switch (d->activeRegion) { + case QDecoration::Top: + geom.setTop(geom.top() + delta.y()); + keepTop = false; + break; + case QDecoration::Bottom: + geom.setBottom(geom.bottom() + delta.y()); + keepTop = true; + break; + case QDecoration::Left: + geom.setLeft(geom.left() + delta.x()); + keepLeft = false; + break; + case QDecoration::Right: + geom.setRight(geom.right() + delta.x()); + keepLeft = true; + break; + case QDecoration::TopRight: + geom.setTopRight(geom.topRight() + delta); + keepLeft = true; + keepTop = false; + break; + case QDecoration::TopLeft: + geom.setTopLeft(geom.topLeft() + delta); + keepLeft = false; + keepTop = false; + break; + case QDecoration::BottomLeft: + geom.setBottomLeft(geom.bottomLeft() + delta); + keepLeft = false; + keepTop = true; + break; + case QDecoration::BottomRight: + geom.setBottomRight(geom.bottomRight() + delta); + keepLeft = true; + keepTop = true; + break; + default: + return; + } + + QSize newSize = QLayout::closestAcceptableSize(d->managed, geom.size()); + + int dx = newSize.width() - geom.width(); + int dy = newSize.height() - geom.height(); + + if (keepTop) { + geom.setBottom(geom.bottom() + dy); + d->mousePos.ry() += dy; + } else { + geom.setTop(geom.top() - dy); + d->mousePos.ry() -= dy; + } + if (keepLeft) { + geom.setRight(geom.right() + dx); + d->mousePos.rx() += dx; + } else { + geom.setLeft(geom.left() - dx); + d->mousePos.rx() -= dx; + } + } + if (geom != d->managed->geometry()) { + QApplication::sendPostedEvents(); + d->managed->setGeometry(geom); + } +} + +void QWSManager::paintEvent(QPaintEvent *) +{ + Q_D(QWSManager); + d->dirtyRegion(QDecoration::All, QDecoration::Normal); +} + +void QWSManagerPrivate::dirtyRegion(int decorationRegion, + QDecoration::DecorationState state, + const QRegion &clip) +{ + QTLWExtra *topextra = managed->d_func()->extra->topextra; + QWidgetBackingStore *bs = topextra->backingStore; + const bool pendingUpdateRequest = bs->isDirty(); + + if (decorationRegion == QDecoration::All) { + if (clip.isEmpty()) + entireDecorationNeedsRepaint = true; + dirtyRegions.clear(); + dirtyStates.clear(); + } + int i = dirtyRegions.indexOf(decorationRegion); + if (i >= 0) { + dirtyRegions.removeAt(i); + dirtyStates.removeAt(i); + } + + dirtyRegions.append(decorationRegion); + dirtyStates.append(state); + if (!entireDecorationNeedsRepaint) + dirtyClip += clip; + + if (!pendingUpdateRequest) + QApplication::postEvent(managed, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); +} + +void QWSManagerPrivate::clearDirtyRegions() +{ + dirtyRegions.clear(); + dirtyStates.clear(); + dirtyClip = QRegion(); + entireDecorationNeedsRepaint = false; +} + +bool QWSManager::repaintRegion(int decorationRegion, QDecoration::DecorationState state) +{ + Q_D(QWSManager); + + d->dirtyRegion(decorationRegion, state); + return true; +} + +void QWSManager::menu(const QPoint &pos) +{ +#ifdef QT_NO_MENU + Q_UNUSED(pos); +#else + Q_D(QWSManager); + if (d->popup) + delete d->popup; + + // Basic window operation menu + d->popup = new QMenu(); + QApplication::qwsDecoration().buildSysMenu(d->managed, d->popup); + connect(d->popup, SIGNAL(triggered(QAction*)), SLOT(menuTriggered(QAction*))); + + d->popup->popup(pos); + d->activeRegion = QDecoration::None; +#endif // QT_NO_MENU +} + +void QWSManager::menuTriggered(QAction *action) +{ +#ifdef QT_NO_MENU + Q_UNUSED(action); +#else + Q_D(QWSManager); + QApplication::qwsDecoration().menuTriggered(d->managed, action); + d->popup->deleteLater(); + d->popup = 0; +#endif +} + +void QWSManager::startMove() +{ + Q_D(QWSManager); + d->mousePos = QCursor::pos(); + d->activeRegion = QDecoration::Title; + d->active = d->managed; + d->managed->grabMouse(); +} + +void QWSManager::startResize() +{ + Q_D(QWSManager); + d->activeRegion = QDecoration::BottomRight; + d->active = d->managed; + d->managed->grabMouse(); +} + +void QWSManager::maximize() +{ + Q_D(QWSManager); + // find out how much space the decoration needs + const int screen = QApplication::desktop()->screenNumber(d->managed); + const QRect desk = QApplication::desktop()->availableGeometry(screen); + QRect dummy(0, 0, 1, 1); + QRect nr; + QRegion r = QApplication::qwsDecoration().region(d->managed, dummy); + if (r.isEmpty()) { + nr = desk; + } else { + r += dummy; // make sure we get the full window region in case of 0 width borders + QRect rect = r.boundingRect(); + nr = QRect(desk.x()-rect.x(), desk.y()-rect.y(), + desk.width() - (rect.width()==1 ? 0 : rect.width()-1), // ==1 -> dummy + desk.height() - (rect.height()==1 ? 0 : rect.height()-1)); + } + d->managed->setGeometry(nr); +} + +bool QWSManagerPrivate::newCachedRegion(const QPoint &pos) +{ + // Check if anything has changed that would affect the region caching + if (managed->windowFlags() == cached_region.windowFlags + && managed->geometry() == cached_region.windowGeometry + && cached_region.region.contains(pos)) + return false; + + // Update the cached region + int reg = QApplication::qwsDecoration().regionAt(managed, pos); + if (QWidget::mouseGrabber()) + reg = QDecoration::None; + + previousRegionType = cached_region.regionType; + cached_region.regionType = reg; + cached_region.region = QApplication::qwsDecoration().region(managed, managed->geometry(), + reg); + // Make room for borders around the widget, even if the decoration doesn't have a frame. + if (reg && !(reg & int(QDecoration::Borders))) { + cached_region.region -= QApplication::qwsDecoration().region(managed, managed->geometry(), QDecoration::Borders); + } + cached_region.windowFlags = managed->windowFlags(); + cached_region.windowGeometry = managed->geometry(); +// QRect rec = cached_region.region.boundingRect(); +// qDebug("Updated cached region: 0x%04x (%d, %d) (%d, %d, %d, %d)", +// reg, pos.x(), pos.y(), rec.x(), rec.y(), rec.right(), rec.bottom()); + return true; +} + +QT_END_NAMESPACE + +#endif //QT_NO_QWS_MANAGER |