/************************************************************************** ** ** This file is part of Qt Simulator ** ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (info@qt.nokia.com) ** ** ** GNU Lesser General Public License Usage ** ** 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.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** Other Usage ** ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** If you have questions regarding the use of this file, please contact ** Nokia at info@qt.nokia.com. ** **************************************************************************/ #include "deviceitem.h" #include "widget.h" #include "application.h" #include "displaywidget.h" #include "qsimulatordata_p.h" #include "mouseindicator.h" #include "widgetmanager.h" #include "pinchmodefilter.h" #include "panmodefilter.h" #include "swipemodefilter.h" #ifndef QT_NO_PHONON #include "phononvideowidget.h" #endif #include #include #include #include #include #include #include #include class Sleeper : QThread { public: using QThread::msleep; }; static int bytesForFormat(QImage::Format format) { //qDebug() << "Size: " << (QImage(16,16, format).bytesPerLine() / 16); return QImage(16,16, format).bytesPerLine() / 16; } Widget::Widget(QRect geometry, QImage::Format f, const QString &t, Application* who, int id, const QString &sharedMemoryName, QGraphicsItem *parent) : QGraphicsItem(parent) , format(f) , widgetId(id) , title(t) , owner(who) , mManager(0) , memory(0) , width(geometry.width()) , height(geometry.height()) , fullscreen(false) , mMenuBar(0) , wantsUpdate(false) , memoryFilled(false) , mMaemo5Stacked(false) , mOrientation(Qt::WA_AutoOrientation) , mSharedMemoryName(sharedMemoryName) , mMouseInputMode(MultiPointTouchUi::defaultMode) , mFilterItem(0) { //Commented out, in order to be //able to easily re-enable mouse tracking //setAcceptHoverEvents(true); setFlag(QGraphicsItem::ItemIsFocusable); setFlag(QGraphicsItem::ItemIgnoresParentOpacity); setPos(geometry.topLeft()); setCursor(QCursor()); createMemory(); } Widget::~Widget() { scene()->removeItem(this); delete memory; } QRectF Widget::boundingRect() const { return QRectF(0, 0, width, height); } void Widget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); Q_UNUSED(widget); if (!memoryFilled || !mWidgetVisible) return; memory->lock(); QImage image((uchar*)memory->data(), width, height, format); painter->drawImage(QPoint(0,0), image); memory->unlock(); } bool Widget::createMemory() { int size = width * height * bytesForFormat(format); if (memory && size == memory->size()) return true; if (memory) { delete memory; memory = 0; } if (size < 0) return false; else if (size == 0) size = 1; const QString key = mSharedMemoryName; //qDebug() << "Creating widget memory:" << size << key; memory = new QSharedMemory(key); QTime time; const int timeout = 1500; while (!memory->create(size, QSharedMemory::ReadWrite)) { if (memory->error() == QSharedMemory::AlreadyExists) { if (!memory->attach(QSharedMemory::ReadWrite)) qFatal("Could not attach to existing shared memory, error %s", qPrintable(memory->errorString())); if (memory->size() < size) qFatal("Shared memory already exists, and is too small: %d where %d required", memory->size(), size); break; } if (time.isNull()) time.start(); else if (time.elapsed() >= timeout) { qWarning() << "Could not create display memory."; delete memory; memory = 0; return false; } else { qWarning() << "Could not create display memory. Error: " << memory->errorString() << ". Retrying..."; Sleeper::msleep(10); } } memory->lock(); uchar* data = (uchar*) memory->data(); QImage displayImage(data, width, height, format); QPainter imagePainter(&displayImage); QBrush brush(Qt::magenta); imagePainter.fillRect(0,0, width, height, brush); imagePainter.end(); memory->unlock(); memoryFilled = false; return true; } QRect Widget::geometry() const { return QRect(x(), y(), width, height); } void Widget::setGeometry(QRect g) { prepareGeometryChange(); setPos(g.topLeft()); width = g.width(); height = g.height(); createMemory(); } void Widget::mousePressEvent(QGraphicsSceneMouseEvent* ev) { switch (mMouseInputMode) { case MultiPointTouchUi::defaultMode: handleMouseEvent(QEvent::MouseButtonPress, ev); break; case MultiPointTouchUi::freeMode: mManager->runCurrentGestureScript(); break; default: break; } } void Widget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* ev) { switch (mMouseInputMode) { case MultiPointTouchUi::defaultMode: handleMouseEvent(QEvent::MouseButtonDblClick, ev); break; default: break; } } void Widget::mouseReleaseEvent(QGraphicsSceneMouseEvent* ev) { switch (mMouseInputMode) { case MultiPointTouchUi::defaultMode: handleMouseEvent(QEvent::MouseButtonRelease, ev); break; default: break; } } void Widget::mouseMoveEvent(QGraphicsSceneMouseEvent* ev) { switch (mMouseInputMode) { case MultiPointTouchUi::defaultMode: handleMouseEvent(QEvent::MouseMove, ev); break; default: break; } } void Widget::hoverMoveEvent(QGraphicsSceneHoverEvent *ev) { switch (mMouseInputMode) { case MultiPointTouchUi::defaultMode: QtSimulatorPrivate::RemoteMetacall::call(owner->socket(), QtSimulatorPrivate::NoSync, "dispatchMouseEvent", widgetId, static_cast(QEvent::MouseMove), mapToItem(owner->display(), ev->pos() - offset).toPoint(), static_cast(Qt::NoButton), static_cast(Qt::NoButton), static_cast(ev->modifiers())); ev->accept(); break; default: break; } } void Widget::handleMouseEvent(QEvent::Type type, QGraphicsSceneMouseEvent *ev) { if (!mWidgetVisible) { ev->ignore(); return; } QtSimulatorPrivate::RemoteMetacall::call(owner->socket(), QtSimulatorPrivate::NoSync, "dispatchMouseEvent", widgetId, static_cast(type), mapToItem(owner->display(), ev->pos() - offset).toPoint(), static_cast(ev->button()), static_cast(ev->buttons()), static_cast(ev->modifiers())); ev->accept(); } void Widget::keyPressEvent(QKeyEvent* ev) { handleKeyEvent(ev); } void Widget::keyReleaseEvent(QKeyEvent* ev) { handleKeyEvent(ev); } void Widget::handleKeyEvent(QKeyEvent* ev) { if (!mWidgetVisible) { ev->ignore(); return; } QtSimulatorPrivate::RemoteMetacall::call(owner->socket(), QtSimulatorPrivate::NoSync, "dispatchKeyEvent", widgetId, static_cast(ev->type()), static_cast(ev->key()), static_cast(ev->modifiers()), ev->text(), ev->isAutoRepeat(), static_cast(ev->count())); ev->accept(); } void Widget::event(QEvent *e) { if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd) { QTouchEvent *ev = static_cast(e); QtSimulatorPrivate::TouchEventData touchEventData; touchEventData.type = static_cast(ev->type()); touchEventData.deviceType = static_cast(ev->deviceType()); touchEventData.modifiers = static_cast(ev->modifiers()); touchEventData.touchPointStates = static_cast(ev->touchPointStates()); foreach (const QTouchEvent::TouchPoint &tp, ev->touchPoints()) { QtSimulatorPrivate::TouchPointData touchPoint; touchPoint.id = tp.id(); touchPoint.state = tp.state(); touchPoint.rect = tp.rect(); touchPoint.sceneRect = tp.sceneRect(); touchPoint.screenRect = tp.screenRect(); touchPoint.normalizedPos = tp.normalizedPos(); touchPoint.startPos = tp.startPos(); touchPoint.startScenePos = tp.startScenePos(); touchPoint.startScreenPos = tp.startScreenPos(); touchPoint.startNormalizedPos = tp.startNormalizedPos(); touchPoint.lastPos = tp.lastPos(); touchPoint.lastScenePos = tp.lastScenePos(); touchPoint.lastScreenPos = tp.lastScreenPos(); touchPoint.lastNormalizedPos = tp.lastNormalizedPos(); touchPoint.pressure = tp.pressure(); touchEventData.touchPoints.append(touchPoint); } QtSimulatorPrivate::RemoteMetacall::call(owner->socket(), QtSimulatorPrivate::NoSync, "dispatchTouchEvent", widgetId, touchEventData); ev->accept(); } } void Widget::updateOffset(const QPoint &newOffset) { if (offset != newOffset) { setPos(pos() - offset + newOffset); offset = newOffset; } } void Widget::setFullscreen(bool full) { fullscreen = full; } bool Widget::isFullScreen() const { return fullscreen; } bool Widget::isWidgetVisible() const { return mWidgetVisible; } void Widget::setWidgetVisible(bool visible) { mWidgetVisible = visible; update(); } void Widget::setMouseInputMode(MultiPointTouchUi::InputMode newMode) { if (mFilterItem) { removeSceneEventFilter(mFilterItem); delete mFilterItem; mFilterItem = 0; } switch (newMode) { case MultiPointTouchUi::pinchMode: mFilterItem = new PinchModeFilter(this); installSceneEventFilter(mFilterItem); break; case MultiPointTouchUi::panMode: mFilterItem = new PanModeFilter(this); installSceneEventFilter(mFilterItem); break; case MultiPointTouchUi::swipeMode: mFilterItem = new SwipeModeFilter(this); installSceneEventFilter(mFilterItem); break; default: break; } mMouseInputMode = newMode; }