/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui 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 http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qapplication_p.h" #include "qsessionmanager.h" #include "qevent.h" #include "qeventdispatcher_s60_p.h" #include "qwidget.h" #include "qdesktopwidget.h" #include "private/qbackingstore_p.h" #include "qt_s60_p.h" #include "private/qevent_p.h" #include "qstring.h" #include "qdebug.h" #include "qimage.h" #include "private/qkeymapper_p.h" #include "private/qfont_p.h" #ifndef QT_NO_STYLE_S60 #include "private/qs60style_p.h" #endif #include "private/qwindowsurface_s60_p.h" #include "qpaintengine.h" #include "private/qmenubar_p.h" #include "apgwgnam.h" // For CApaWindowGroupName #include // For CMdaAudioToneUtility #if !defined(QT_NO_IM) && defined(Q_WS_S60) #include "qinputcontext.h" #include #endif // !defined(QT_NO_IM) && defined(Q_WS_S60) #include "private/qstylesheetstyle_p.h" QT_BEGIN_NAMESPACE #if defined(QT_DEBUG) static bool appNoGrab = false; // Grabbing enabled #endif Q_GLOBAL_STATIC(QS60Data, qt_s60Data); extern bool qt_sendSpontaneousEvent(QObject*,QEvent*); extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp QWidget *qt_button_down = 0; // widget got last button-down QS60Data* qGlobalS60Data() { return qt_s60Data(); } bool qt_nograb() // application no-grab option { #if defined(QT_DEBUG) return appNoGrab; #else return false; #endif } // Modified from http://www3.symbian.com/faq.nsf/0/0F1464EE96E737E780256D5E00503DD1?OpenDocument class QS60Beep : public CBase, public MMdaAudioToneObserver { public: static QS60Beep* NewL(TInt aFrequency, TTimeIntervalMicroSeconds iDuration); void Play(); ~QS60Beep(); private: void ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds iDuration); void MatoPrepareComplete(TInt aError); void MatoPlayComplete(TInt aError); private: typedef enum { EBeepNotPrepared, EBeepPrepared, EBeepPlaying } TBeepState; private: CMdaAudioToneUtility* iToneUtil; TBeepState iState; TInt iFrequency; TTimeIntervalMicroSeconds iDuration; }; QS60Beep::~QS60Beep() { delete iToneUtil; } QS60Beep* QS60Beep::NewL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration) { QS60Beep* self=new (ELeave) QS60Beep(); CleanupStack::PushL(self); self->ConstructL(aFrequency, aDuration); CleanupStack::Pop(); return self; }; void QS60Beep::ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration) { iToneUtil=CMdaAudioToneUtility::NewL(*this); iState=EBeepNotPrepared; iFrequency=aFrequency; iDuration=aDuration; iToneUtil->PrepareToPlayTone(iFrequency,iDuration); } void QS60Beep::Play() { if(iState!=EBeepNotPrepared){ if(iState==EBeepPlaying) { iToneUtil->CancelPlay(); iState=EBeepPrepared; } } iToneUtil->Play(); iState=EBeepPlaying; } void QS60Beep::MatoPrepareComplete(TInt aError) { if(aError==KErrNone) { iState=EBeepPrepared; } } void QS60Beep::MatoPlayComplete(TInt aError) { Q_UNUSED(aError); iState=EBeepPrepared; } QHash QApplicationPrivate::scanCodeCache; static Qt::KeyboardModifiers mapToQtModifiers(TUint s60Modifiers) { Qt::KeyboardModifiers result = Qt::NoModifier; if (s60Modifiers & EModifierKeypad) result |= Qt::KeypadModifier; if (s60Modifiers & EModifierShift || s60Modifiers & EModifierLeftShift || s60Modifiers & EModifierRightShift) result |= Qt::ShiftModifier; if (s60Modifiers & EModifierCtrl || s60Modifiers & EModifierLeftCtrl || s60Modifiers & EModifierRightCtrl) result |= Qt::ControlModifier; if (s60Modifiers & EModifierAlt || s60Modifiers & EModifierLeftAlt || s60Modifiers & EModifierRightAlt) result |= Qt::AltModifier; return result; } static void mapS60MouseEventTypeToQt(QEvent::Type *type, Qt::MouseButton *button, const TPointerEvent *pEvent) { switch (pEvent->iType) { case TPointerEvent::EButton1Down: *type = QEvent::MouseButtonPress; *button = Qt::LeftButton; break; case TPointerEvent::EButton1Up: *type = QEvent::MouseButtonRelease; *button = Qt::LeftButton; break; case TPointerEvent::EButton2Down: *type = QEvent::MouseButtonPress; *button = Qt::MidButton; break; case TPointerEvent::EButton2Up: *type = QEvent::MouseButtonRelease; *button = Qt::MidButton; break; case TPointerEvent::EButton3Down: *type = QEvent::MouseButtonPress; *button = Qt::RightButton; break; case TPointerEvent::EButton3Up: *type = QEvent::MouseButtonRelease; *button = Qt::RightButton; break; case TPointerEvent::EDrag: *type = QEvent::MouseMove; *button = Qt::NoButton; break; case TPointerEvent::EMove: // Qt makes no distinction between move and drag *type = QEvent::MouseMove; *button = Qt::NoButton; break; default: *type = QEvent::None; *button = Qt::NoButton; break; } if (pEvent->iModifiers & EModifierDoubleClick){ *type = QEvent::MouseButtonDblClick; } if (*type == QEvent::MouseButtonPress || *type == QEvent::MouseButtonDblClick) QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | (*button); else if (*type == QEvent::MouseButtonRelease) QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~(*button)); QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & Qt::MouseButtonMask; } //### Can be replaced with CAknLongTapDetector if animation is required. //NOTE: if CAknLongTapDetector is used make sure it gets variated out of 3.1 and 3.2,. //also MLongTapObserver needs to be changed to MAknLongTapDetectorCallBack if CAknLongTapDetector is used. class QLongTapTimer : public CTimer { public: static QLongTapTimer* NewL(QAbstractLongTapObserver *observer); QLongTapTimer(QAbstractLongTapObserver *observer); void ConstructL(); public: void PointerEventL(const TPointerEvent &event); void RunL(); protected: private: QAbstractLongTapObserver *m_observer; TPointerEvent m_event; QPoint m_pressedCoordinates; int m_dragDistance; }; QLongTapTimer* QLongTapTimer::NewL(QAbstractLongTapObserver *observer) { QLongTapTimer* self = new QLongTapTimer(observer); self->ConstructL(); return self; } void QLongTapTimer::ConstructL() { CTimer::ConstructL(); } QLongTapTimer::QLongTapTimer(QAbstractLongTapObserver *observer):CTimer(CActive::EPriorityHigh) { m_observer = observer; m_dragDistance = qApp->startDragDistance(); CActiveScheduler::Add(this); } void QLongTapTimer::PointerEventL(const TPointerEvent& event) { if ( event.iType == TPointerEvent::EDrag || event.iType == TPointerEvent::EButtonRepeat) { QPoint diff(QPoint(event.iPosition.iX,event.iPosition.iY) - m_pressedCoordinates); if (diff.manhattanLength() < m_dragDistance) return; } Cancel(); m_event = event; if (event.iType == TPointerEvent::EButton1Down) { m_pressedCoordinates = QPoint(event.iPosition.iX,event.iPosition.iY); // must be same as KLongTapDelay in aknlongtapdetector.h After(800000); } } void QLongTapTimer::RunL() { if (m_observer) m_observer->HandleLongTapEventL(m_event.iPosition, m_event.iParentPosition); } QSymbianControl::QSymbianControl(QWidget *w) : CCoeControl(), qwidget(w), m_ignoreFocusChanged(false) { } void QSymbianControl::ConstructL(bool topLevel, bool desktop) { if (!desktop) { if (topLevel) CreateWindowL(S60->windowGroup()); SetFocusing(true); m_longTapDetector = QLongTapTimer::NewL(this); } } QSymbianControl::~QSymbianControl() { S60->appUi()->RemoveFromStack(this); delete m_longTapDetector; } void QSymbianControl::setWidget(QWidget *w) { qwidget = w; } void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ) { QWidget *alienWidget; QPoint widgetPos = QPoint(aPenEventLocation.iX, aPenEventLocation.iY); QPoint globalPos = QPoint(aPenEventScreenLocation.iX,aPenEventScreenLocation.iY); alienWidget = qwidget->childAt(widgetPos); if (!alienWidget) alienWidget = qwidget; QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~Qt::LeftButton); QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | Qt::RightButton; QMouseEvent mEvent(QEvent::MouseButtonPress, alienWidget->mapFrom(qwidget, widgetPos), globalPos, Qt::RightButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier); sendMouseEvent(alienWidget, &mEvent); m_previousEventLongTap = true; } void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent) { m_longTapDetector->PointerEventL(pEvent); QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent)); } void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) { //### refactor me, getting too complex QMouseEvent::Type type; Qt::MouseButton button; mapS60MouseEventTypeToQt(&type, &button, &pEvent); if (m_previousEventLongTap) if (type == QEvent::MouseButtonRelease){ button = Qt::RightButton; QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & ~Qt::RightButton; m_previousEventLongTap = false; } if (type == QMouseEvent::None) return; // store events for later sending/saving QWidget *alienWidget; typedef QPair Event; QList events; QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY); TPoint controlScreenPos = PositionRelativeToScreen(); QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos; if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick) { // get the button press target alienWidget = qwidget->childAt(widgetPos); if (!alienWidget) alienWidget = qwidget; S60->mousePressTarget = alienWidget; //pointer grab SetGloballyCapturing(ETrue); SetPointerCapture(ETrue); } else if (type == QEvent::MouseButtonRelease) { //release pointer grab SetGloballyCapturing(EFalse); SetPointerCapture(EFalse); } alienWidget = S60->mousePressTarget; if (alienWidget != S60->lastPointerEventTarget) if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove) { //moved to another widget, create enter and leave events if (S60->lastPointerEventTarget) { QMouseEvent mEventLeave(QEvent::Leave, S60->lastPointerEventTarget->mapFromGlobal(S60->lastCursorPos), S60->lastCursorPos, button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); events.append(Event(S60->lastPointerEventTarget,mEventLeave)); } QMouseEvent mEventEnter(QEvent::Enter, alienWidget->mapFromGlobal(globalPos), globalPos, button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); events.append(Event(alienWidget,mEventEnter)); } S60->lastCursorPos = globalPos; S60->lastPointerEventPos = widgetPos; S60->lastPointerEventTarget = alienWidget; if (alienWidget) { QMouseEvent mEvent(type, alienWidget->mapFromGlobal(globalPos), globalPos, button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); events.append(Event(alienWidget,mEvent)); QEventDispatcherS60 *dispatcher; // It is theoretically possible for someone to install a different event dispatcher. if ((dispatcher = qobject_cast(alienWidget->d_func()->threadData->eventDispatcher)) != 0) { if (dispatcher->excludeUserInputEvents()) { for (int i=0;i < events.count();++i) { Event next = events[i]; dispatcher->saveInputEvent(this, next.first, new QMouseEvent(next.second)); } return; } } } for (int i=0;i < events.count();++i) { Event next = events[i]; sendMouseEvent(next.first, &(next.second)); } } void QSymbianControl::sendMouseEvent(QWidget *widget, QMouseEvent *mEvent) { qt_sendSpontaneousEvent(widget, mEvent); } TKeyResponse QSymbianControl::OfferKeyEventL(const TKeyEvent& keyEvent, TEventCode type) { TKeyResponse r = EKeyWasNotConsumed; QT_TRYCATCH_LEAVING(r = OfferKeyEvent(keyEvent, type)); return r; } TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCode type) { switch (type) { //case EEventKeyDown: // <-- Intentionally left out. See below. case EEventKeyUp: case EEventKey: { // S60 has a confusing way of delivering key events. There are three types of // events: EKeyEvent, EKeyEventDown and EKeyEventUp. When a key is pressed, the // two first events are generated. When releasing the key, the last one is // generated. // Because S60 does not generate keysyms for EKeyEventDown and EKeyEventUp events, // we need to do some special tricks to map it to the Qt way. First, we completely // discard EKeyEventDown events, since they are redundant. Second, since // EKeyEventUp does not give us a keysym, we need to cache the keysyms from // the EKeyEvent events. This is what resolveS60ScanCode does. // ### hackish way to send Qt application to background when pressing right softkey /* if( keyEvent.iScanCode == EStdKeyDevice1 ) { S60->window_group->SetOrdinalPosition(-1); qApp->setActiveWindow(0); return EKeyWasNotConsumed; } */ TUint s60Keysym = QApplicationPrivate::resolveS60ScanCode(keyEvent.iScanCode, keyEvent.iCode); int keyCode; if (s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) { // Normal characters keys. keyCode = s60Keysym; } else { // Special S60 keys. keyCode = qt_keymapper_private()->mapS60KeyToQt(s60Keysym); } Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers); QKeyEventEx qKeyEvent(type == EEventKeyUp ? QEvent::KeyRelease : QEvent::KeyPress, keyCode, mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods), false, 1, keyEvent.iScanCode, s60Keysym, mods); // WId wid = reinterpret_cast(keyEvent.Handle())->Child(); // if (!wid) // Could happen if window isn't shown yet. // return EKeyWasNotConsumed; QWidget *widget; widget = QWidget::keyboardGrabber(); if (!widget) { if (QApplicationPrivate::popupWidgets != 0) { widget = QApplication::activePopupWidget()->focusWidget(); if (!widget) { widget = QApplication::activePopupWidget(); } } else { widget = QApplicationPrivate::focus_widget; if (!widget) { widget = qwidget; } } } QEventDispatcherS60 *dispatcher; // It is theoretically possible for someone to install a different event dispatcher. if ((dispatcher = qobject_cast(widget->d_func()->threadData->eventDispatcher)) != 0) { if (dispatcher->excludeUserInputEvents()) { dispatcher->saveInputEvent(this, widget, new QKeyEventEx(qKeyEvent)); return EKeyWasConsumed; } } return sendKeyEvent(widget, &qKeyEvent); } } return EKeyWasNotConsumed; } void QSymbianControl::sendInputEvent(QWidget *widget, QInputEvent *inputEvent) { switch (inputEvent->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: sendKeyEvent(widget, static_cast(inputEvent)); break; case QEvent::MouseButtonDblClick: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: sendMouseEvent(widget, static_cast(inputEvent)); break; default: // Shouldn't get here. Q_ASSERT_X(0 == 1, "QSymbianControl::sendInputEvent()", "inputEvent->type() is unknown"); break; } } TKeyResponse QSymbianControl::sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent) { #if !defined(QT_NO_IM) && defined(Q_WS_S60) if (widget && widget->isEnabled() && widget->testAttribute(Qt::WA_InputMethodEnabled)) { QInputContext *qic = widget->inputContext(); if(qic && qic->filterEvent(keyEvent)) return EKeyWasConsumed; } #endif // !defined(QT_NO_IM) && defined(Q_WS_S60) if (widget && qt_sendSpontaneousEvent(widget, keyEvent)) if (keyEvent->isAccepted()) return EKeyWasConsumed; return EKeyWasNotConsumed; } #if !defined(QT_NO_IM) && defined(Q_WS_S60) TCoeInputCapabilities QSymbianControl::InputCapabilities() const { QWidget *w = 0; if(qwidget->hasFocus()) { w = qwidget; } else { w = qwidget->focusWidget(); } QCoeFepInputContext *ic; if (w && w->isEnabled() && w->testAttribute(Qt::WA_InputMethodEnabled) && (ic = qobject_cast(w->inputContext()))) { return ic->inputCapabilities(); } else { return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0); } } #endif void QSymbianControl::Draw(const TRect& r) const { QWindowSurface *surface = qwidget->windowSurface(); if (!surface) return; QPaintEngine *engine = surface->paintDevice()->paintEngine(); if (!engine) return; if (engine->type() == QPaintEngine::Raster) { QS60WindowSurface *s60Surface = static_cast(qwidget->windowSurface()); CFbsBitmap *bitmap = s60Surface->symbianBitmap(); CWindowGc &gc = SystemGc(); if (qwidget->d_func()->isOpaque) gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); gc.BitBlt(r.iTl, bitmap, r); } else { surface->flush(qwidget, QRegion(qt_TRect2QRect(r)), QPoint()); } } void QSymbianControl::SizeChanged() { CCoeControl::SizeChanged(); QSize oldSize = qwidget->size(); QSize newSize(Size().iWidth, Size().iHeight); if (oldSize != newSize) { QRect cr = qwidget->geometry(); cr.setSize(newSize); qwidget->data->crect = cr; if (qwidget->isVisible()) { QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData(); bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); if (!slowResize && tlwExtra) tlwExtra->inTopLevelResize = true; QResizeEvent e(newSize, oldSize); qt_sendSpontaneousEvent(qwidget, &e); if (!qwidget->testAttribute(Qt::WA_StaticContents)) qwidget->d_func()->syncBackingStore(); if (!slowResize && tlwExtra) tlwExtra->inTopLevelResize = false; } } } void QSymbianControl::PositionChanged() { CCoeControl::PositionChanged(); QPoint oldPos = qwidget->geometry().topLeft(); QPoint newPos(Position().iX, Position().iY); if (oldPos != newPos) { QRect cr = qwidget->geometry(); cr.moveTopLeft(newPos); qwidget->data->crect = cr; QTLWExtra *top = qwidget->d_func()->maybeTopData(); if (top) top->normalGeometry = cr; if (qwidget->isVisible()) { QMoveEvent e(newPos, oldPos); qt_sendSpontaneousEvent(qwidget, &e); } else { QMoveEvent * e = new QMoveEvent(newPos, oldPos); QApplication::postEvent(qwidget, e); } } } void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */) { if (m_ignoreFocusChanged) return; // Popups never get focused, but still receive the FocusChanged when they are hidden. if (QApplicationPrivate::popupWidgets != 0 || (qwidget->windowType() & Qt::Popup) == Qt::Popup) return; QEvent *deferredFocusEvent = new QEvent(QEvent::SymbianDeferredFocusChanged); QApplication::postEvent(qwidget, deferredFocusEvent); } void QSymbianControl::HandleResourceChange(int resourceType) { switch (resourceType) { case KInternalStatusPaneChange: qwidget->d_func()->setWindowIcon_sys(true); break; case KUidValueCoeFontChangeEvent: // font change event break; #ifdef Q_WS_S60 case KEikDynamicLayoutVariantSwitch: { if (qwidget->isFullScreen()) { SetExtentToWholeScreen(); } else if (qwidget->isMaximized()) { TRect r = static_cast(S60->appUi())->ClientRect(); SetExtent(r.iTl, r.Size()); } break; } #endif default: break; } CCoeControl::HandleResourceChange(resourceType); } void QSymbianControl::CancelLongTapTimer() { m_longTapDetector->Cancel(); } TTypeUid::Ptr QSymbianControl::MopSupplyObject(TTypeUid id) { if (id.iUid == ETypeId) return id.MakePtr(this); return CCoeControl::MopSupplyObject(id); } void qt_init(QApplicationPrivate * /* priv */, int) { #ifdef QT_NO_DEBUG if (!qgetenv("QT_S60_AUTO_FLUSH_WSERV").isEmpty()) #endif S60->wsSession().SetAutoFlush(ETrue); S60->updateScreenSize(); TDisplayMode mode = S60->screenDevice()->DisplayMode(); S60->screenDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(mode); RProcess me; TSecureId securId = me.SecureId(); S60->uid = securId.operator TUid(); /* ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag int argc = priv->argc; char **argv = priv->argv; // Get command line params int j = argc ? 1 : 0; for (int i=1; iappend(popup); if (QApplicationPrivate::popupWidgets->count() == 1 && !qt_nograb()) { Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created)); WId id = popup->effectiveWinId(); id->SetPointerCapture(true); id->SetGloballyCapturing(true); } // popups are not focus-handled by the window system (the first // popup grabbed the keyboard), so we have to do that manually: A // new popup gets the focus if (QApplication::focusWidget()) static_cast(QApplication::focusWidget()->effectiveWinId())->CancelLongTapTimer(); QWidget *fw = popup->focusWidget(); if (fw) { fw->setFocus(Qt::PopupFocusReason); } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup fw = QApplication::focusWidget(); if (fw) { QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason); q_func()->sendEvent(fw, &e); } } } void QApplicationPrivate::closePopup(QWidget *popup) { if (!QApplicationPrivate::popupWidgets) return; QApplicationPrivate::popupWidgets->removeAll(popup); if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup delete QApplicationPrivate::popupWidgets; QApplicationPrivate::popupWidgets = 0; if (!qt_nograb()) { // grabbing not disabled Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created)); WId id = popup->effectiveWinId(); id->SetPointerCapture(false); id->SetGloballyCapturing(false); if (QWidgetPrivate::mouseGrabber != 0) QWidgetPrivate::mouseGrabber->grabMouse(); if (QWidgetPrivate::keyboardGrabber != 0) QWidgetPrivate::keyboardGrabber->grabKeyboard(); QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget() : q_func()->focusWidget(); if (fw) { if (fw != q_func()->focusWidget()) { fw->setFocus(Qt::PopupFocusReason); } else { QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason); q_func()->sendEvent(fw, &e); } } } } else { // popups are not focus-handled by the window system (the // first popup grabbed the keyboard), so we have to do that // manually: A popup was closed, so the previous popup gets // the focus. QWidget* aw = QApplicationPrivate::popupWidgets->last(); if (QWidget *fw = QApplication::focusWidget()) { QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason); q_func()->sendEvent(fw, &e); } } } QWidget * QApplication::topLevelAt(QPoint const& point) { QWidget *found = 0; int lowestZ = INT_MAX; QWidgetList list = QApplication::topLevelWidgets(); for (int i = 0; i < list.count(); ++i) { QWidget *widget = list.at(i); if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) { Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created)); if (widget->geometry().adjusted(0,0,1,1).contains(point)) { // At this point we know there is a Qt widget under the point. // Now we need to make sure it is the top most in the z-order. RDrawableWindow* rw = widget->d_func()->topData()->rwindow; int z = rw->OrdinalPosition(); if (z < lowestZ) { lowestZ = z; found = widget; } } } } return found; } void QApplication::alert(QWidget * /* widget */, int /* duration */) { // TODO: Implement QApplication::alert(QWidget *widget, int duration) } int QApplication::doubleClickInterval() { TTimeIntervalMicroSeconds32 us; TInt distance; S60->wsSession().GetDoubleClickSettings(us, distance); return (us.Int() / 1000); } void QApplication::setDoubleClickInterval(int ms) { TTimeIntervalMicroSeconds32 newUs( ms * 1000); TTimeIntervalMicroSeconds32 us; TInt distance; S60->wsSession().GetDoubleClickSettings(us, distance); if (us != newUs) S60->wsSession().SetDoubleClick(newUs, distance); } int QApplication::keyboardInputInterval() { return QApplicationPrivate::keyboard_input_time; } void QApplication::setKeyboardInputInterval(int ms) { QApplicationPrivate::keyboard_input_time = ms; } int QApplication::cursorFlashTime() { return QApplicationPrivate::cursor_flash_time; } void QApplication::setCursorFlashTime(int msecs) { QApplicationPrivate::cursor_flash_time = msecs; } void QApplication::beep() { TInt frequency=440; TTimeIntervalMicroSeconds duration(500000); QS60Beep* beep=NULL; TRAPD(err, beep=QS60Beep::NewL(frequency, duration)); if(!err) { beep->Play(); } delete beep; beep=NULL; } int QApplication::s60ProcessEvent(TWsEvent *event) { bool handled = s60EventFilter(event); if (handled) return 1; // Qt event handling. Handle some events regardless of if the handle is in our // widget map or not. CCoeControl* control = reinterpret_cast(event->Handle()); const bool controlInMap = QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control); switch (event->Type()) { #if !defined(QT_NO_IM) && defined(Q_WS_S60) case EEventKey: case EEventKeyUp: case EEventKeyDown: { // The control doesn't seem to be any of our widgets, so rely on the focused // widget instead. If the user needs the control, it can be found inside the // event structure. QWidget *w = qApp ? qApp->focusWidget() : 0; if (w) { QInputContext *ic = w->inputContext(); if (ic && ic->s60FilterEvent(w, event)) { return 1; } else { return 0; } } break; } #endif case EEventPointerEnter: if (controlInMap) return 1; // Qt::Enter will be generated in HandlePointerL break; case EEventPointerExit: if (controlInMap) { if (S60) { // mouseEvent outside our window, send leave event to last focused widget QMouseEvent mEvent(QEvent::Leave, S60->lastPointerEventPos, S60->lastCursorPos, Qt::NoButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier); if (S60->lastPointerEventTarget) qt_sendSpontaneousEvent(S60->lastPointerEventTarget,&mEvent); S60->lastPointerEventTarget = 0; } return 1; } break; case EEventScreenDeviceChanged: if (S60) S60->updateScreenSize(); if (qt_desktopWidget) { QSize oldSize = qt_desktopWidget->size(); qt_desktopWidget->data->crect.setWidth(S60->screenWidthInPixels); qt_desktopWidget->data->crect.setHeight(S60->screenHeightInPixels); QResizeEvent e(qt_desktopWidget->size(), oldSize); QApplication::sendEvent(qt_desktopWidget, &e); } return 0; // Propagate to CONE case EEventWindowVisibilityChanged: if (controlInMap) { const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged(); QWidget *w = QWidgetPrivate::mapper->value(control); if (!w->d_func()->maybeTopData()) break; if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible) { delete w->d_func()->topData()->backingStore; w->d_func()->topData()->backingStore = 0; } else if ((visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible) && !w->d_func()->maybeBackingStore()) { w->d_func()->topData()->backingStore = new QWidgetBackingStore(w); w->update(); } return 1; } break; default: break; } if (!controlInMap) return -1; return 0; } bool QApplication::s60EventFilter(TWsEvent * /* aEvent */) { return false; } /*! Handles commands which are typically handled by CAknAppUi::HandleCommandL() Qts Ui integration into Symbian is partially achieved by deriving from CAknAppUi. Currently, exit, menu and softkey commands are handled \sa s60EventFilter(), s60ProcessEvent() */ void QApplication::symbianHandleCommand(int command) { switch (command) { case EEikCmdExit: #ifdef Q_WS_S60 case EAknSoftkeyExit: #endif exit(); break; default: if (command >= SOFTKEYSTART && command <= SOFTKEYEND) { int index= command-SOFTKEYSTART; QWidget *focused = QApplication::focusWidget(); QWidget *softKeySource = focused ? focused : QApplication::activeWindow(); const QList& softKeys = softKeySource->softKeys(); Q_ASSERT(index < softKeys.count()); softKeys.at(index)->activate(QAction::Trigger); } #ifdef Q_WS_S60 else QMenuBarPrivate::symbianCommands(command); #endif break; } } void QApplication::symbianResourceChange(int type) { switch (type) { #ifdef Q_WS_S60 case KEikDynamicLayoutVariantSwitch: { if (S60) S60->updateScreenSize(); #ifndef QT_NO_STYLE_S60 QS60Style *s60Style = 0; #ifndef QT_NO_STYLE_STYLESHEET QStyleSheetStyle *proxy = qobject_cast(QApplication::style()); if (proxy) s60Style = qobject_cast(proxy->baseStyle()); else #endif s60Style = qobject_cast(QApplication::style()); if (s60Style) s60Style->d_func()->handleDynamicLayoutVariantSwitch(); #endif } break; #ifndef QT_NO_STYLE_S60 case KAknsMessageSkinChange: if (QS60Style *s60Style = qobject_cast(QApplication::style())) s60Style->d_func()->handleSkinChange(); break; #endif #endif // Q_WS_S60 default: break; } } #ifndef QT_NO_WHEELEVENT int QApplication::wheelScrollLines() { return QApplicationPrivate::wheel_scroll_lines; } void QApplication::setWheelScrollLines(int n) { QApplicationPrivate::wheel_scroll_lines = n; } #endif //QT_NO_WHEELEVENT bool QApplication::isEffectEnabled(Qt::UIEffect /* effect */) { // TODO: Implement QApplication::isEffectEnabled(Qt::UIEffect effect) return false; } void QApplication::setEffectEnabled(Qt::UIEffect /* effect */, bool /* enable */) { // TODO: Implement QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable) } TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym) { if (keysym) { // If keysym is specified, cache it. scanCodeCache.insert(scanCode, keysym); return keysym; } else { // If not, retrieve the cached version. return scanCodeCache[scanCode]; } } void QApplicationPrivate::initializeMultitouch_sys() { } void QApplicationPrivate::cleanupMultitouch_sys() { } #ifndef QT_NO_SESSIONMANAGER QSessionManager::QSessionManager(QApplication * /* app */, QString & /* id */, QString& /* key */) { } QSessionManager::~QSessionManager() { } bool QSessionManager::allowsInteraction() { return false; } void QSessionManager::cancel() { } #endif //QT_NO_SESSIONMANAGER QT_END_NAMESPACE