/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Controls module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qquickpopupwindow_p.h" #include #include #include #include QT_BEGIN_NAMESPACE QQuickPopupWindow1::QQuickPopupWindow1() : QQuickWindow(), m_parentItem(0), m_contentItem(0), m_mouseMoved(false), m_needsActivatedEvent(true), m_dismissed(false), m_pressed(false) { setFlags(Qt::Popup); connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(applicationStateChanged(Qt::ApplicationState))); } void QQuickPopupWindow1::applicationStateChanged(Qt::ApplicationState state) { if (state != Qt::ApplicationActive) dismissPopup(); } void QQuickPopupWindow1::show() { qreal posx = x(); qreal posy = y(); // transientParent may not be a QQuickWindow when embedding into widgets if (QWindow *tp = transientParent()) { if (m_parentItem) { QPointF pos = m_parentItem->mapToItem(m_parentItem->window()->contentItem(), QPointF(posx, posy)); posx = pos.x(); posy = pos.y(); } QPoint tlwOffset = tp->mapToGlobal(QPoint()); posx += tlwOffset.x(); posy += tlwOffset.y(); } else if (m_parentItem && m_parentItem->window()) { QPoint offset; QQuickWindow *quickWindow = m_parentItem->window(); QWindow *renderWindow = QQuickRenderControl::renderWindowFor(quickWindow, &offset); QPointF pos = m_parentItem->mapToItem(quickWindow->contentItem(), QPointF(posx, posy)); posx = pos.x(); posy = pos.y(); QPoint parentWindowOffset = (renderWindow ? renderWindow : quickWindow)->mapToGlobal(QPoint()); posx += offset.x() + parentWindowOffset.x(); posy += offset.y() + parentWindowOffset.y(); } if (m_contentItem) { qreal initialWidth = qMax(qreal(1), m_contentItem->width()); qreal initialHeight = qMax(qreal(1), m_contentItem->height()); setGeometry(posx, posy, initialWidth, initialHeight); } else { setPosition(posx, posy); } emit geometryChanged(); if (!qobject_cast(transientParent())) { // No need for parent menu windows if (QQuickWindow *w = qobject_cast(transientParent())) { if (QQuickItem *mg = w->mouseGrabberItem()) mg->ungrabMouse(); } else if (m_parentItem && m_parentItem->window()) { if (QQuickItem *mg = m_parentItem->window()->mouseGrabberItem()) mg->ungrabMouse(); } } QQuickWindow::show(); setMouseGrabEnabled(true); // Needs to be done after calling show() setKeyboardGrabEnabled(true); } void QQuickPopupWindow1::setParentItem(QQuickItem *item) { m_parentItem = item; if (m_parentItem) setTransientParent(m_parentItem->window()); } void QQuickPopupWindow1::setPopupContentItem(QQuickItem *contentItem) { if (!contentItem) return; contentItem->setParentItem(this->contentItem()); connect(contentItem, SIGNAL(widthChanged()), this, SLOT(updateSize())); connect(contentItem, SIGNAL(heightChanged()), this, SLOT(updateSize())); m_contentItem = contentItem; } void QQuickPopupWindow1::updateSize() { setGeometry(x(), y(), popupContentItem()->width(), popupContentItem()->height()); emit geometryChanged(); } void QQuickPopupWindow1::dismissPopup() { m_dismissed = true; emit popupDismissed(); hide(); } void QQuickPopupWindow1::mouseMoveEvent(QMouseEvent *e) { QRect rect = QRect(QPoint(), size()); m_mouseMoved = true; if (rect.contains(e->pos())) { if (e->buttons() != Qt::NoButton) m_pressed = true; QQuickWindow::mouseMoveEvent(e); } else forwardEventToTransientParent(e); } void QQuickPopupWindow1::mousePressEvent(QMouseEvent *e) { m_pressed = true; QRect rect = QRect(QPoint(), size()); if (rect.contains(e->pos())) { QQuickWindow::mousePressEvent(e); } else forwardEventToTransientParent(e); } void QQuickPopupWindow1::mouseReleaseEvent(QMouseEvent *e) { QRect rect = QRect(QPoint(), size()); if (rect.contains(e->pos())) { if (m_mouseMoved) { QMouseEvent pe = QMouseEvent(QEvent::MouseButtonPress, e->pos(), e->button(), e->buttons(), e->modifiers()); QQuickWindow::mousePressEvent(&pe); if (!m_dismissed) QQuickWindow::mouseReleaseEvent(e); } m_mouseMoved = true; // Initial mouse release counts as move. } else { if (m_pressed) forwardEventToTransientParent(e); } m_pressed = false; } void QQuickPopupWindow1::forwardEventToTransientParent(QMouseEvent *e) { bool forwardEvent = true; if (!qobject_cast(transientParent()) && ((m_mouseMoved && e->type() == QEvent::MouseButtonRelease) || e->type() == QEvent::MouseButtonPress)) { // Clicked outside any popup dismissPopup(); forwardEvent = shouldForwardEventAfterDismiss(e); } if (forwardEvent && transientParent()) { QPoint parentPos = transientParent()->mapFromGlobal(mapToGlobal(e->pos())); QMouseEvent pe = QMouseEvent(e->type(), parentPos, e->button(), e->buttons(), e->modifiers()); QGuiApplication::sendEvent(transientParent(), &pe); } } bool QQuickPopupWindow1::shouldForwardEventAfterDismiss(QMouseEvent*) const { return false; } void QQuickPopupWindow1::exposeEvent(QExposeEvent *e) { if (isExposed() && m_needsActivatedEvent) { m_needsActivatedEvent = false; QWindowSystemInterface::handleWindowActivated(this); } else if (!isExposed() && !m_needsActivatedEvent) { m_needsActivatedEvent = true; if (QWindow *tp = transientParent()) QWindowSystemInterface::handleWindowActivated(tp); } QQuickWindow::exposeEvent(e); } void QQuickPopupWindow1::hideEvent(QHideEvent *e) { if (QWindow *tp = !m_needsActivatedEvent ? transientParent() : 0) { m_needsActivatedEvent = true; if (tp->isVisible()) QWindowSystemInterface::handleWindowActivated(tp); } QQuickWindow::hideEvent(e); } /*! \reimp */ bool QQuickPopupWindow1::event(QEvent *event) { //QTBUG-45079 //This is a workaround for popup menu not being closed when using touch input. //Currently mouse synthesized events are not created for touch events which are //outside the qquickwindow. if (event->type() == QEvent::TouchBegin && !qobject_cast(transientParent())) { QRect rect = QRect(QPoint(), size()); QTouchEvent *touch = static_cast(event); QTouchEvent::TouchPoint point = touch->touchPoints().first(); if ((point.state() == Qt::TouchPointPressed) && !rect.contains(point.pos().toPoint())) { //first default handling bool result = QQuickWindow::event(event); //now specific broken case if (!m_dismissed) dismissPopup(); return result; } } return QQuickWindow::event(event); } QT_END_NAMESPACE