diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/3rdparty/phonon/mmf/videooutput.cpp | 24 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/videooutput.h | 1 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/videoplayer.cpp | 77 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/videoplayer.h | 10 | ||||
-rw-r--r-- | src/gui/kernel/qapplication_s60.cpp | 20 | ||||
-rw-r--r-- | src/gui/kernel/qwidget_s60.cpp | 152 |
6 files changed, 246 insertions, 38 deletions
diff --git a/src/3rdparty/phonon/mmf/videooutput.cpp b/src/3rdparty/phonon/mmf/videooutput.cpp index 53178cb..c517c22 100644 --- a/src/3rdparty/phonon/mmf/videooutput.cpp +++ b/src/3rdparty/phonon/mmf/videooutput.cpp @@ -21,6 +21,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include "videooutputobserver.h" #include <QPaintEvent> +#include <QPainter> #include <QMoveEvent> #include <QResizeEvent> @@ -165,16 +166,13 @@ void MMF::VideoOutput::paintEvent(QPaintEvent* event) TRACE("regions %d", event->region().numRects()); TRACE("type %d", event->type()); - QWidget::paintEvent(event); -} - -QPaintEngine* MMF::VideoOutput::paintEngine() const -{ - TRACE_CONTEXT(VideoOutput::sizeHint, EVideoApi); - - QPaintEngine* const engine = QWidget::paintEngine(); - - TRACE_RETURN("0x%08x", engine); +/* + QPainter painter; + painter.begin(this); + painter.setBrush(QColor(0, 0, 0, 255)); // opaque black + painter.drawRects(event->region().rects()); + painter.end(); +*/ } void MMF::VideoOutput::resizeEvent(QResizeEvent* event) @@ -186,9 +184,8 @@ void MMF::VideoOutput::resizeEvent(QResizeEvent* event) QWidget::resizeEvent(event); - if (m_observer) { + if (m_observer) m_observer->videoOutputRegionChanged(); - } } void MMF::VideoOutput::moveEvent(QMoveEvent* event) @@ -200,9 +197,8 @@ void MMF::VideoOutput::moveEvent(QMoveEvent* event) QWidget::moveEvent(event); - if (m_observer) { + if (m_observer) m_observer->videoOutputRegionChanged(); - } } #endif // PHONON_MMF_VIDEOOUTPUT_IS_QWIDGET diff --git a/src/3rdparty/phonon/mmf/videooutput.h b/src/3rdparty/phonon/mmf/videooutput.h index 0da6ea0..bcd9cb4 100644 --- a/src/3rdparty/phonon/mmf/videooutput.h +++ b/src/3rdparty/phonon/mmf/videooutput.h @@ -48,7 +48,6 @@ protected: void paintEvent(QPaintEvent* event); void resizeEvent(QResizeEvent* event); void moveEvent(QMoveEvent* event); - QPaintEngine* paintEngine() const; #endif // PHONON_MMF_VIDEOOUTPUT_IS_QWIDGET #ifdef PHONON_MMF_DEBUG_VIDEO_OUTPUT diff --git a/src/3rdparty/phonon/mmf/videoplayer.cpp b/src/3rdparty/phonon/mmf/videoplayer.cpp index f008edd..736d74f 100644 --- a/src/3rdparty/phonon/mmf/videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/videoplayer.cpp @@ -40,6 +40,7 @@ MMF::VideoPlayer::VideoPlayer() , m_screenDevice(NULL) , m_window(NULL) , m_totalTime(0) + , m_mmfOutputChangePending(false) { construct(); } @@ -50,6 +51,7 @@ MMF::VideoPlayer::VideoPlayer(const AbstractPlayer& player) , m_screenDevice(NULL) , m_window(NULL) , m_totalTime(0) + , m_mmfOutputChangePending(false) { construct(); } @@ -72,6 +74,13 @@ void MMF::VideoPlayer::construct() // TODO: is this the correct way to handle errors which occur when // creating a Symbian object in the constructor of a Qt object? + + // TODO: check whether videoOutput is visible? If not, then the + // corresponding window will not be active, meaning that the + // clipping region will be set to empty and the video will not be + // visible. If this is the case, we should set m_mmfOutputChangePending + // and respond to future showEvents from the videoOutput widget. + TRAPD(err, m_player = CVideoPlayerUtility::NewL ( @@ -106,6 +115,14 @@ MMF::VideoPlayer::~VideoPlayer() void MMF::VideoPlayer::doPlay() { + TRACE_CONTEXT(VideoPlayer::doPlay, EVideoApi); + + // See comment in updateMmfOutput + if(m_mmfOutputChangePending) { + TRACE_0("MMF output change pending - pushing now"); + updateMmfOutput(); + } + m_player->Play(); } @@ -222,6 +239,12 @@ void MMF::VideoPlayer::MvpuoPrepareComplete(TInt aError) videoOutput().setFrameSize(m_frameSize); + // See comment in updateMmfOutput + if(m_mmfOutputChangePending) { + TRACE_0("MMF output change pending - pushing now"); + updateMmfOutput(); + } + emit totalTimeChanged(totalTime()); changeState(StoppedState); } else { @@ -288,12 +311,37 @@ void MMF::VideoPlayer::MvpuoEvent(const TMMFEvent &aEvent) void MMF::VideoPlayer::videoOutputRegionChanged() { TRACE_CONTEXT(VideoPlayer::videoOutputRegionChanged, EVideoInternal); - TRACE_ENTRY_0(); + TRACE_ENTRY("state %d", state()); -#ifdef PHONON_MMF_DEBUG_VIDEO_OUTPUT - videoOutput().dump(); -#endif + getNativeWindowSystemHandles(); + + // See comment in updateMmfOutput + if(state() == LoadingState) + m_mmfOutputChangePending = true; + else + updateMmfOutput(); + + TRACE_EXIT_0(); +} +void MMF::VideoPlayer::updateMmfOutput() +{ + TRACE_CONTEXT(VideoPlayer::updateMmfOutput, EVideoInternal); + TRACE_ENTRY_0(); + + // Calling SetDisplayWindowL is a no-op unless the MMF controller has + // been loaded, so we shouldn't do it. Instead, the + // m_mmfOutputChangePending flag is used to record the fact that we + // need to call SetDisplayWindowL, and this is checked in + // MvpuoPrepareComplete, at which point the MMF controller has been + // loaded. + + // TODO: check whether videoOutput is visible? If not, then the + // corresponding window will not be active, meaning that the + // clipping region will be set to empty and the video will not be + // visible. If this is the case, we should set m_mmfOutputChangePending + // and respond to future showEvents from the videoOutput widget. + getNativeWindowSystemHandles(); TRAPD(err, @@ -309,7 +357,9 @@ void MMF::VideoPlayer::videoOutputRegionChanged() TRACE("SetDisplayWindowL error %d", err); setError(NormalError); } - + + m_mmfOutputChangePending = false; + TRACE_EXIT_0(); } @@ -389,11 +439,22 @@ void MMF::VideoPlayer::getNativeWindowSystemHandles() // HACK: why isn't control->Rect updated following a call to // updateGeometry on the parent widget? m_windowRect = TRect(0, 100, 320, 250); + m_clipRect = m_windowRect; #else - m_windowRect = control->Rect(); -#endif - + m_windowRect = TRect( + control->DrawableWindow()->AbsPosition(), + control->DrawableWindow()->Size()); + + //m_clipRect = control->Rect(); m_clipRect = m_windowRect; +#endif + + TRACE("windowRect %d %d - %d %d", + m_windowRect.iTl.iX, m_windowRect.iTl.iY, + m_windowRect.iBr.iX, m_windowRect.iBr.iY); + TRACE("clipRect %d %d - %d %d", + m_clipRect.iTl.iX, m_clipRect.iTl.iY, + m_clipRect.iBr.iX, m_clipRect.iBr.iY); } diff --git a/src/3rdparty/phonon/mmf/videoplayer.h b/src/3rdparty/phonon/mmf/videoplayer.h index da373ab..887a26b 100644 --- a/src/3rdparty/phonon/mmf/videoplayer.h +++ b/src/3rdparty/phonon/mmf/videoplayer.h @@ -85,9 +85,10 @@ private: // AbstractPlayer virtual void videoOutputChanged(); - + void getNativeWindowSystemHandles(); - + void updateMmfOutput(); + private: CVideoPlayerUtility* m_player; QScopedPointer<VideoOutput> m_dummyVideoOutput; @@ -98,11 +99,14 @@ private: RWindowBase* m_window; TRect m_windowRect; TRect m_clipRect; - + QSize m_frameSize; qint64 m_totalTime; + bool m_mmfOutputChangePending; + }; + } } diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 44ac380..67b974e 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -316,10 +316,24 @@ QSymbianControl::QSymbianControl(QWidget *w) void QSymbianControl::ConstructL(bool topLevel, bool desktop) { if (!desktop) - { - if (topLevel) + { + if (topLevel or !qwidget->parentWidget()) CreateWindowL(S60->windowGroup()); - + else + /** + * TODO: in order to avoid creating windows for all ancestors of + * this widget up to the root window, the parameter passed to + * CreateWindowL should be + * qwidget->parentWidget()->effectiveWinId(). However, if we do + * this, then we need to take care of re-parenting when a window + * is created for a widget between this one and the root window. + */ + CreateWindowL(qwidget->parentWidget()->winId()); + + // Necessary in order to be able to track the activation status of + // the control's window + qwidget->d_func()->createTLExtra(); + SetFocusing(true); m_longTapDetector = QLongTapTimer::NewL(this); } diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index f8a5be5..a516266 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -150,9 +150,143 @@ void QWidgetPrivate::setSoftKeys_sys(const QList<QAction*> &softkeys) #endif } -void QWidgetPrivate::setWSGeometry(bool /* dontShow */, const QRect & /* rect */) -{ +void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &) +{ + // Note: based on x11 implementation + + static const int XCOORD_MAX = 16383; + static const int WRECT_MAX = 16383; + + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + + /* + There are up to four different coordinate systems here: + Qt coordinate system for this widget. + X coordinate system for this widget (relative to wrect). + Qt coordinate system for parent + X coordinate system for parent (relative to parent's wrect). + */ + + QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX); + QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX); + QRect wrect; + //xrect is the X geometry of my widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys) + QRect xrect = data.crect; + + const QWidget *const parent = q->parentWidget(); + QRect parentWRect = parent->data->wrect; + + if (parentWRect.isValid()) { + // parent is clipped, and we have to clip to the same limit as parent + if (!parentWRect.contains(xrect)) { + xrect &= parentWRect; + wrect = xrect; + //translate from parent's to my Qt coord sys + wrect.translate(-data.crect.topLeft()); + } + //translate from parent's Qt coords to parent's X coords + xrect.translate(-parentWRect.topLeft()); + + } else { + // parent is not clipped, we may or may not have to clip + + if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) { + // This is where the main optimization is: we are already + // clipped, and if our clip is still valid, we can just + // move our window, and do not need to move or clip + // children + + QRect vrect = xrect & parent->rect(); + vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords + if (data.wrect.contains(vrect)) { + xrect = data.wrect; + xrect.translate(data.crect.topLeft()); + if (data.winid) { + data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height())); + data.winid->DrawNow(); + } + return; + } + } + + if (!validRange.contains(xrect)) { + // we are too big, and must clip + xrect &=wrectRange; + wrect = xrect; + wrect.translate(-data.crect.topLeft()); + //parent's X coord system is equal to parent's Qt coord + //sys, so we don't need to map xrect. + } + + } + + // unmap if we are outside the valid window system coord system + bool outsideRange = !xrect.isValid(); + bool mapWindow = false; + if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) { + q->setAttribute(Qt::WA_OutsideWSRange, outsideRange); + if (outsideRange) { + if (data.winid) + data.winid->DrawableWindow()->SetVisible(EFalse); + q->setAttribute(Qt::WA_Mapped, false); + } else if (!q->isHidden()) { + mapWindow = true; + } + } + if (outsideRange) + return; + + bool jump = (data.wrect != wrect); + data.wrect = wrect; + + + // and now recursively for all children... + // ### can be optimized + for (int i = 0; i < children.size(); ++i) { + QObject *object = children.at(i); + if (object->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(object); + if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created)) + w->d_func()->setWSGeometry(jump); + } + } + + if (data.winid) { + // move ourselves to the new position and map (if necessary) after + // the movement. Rationale: moving unmapped windows is much faster + // than moving mapped windows + if (!parent->internalWinId()) + xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0))); + data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height())); + if(!jump) + data.winid->DrawNow(); + } + + //to avoid flicker, we have to show children after the helper widget has moved + if (jump) { + for (int i = 0; i < children.size(); ++i) { + QObject *object = children.at(i); + if (object->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(object); + if (!w->testAttribute(Qt::WA_OutsideWSRange) && !w->testAttribute(Qt::WA_Mapped) && !w->isHidden()) { + w->setAttribute(Qt::WA_Mapped); + if (w->internalWinId()) + w->data->winid->DrawableWindow()->SetVisible(ETrue); + } + } + } + } + + if (jump && data.winid) + data.winid->DrawNow(TRect(0, 0, wrect.width(), wrect.height())); + + if (mapWindow and !dontShow) { + q->setAttribute(Qt::WA_Mapped); + if (q->internalWinId()) + q->internalWinId()->DrawableWindow()->SetVisible(ETrue); + } } void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) @@ -358,9 +492,6 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de } QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control, ECoeStackPriorityDefault, stackingFlags)); - WId parentw = parentWidget->effectiveWinId(); - QT_TRAP_THROWING(control->SetContainerWindowL(*parentw)); - q->setAttribute(Qt::WA_WState_Created); int x, y, w, h; data.crect.getRect(&x, &y, &w, &h); @@ -390,7 +521,7 @@ void QWidgetPrivate::show_sys() return; } - if (q->isWindow() && q->internalWinId()) { + if (q->internalWinId()) { WId id = q->internalWinId(); if (!extra->topextra->activated) { @@ -398,12 +529,15 @@ void QWidgetPrivate::show_sys() extra->topextra->activated = 1; } id->MakeVisible(true); - id->SetFocus(true); + + if(q->isWindow()) + id->SetFocus(true); // Force setting of the icon after window is made visible, // this is needed even WA_SetWindowIcon is not set, as in that case we need // to reset to the application level window icon - setWindowIcon_sys(true); + if(q->isWindow()) + setWindowIcon_sys(true); } invalidateBuffer(q->rect()); @@ -415,7 +549,7 @@ void QWidgetPrivate::hide_sys() Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); deactivateWidgetCleanup(); WId id = q->internalWinId(); - if (q->isWindow() && id) { + if (id) { if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged() id->SetFocus(false); id->MakeVisible(false); |