diff options
Diffstat (limited to 'src/plugins')
155 files changed, 4163 insertions, 3085 deletions
diff --git a/src/plugins/accessible/widgets/itemviews.cpp b/src/plugins/accessible/widgets/itemviews.cpp index d460ec2c98..86c7812553 100644 --- a/src/plugins/accessible/widgets/itemviews.cpp +++ b/src/plugins/accessible/widgets/itemviews.cpp @@ -1010,15 +1010,6 @@ void QAccessibleTableCell::unselectCell() view->selectionModel()->select(m_index, QItemSelectionModel::Deselect); } -void QAccessibleTableCell::rowColumnExtents(int *row, int *column, int *rowExtents, int *columnExtents, bool *selected) const -{ - *row = m_index.row(); - *column = m_index.column(); - *rowExtents = 1; - *columnExtents = 1; - *selected = isSelected(); -} - QAccessibleInterface *QAccessibleTableCell::table() const { return QAccessible::queryAccessibleInterface(view); diff --git a/src/plugins/accessible/widgets/itemviews.h b/src/plugins/accessible/widgets/itemviews.h index 09dacde7a2..72b2339dd3 100644 --- a/src/plugins/accessible/widgets/itemviews.h +++ b/src/plugins/accessible/widgets/itemviews.h @@ -194,7 +194,6 @@ public: virtual QList<QAccessibleInterface*> rowHeaderCells() const; virtual int rowIndex() const; virtual bool isSelected() const; - virtual void rowColumnExtents(int *row, int *column, int *rowExtents, int *columnExtents, bool *selected) const; virtual QAccessibleInterface* table() const; //action interface diff --git a/src/plugins/bearer/blackberry/qbbengine.cpp b/src/plugins/bearer/blackberry/qbbengine.cpp index ab1ba9aa19..37093a09ec 100644 --- a/src/plugins/bearer/blackberry/qbbengine.cpp +++ b/src/plugins/bearer/blackberry/qbbengine.cpp @@ -98,10 +98,9 @@ interfaceType(netstatus_interface_type_t type) return QNetworkConfiguration::BearerBluetooth; case NETSTATUS_INTERFACE_TYPE_CELLULAR: - //### TODO not sure which BearerType would be the best - //to return here. We need to be able to get more - //information on the bearer type in order to return - //the exact match. + // The exact bearer type is determined in QNetworkConfiguration + // at the time this info is queried, because opposed to the + // information here the type might change quickly. return QNetworkConfiguration::Bearer2G; case NETSTATUS_INTERFACE_TYPE_VPN: diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp index 116c6cfa7d..c222b62a36 100644 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp +++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp @@ -47,6 +47,8 @@ #include <QtCore/QStringList> #include <QtCore/QString> +#include <algorithm> + #include <xkbcommon/xkbcommon.h> #ifdef XKBCOMMON_0_2_0 @@ -445,6 +447,6 @@ void TableGenerator::orderComposeTable() // Stable-sorting to ensure that the item that appeared before the other in the // original container will still appear first after the sort. This property is // needed to handle the cases when user re-defines already defined key sequence - qStableSort(m_composeTable.begin(), m_composeTable.end(), Compare()); + std::stable_sort(m_composeTable.begin(), m_composeTable.end(), Compare()); } diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp index 611b9fdd9b..65b93b1a45 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp @@ -45,6 +45,8 @@ #include <QtGui/QKeyEvent> #include <QtCore/QDebug> +#include <algorithm> + QT_BEGIN_NAMESPACE //#define DEBUG_COMPOSING @@ -170,7 +172,7 @@ static bool isDuplicate(const QComposeTableElement &lhs, const QComposeTableElem bool QComposeInputContext::checkComposeTable() { QVector<QComposeTableElement>::const_iterator it = - qLowerBound(m_composeTable.constBegin(), m_composeTable.constEnd(), m_composeBuffer, Compare()); + std::lower_bound(m_composeTable.constBegin(), m_composeTable.constEnd(), m_composeBuffer, Compare()); // prevent dereferencing an 'end' iterator, which would result in a crash if (it == m_composeTable.constEnd()) diff --git a/src/plugins/platforminputcontexts/maliit/contextadaptor.cpp b/src/plugins/platforminputcontexts/maliit/contextadaptor.cpp deleted file mode 100644 index 134ff94f6b..0000000000 --- a/src/plugins/platforminputcontexts/maliit/contextadaptor.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, 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. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "contextadaptor.h" -#include <QtCore/QByteArray> -#include <QtCore/QList> -#include <QtCore/QMetaObject> -#include <QtCore/QMap> -#include <QtCore/QString> -#include <QtCore/QStringList> -#include <QtCore/QVariant> - -#include "qmaliitplatforminputcontext.h" - -/* - * Implementation of adaptor class Inputcontext1Adaptor - */ - -Inputcontext1Adaptor::Inputcontext1Adaptor(QObject *parent) - : QDBusAbstractAdaptor(parent) -{ - // constructor - setAutoRelaySignals(true); -} - -Inputcontext1Adaptor::~Inputcontext1Adaptor() -{ - // destructor -} - -void Inputcontext1Adaptor::activationLostEvent() -{ - // handle method call com.meego.inputmethod.inputcontext1.activationLostEvent - QMetaObject::invokeMethod(parent(), "activationLostEvent"); -} - -void Inputcontext1Adaptor::commitString(const QString &in0, int in1, int in2, int in3) -{ - // handle method call com.meego.inputmethod.inputcontext1.commitString - QMetaObject::invokeMethod(parent(), "commitString", Q_ARG(QString, in0), Q_ARG(int, in1), Q_ARG(int, in2), Q_ARG(int, in3)); -} - -void Inputcontext1Adaptor::updatePreedit(const QDBusMessage &message) -{ - // handle method call com.meego.inputmethod.inputcontext1.updatePreedit - QMetaObject::invokeMethod(parent(), "updatePreedit", Q_ARG(QDBusMessage, message)); -} - -void Inputcontext1Adaptor::copy() -{ - // handle method call com.meego.inputmethod.inputcontext1.copy - QMetaObject::invokeMethod(parent(), "copy"); -} - -void Inputcontext1Adaptor::imInitiatedHide() -{ - // handle method call com.meego.inputmethod.inputcontext1.imInitiatedHide - QMetaObject::invokeMethod(parent(), "imInitiatedHide"); -} - -void Inputcontext1Adaptor::keyEvent(int in0, int in1, int in2, const QString &in3, bool in4, int in5, uchar in6) -{ - // handle method call com.meego.inputmethod.inputcontext1.keyEvent - QMetaObject::invokeMethod(parent(), "keyEvent", Q_ARG(int, in0), Q_ARG(int, in1), Q_ARG(int, in2), Q_ARG(QString, in3), Q_ARG(bool, in4), Q_ARG(int, in5), Q_ARG(uchar, in6)); -} - -void Inputcontext1Adaptor::paste() -{ - // handle method call com.meego.inputmethod.inputcontext1.paste - QMetaObject::invokeMethod(parent(), "paste"); -} - -bool Inputcontext1Adaptor::preeditRectangle(int &out1, int &out2, int &out3, int &out4) -{ - // handle method call com.meego.inputmethod.inputcontext1.preeditRectangle - return static_cast<QMaliitPlatformInputContext *>(parent())->preeditRectangle(out1, out2, out3, out4); -} - -bool Inputcontext1Adaptor::selection(QString &out1) -{ - // handle method call com.meego.inputmethod.inputcontext1.selection - return static_cast<QMaliitPlatformInputContext *>(parent())->selection(out1); -} - -void Inputcontext1Adaptor::setDetectableAutoRepeat(bool in0) -{ - // handle method call com.meego.inputmethod.inputcontext1.setDetectableAutoRepeat - QMetaObject::invokeMethod(parent(), "setDetectableAutoRepeat", Q_ARG(bool, in0)); -} - -void Inputcontext1Adaptor::setGlobalCorrectionEnabled(bool in0) -{ - // handle method call com.meego.inputmethod.inputcontext1.setGlobalCorrectionEnabled - QMetaObject::invokeMethod(parent(), "setGlobalCorrectionEnabled", Q_ARG(bool, in0)); -} - -void Inputcontext1Adaptor::setLanguage(const QString &in0) -{ - // handle method call com.meego.inputmethod.inputcontext1.setLanguage - QMetaObject::invokeMethod(parent(), "setLanguage", Q_ARG(QString, in0)); -} - -void Inputcontext1Adaptor::setRedirectKeys(bool in0) -{ - // handle method call com.meego.inputmethod.inputcontext1.setRedirectKeys - QMetaObject::invokeMethod(parent(), "setRedirectKeys", Q_ARG(bool, in0)); -} - -void Inputcontext1Adaptor::setSelection(int in0, int in1) -{ - // handle method call com.meego.inputmethod.inputcontext1.setSelection - QMetaObject::invokeMethod(parent(), "setSelection", Q_ARG(int, in0), Q_ARG(int, in1)); -} - -void Inputcontext1Adaptor::updateInputMethodArea(int in0, int in1, int in2, int in3) -{ - // handle method call com.meego.inputmethod.inputcontext1.updateInputMethodArea - QMetaObject::invokeMethod(parent(), "updateInputMethodArea", Q_ARG(int, in0), Q_ARG(int, in1), Q_ARG(int, in2), Q_ARG(int, in3)); -} - diff --git a/src/plugins/platforminputcontexts/maliit/contextadaptor.h b/src/plugins/platforminputcontexts/maliit/contextadaptor.h deleted file mode 100644 index e959a7cb5b..0000000000 --- a/src/plugins/platforminputcontexts/maliit/contextadaptor.h +++ /dev/null @@ -1,148 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, 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. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef CONTEXT_H_1318935171 -#define CONTEXT_H_1318935171 - -#include <QtCore/QObject> -#include <QtCore/QByteArray> -#include <QtCore/QList> -#include <QtCore/QMap> -#include <QtCore/QString> -#include <QtCore/QStringList> -#include <QtCore/QVariant> -#include <QtDBus/QtDBus> - -/* - * Adaptor class for interface com.meego.inputmethod.inputcontext1 - */ -class Inputcontext1Adaptor: public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "com.meego.inputmethod.inputcontext1") - Q_CLASSINFO("D-Bus Introspection", "" -" <interface name=\"com.meego.inputmethod.inputcontext1\">\n" -" <method name=\"activationLostEvent\"/>\n" -" <method name=\"imInitiatedHide\"/>\n" -" <method name=\"commitString\">\n" -" <arg type=\"s\"/>\n" -" <arg type=\"i\"/>\n" -" <arg type=\"i\"/>\n" -" <arg type=\"i\"/>\n" -" </method>\n" -" <method name=\"updatePreedit\">\n" -" <arg type=\"s\"/>\n" -" <arg type=\"a(iii)\"/>\n" -" <arg type=\"i\"/>\n" -" <arg type=\"i\"/>\n" -" <arg type=\"i\"/>\n" -" </method>\n" -" <method name=\"keyEvent\">\n" -" <arg type=\"i\"/>\n" -" <arg type=\"i\"/>\n" -" <arg type=\"i\"/>\n" -" <arg type=\"s\"/>\n" -" <arg type=\"b\"/>\n" -" <arg type=\"i\"/>\n" -" <arg type=\"y\"/>\n" -" </method>\n" -" <method name=\"updateInputMethodArea\">\n" -" <arg type=\"i\"/>\n" -" <arg type=\"i\"/>\n" -" <arg type=\"i\"/>\n" -" <arg type=\"i\"/>\n" -" </method>\n" -" <method name=\"setGlobalCorrectionEnabled\">\n" -" <arg type=\"b\"/>\n" -" </method>\n" -" <method name=\"preeditRectangle\">\n" -" <arg direction=\"out\" type=\"b\"/>\n" -" <arg direction=\"out\" type=\"i\"/>\n" -" <arg direction=\"out\" type=\"i\"/>\n" -" <arg direction=\"out\" type=\"i\"/>\n" -" <arg direction=\"out\" type=\"i\"/>\n" -" </method>\n" -" <method name=\"copy\"/>\n" -" <method name=\"paste\"/>\n" -" <method name=\"setRedirectKeys\">\n" -" <arg type=\"b\"/>\n" -" </method>\n" -" <method name=\"setDetectableAutoRepeat\">\n" -" <arg type=\"b\"/>\n" -" </method>\n" -" <method name=\"setSelection\">\n" -" <arg type=\"i\"/>\n" -" <arg type=\"i\"/>\n" -" </method>\n" -" <method name=\"selection\">\n" -" <arg direction=\"out\" type=\"b\"/>\n" -" <arg direction=\"out\" type=\"s\"/>\n" -" </method>\n" -" <method name=\"setLanguage\">\n" -" <arg type=\"s\"/>\n" -" </method>\n" -" </interface>\n" - "") -public: - Inputcontext1Adaptor(QObject *parent); - virtual ~Inputcontext1Adaptor(); - -public: // PROPERTIES -public Q_SLOTS: // METHODS - void activationLostEvent(); - void commitString(const QString &in0, int in1, int in2, int in3); - void updatePreedit(const QDBusMessage &message); - void copy(); - void imInitiatedHide(); - void keyEvent(int in0, int in1, int in2, const QString &in3, bool in4, int in5, uchar in6); - void paste(); - bool preeditRectangle(int &out1, int &out2, int &out3, int &out4); - bool selection(QString &out1); - void setDetectableAutoRepeat(bool in0); - void setGlobalCorrectionEnabled(bool in0); - void setLanguage(const QString &in0); - void setRedirectKeys(bool in0); - void setSelection(int in0, int in1); - void updateInputMethodArea(int in0, int in1, int in2, int in3); -Q_SIGNALS: // SIGNALS -}; - -#endif diff --git a/src/plugins/platforminputcontexts/maliit/maliit.json b/src/plugins/platforminputcontexts/maliit/maliit.json deleted file mode 100644 index f828e1426e..0000000000 --- a/src/plugins/platforminputcontexts/maliit/maliit.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Keys": [ "maliit" ] -} diff --git a/src/plugins/platforminputcontexts/maliit/maliit.pro b/src/plugins/platforminputcontexts/maliit/maliit.pro deleted file mode 100644 index 1e50f7289b..0000000000 --- a/src/plugins/platforminputcontexts/maliit/maliit.pro +++ /dev/null @@ -1,19 +0,0 @@ -TARGET = maliitplatforminputcontextplugin - -PLUGIN_TYPE = platforminputcontexts -PLUGIN_CLASS_NAME = QMaliitPlatformInputContextPlugin -load(qt_plugin) - -QT += dbus gui-private -SOURCES += $$PWD/qmaliitplatforminputcontext.cpp \ - $$PWD/serverproxy.cpp \ - $$PWD/serveraddressproxy.cpp \ - $$PWD/contextadaptor.cpp \ - $$PWD/main.cpp - -HEADERS += $$PWD/qmaliitplatforminputcontext.h \ - $$PWD/serverproxy.h \ - $$PWD/serveraddressproxy.h \ - $$PWD/contextadaptor.h - -OTHER_FILES += $$PWD/maliit.json diff --git a/src/plugins/platforminputcontexts/maliit/qmaliitplatforminputcontext.cpp b/src/plugins/platforminputcontexts/maliit/qmaliitplatforminputcontext.cpp deleted file mode 100644 index 6d748d44a1..0000000000 --- a/src/plugins/platforminputcontexts/maliit/qmaliitplatforminputcontext.cpp +++ /dev/null @@ -1,583 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, 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. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include "qmaliitplatforminputcontext.h" - -#include <QtDebug> -#include <QTextCharFormat> -#include <QGuiApplication> -#include <qwindow.h> -#include <qevent.h> -#include <qscreen.h> - -#include "serveraddressproxy.h" -#include "serverproxy.h" -#include "contextadaptor.h" - -#include <sys/types.h> -#include <signal.h> - -#include <QtDBus> - -QT_BEGIN_NAMESPACE - -enum { debug = 0 }; - -enum InputPanelVisibility { - InputPanelHidden, - InputPanelShowRequested, - InputPanelShown -}; - -enum MaliitOrientationAngle { - Angle0 = 0, - Angle90 = 90, - Angle180 = 180, - Angle270 = 270 -}; - -static int orientationAngle(Qt::ScreenOrientation orientation) -{ - switch (orientation) { - case Qt::PrimaryOrientation: // Urgh. - case Qt::PortraitOrientation: - return Angle270; - case Qt::LandscapeOrientation: - return Angle0; - case Qt::InvertedPortraitOrientation: - return Angle90; - case Qt::InvertedLandscapeOrientation: - return Angle180; - } - return Angle0; -} - -// From MTF: -//! Content type for text entries. Used at least with MTextEdit -enum TextContentType { - //! all characters allowed - FreeTextContentType, - - //! only integer numbers allowed - NumberContentType, - - //! allows numbers and certain other characters used in phone numbers - PhoneNumberContentType, - - //! allows only characters permitted in email address - EmailContentType, - - //! allows only character permitted in URL address - UrlContentType, - - //! allows content with user defined format - CustomContentType -}; -static TextContentType contentTypeFromHints(Qt::InputMethodHints hints) -{ - TextContentType type = FreeTextContentType; - hints &= Qt::ImhExclusiveInputMask; - - if (hints == Qt::ImhFormattedNumbersOnly || hints == Qt::ImhDigitsOnly) - type = NumberContentType; - else if (hints == Qt::ImhDialableCharactersOnly) - type = PhoneNumberContentType; - else if (hints == Qt::ImhEmailCharactersOnly) - type = EmailContentType; - else if (hints == Qt::ImhUrlCharactersOnly) - type = UrlContentType; - - return type; -} - -/// From Maliit's namespace.h -enum MaliitEventRequestType { - EventRequestBoth, //!< Both a Qt::KeyEvent and a signal - EventRequestSignalOnly, //!< Only a signal - EventRequestEventOnly //!< Only a Qt::KeyEvent -}; - -static QString maliitServerAddress() -{ - org::maliit::Server::Address serverAddress(QStringLiteral("org.maliit.server"), QStringLiteral("/org/maliit/server/address"), QDBusConnection::sessionBus()); - - QString address(serverAddress.address()); - - // Fallback to old socket when org.maliit.server service is not available - if (address.isEmpty()) - return QStringLiteral("unix:path=/tmp/meego-im-uiserver/imserver_dbus"); - - return address; -} - -class QMaliitPlatformInputContextPrivate -{ -public: - QMaliitPlatformInputContextPrivate(QMaliitPlatformInputContext *qq); - ~QMaliitPlatformInputContextPrivate() - { - delete adaptor; - delete server; - } - - void sendStateUpdate(bool focusChanged = false); - - QDBusConnection connection; - ComMeegoInputmethodUiserver1Interface *server; - Inputcontext1Adaptor *adaptor; - - QMap<QString, QVariant> imState; - - InputPanelVisibility visibility; - - bool valid; - bool active; - bool correctionEnabled; - QRect keyboardRect; - QString preedit; - QPointer<QWindow> window; - QMaliitPlatformInputContext *q; -}; - - -QMaliitPlatformInputContext::QMaliitPlatformInputContext() - : d(new QMaliitPlatformInputContextPrivate(this)) -{ - if (debug) - qDebug() << "QMaliitPlatformInputContext::QMaliitPlatformInputContext()"; -} - -QMaliitPlatformInputContext::~QMaliitPlatformInputContext(void) -{ - delete d; -} - -bool QMaliitPlatformInputContext::isValid() const -{ - return d->valid; -} - -void QMaliitPlatformInputContext::invokeAction(QInputMethod::Action action, int x) -{ - if (!inputMethodAccepted()) - return; - - if (action == QInputMethod::Click) { - if (x < 0 || x >= d->preedit.length()) { - reset(); - return; - } - - d->imState["preeditClickPos"] = x; - d->sendStateUpdate(); - // The first argument is the mouse pos and the second is the - // preedit rectangle. Both are unused on the server side. - d->server->mouseClickedOnPreedit(0, 0, 0, 0, 0, 0); - } else { - QPlatformInputContext::invokeAction(action, x); - } -} - -void QMaliitPlatformInputContext::reset() -{ - const bool hadPreedit = !d->preedit.isEmpty(); - if (hadPreedit && inputMethodAccepted()) { - // ### selection - QInputMethodEvent event; - event.setCommitString(d->preedit); - QGuiApplication::sendEvent(qGuiApp->focusObject(), &event); - d->preedit.clear(); - } - - QDBusPendingReply<void> reply = d->server->reset(); - if (hadPreedit) - reply.waitForFinished(); -} - -void QMaliitPlatformInputContext::update(Qt::InputMethodQueries queries) -{ - if (!qGuiApp->focusObject()) - return; - - QInputMethodQueryEvent query(queries); - QGuiApplication::sendEvent(qGuiApp->focusObject(), &query); - - if (queries & Qt::ImSurroundingText) - d->imState["surroundingText"] = query.value(Qt::ImSurroundingText); - if (queries & Qt::ImCursorPosition) - d->imState["cursorPosition"] = query.value(Qt::ImCursorPosition); - if (queries & Qt::ImAnchorPosition) - d->imState["anchorPosition"] = query.value(Qt::ImAnchorPosition); - if (queries & Qt::ImCursorRectangle) { - QRect rect = query.value(Qt::ImCursorRectangle).toRect(); - rect = qGuiApp->inputMethod()->inputItemTransform().mapRect(rect); - QWindow *window = qGuiApp->focusWindow(); - if (window) - d->imState["cursorRectangle"] = QRect(window->mapToGlobal(rect.topLeft()), rect.size()); - } - - if (queries & Qt::ImCurrentSelection) - d->imState["hasSelection"] = !query.value(Qt::ImCurrentSelection).toString().isEmpty(); - - if (queries & Qt::ImHints) { - Qt::InputMethodHints hints = Qt::InputMethodHints(query.value(Qt::ImHints).toUInt()); - - d->imState["predictionEnabled"] = !(hints & Qt::ImhNoPredictiveText); - d->imState["autocapitalizationEnabled"] = !(hints & Qt::ImhNoAutoUppercase); - d->imState["hiddenText"] = (hints & Qt::ImhHiddenText) != 0; - - d->imState["contentType"] = contentTypeFromHints(hints); - } - - d->sendStateUpdate(/*focusChanged*/true); -} - -QRectF QMaliitPlatformInputContext::keyboardRect() const -{ - return d->keyboardRect; -} - -void QMaliitPlatformInputContext::activationLostEvent() -{ - d->active = false; - d->visibility = InputPanelHidden; -} - -void QMaliitPlatformInputContext::commitString(const QString &string, int replacementStart, int replacementLength, int /* cursorPos */) -{ - if (!inputMethodAccepted()) - return; - - d->preedit.clear(); - - if (debug) - qWarning() << "CommitString" << string; - // ### start/cursorPos - QInputMethodEvent event; - event.setCommitString(string, replacementStart, replacementLength); - QCoreApplication::sendEvent(qGuiApp->focusObject(), &event); -} - -void QMaliitPlatformInputContext::updatePreedit(const QDBusMessage &message) -{ - if (!inputMethodAccepted()) - return; - - QList<QVariant> arguments = message.arguments(); - if (arguments.count() != 5) { - qWarning() << "QMaliitPlatformInputContext::updatePreedit: Received message from input method server with wrong parameters."; - return; - } - - d->preedit = arguments[0].toString(); - - QList<QInputMethodEvent::Attribute> attributes; - - const QDBusArgument formats = arguments[1].value<QDBusArgument>(); - formats.beginArray(); - while (!formats.atEnd()) { - formats.beginStructure(); - int start, length, preeditFace; - formats >> start >> length >> preeditFace; - formats.endStructure(); - - QTextCharFormat format; - - enum PreeditFace { - PreeditDefault, - PreeditNoCandidates, - PreeditKeyPress, //!< Used for displaying the hwkbd key just pressed - PreeditUnconvertible, //!< Inactive preedit region, not clickable - PreeditActive, //!< Preedit region with active suggestions - - }; - switch (PreeditFace(preeditFace)) { - case PreeditDefault: - case PreeditKeyPress: - format.setUnderlineStyle(QTextCharFormat::SingleUnderline); - format.setUnderlineColor(QColor(0, 0, 0)); - break; - case PreeditNoCandidates: - format.setUnderlineStyle(QTextCharFormat::SingleUnderline); - format.setUnderlineColor(QColor(255, 0, 0)); - break; - case PreeditUnconvertible: - format.setForeground(QBrush(QColor(128, 128, 128))); - break; - case PreeditActive: - format.setForeground(QBrush(QColor(153, 50, 204))); - format.setFontWeight(QFont::Bold); - break; - default: - break; - } - - attributes << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, start, length, format); - } - formats.endArray(); - - int replacementStart = arguments[2].toInt(); - int replacementLength = arguments[3].toInt(); - int cursorPos = arguments[4].toInt(); - - if (debug) - qWarning() << "updatePreedit" << d->preedit << replacementStart << replacementLength << cursorPos; - - if (cursorPos >= 0) - attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursorPos, 1, QVariant()); - - QInputMethodEvent event(d->preedit, attributes); - if (replacementStart || replacementLength) - event.setCommitString(QString(), replacementStart, replacementLength); - QCoreApplication::sendEvent(qGuiApp->focusObject(), &event); -} - -void QMaliitPlatformInputContext::copy() -{ - // Not supported at the moment. -} - -void QMaliitPlatformInputContext::imInitiatedHide() -{ - d->visibility = InputPanelHidden; - emitInputPanelVisibleChanged(); - // ### clear focus -} - -void QMaliitPlatformInputContext::keyEvent(int type, int key, int modifiers, const QString &text, - bool autoRepeat, int count, uchar requestType_) -{ - MaliitEventRequestType requestType = MaliitEventRequestType(requestType_); - if (requestType == EventRequestSignalOnly) { - qWarning() << "Maliit: Signal emitted key events are not supported."; - return; - } - - // HACK: This code relies on QEvent::Type for key events and modifiers to be binary compatible between - // Qt 4 and 5. - QEvent::Type eventType = static_cast<QEvent::Type>(type); - if (type != QEvent::KeyPress && type != QEvent::KeyRelease) { - qWarning() << "Maliit: Unknown key event type" << type; - return; - } - - QKeyEvent event(eventType, key, static_cast<Qt::KeyboardModifiers>(modifiers), - text, autoRepeat, count); - if (d->window) - QCoreApplication::sendEvent(d->window.data(), &event); -} - -void QMaliitPlatformInputContext::paste() -{ - // Not supported at the moment. -} - -bool QMaliitPlatformInputContext::preeditRectangle(int &x, int &y, int &width, int &height) -{ - // ### - QRect r = qApp->inputMethod()->cursorRectangle().toRect(); - if (!r.isValid()) - return false; - x = r.x(); - y = r.y(); - width = r.width(); - height = r.height(); - return true; -} - -bool QMaliitPlatformInputContext::selection(QString &selection) -{ - selection.clear(); - - if (!inputMethodAccepted()) - return false; - - QInputMethodQueryEvent query(Qt::ImCurrentSelection); - QGuiApplication::sendEvent(qGuiApp->focusObject(), &query); - QVariant value = query.value(Qt::ImCurrentSelection); - if (!value.isValid()) - return false; - - selection = value.toString(); - return true; -} - -void QMaliitPlatformInputContext::setDetectableAutoRepeat(bool) -{ - // Not supported. -} - -void QMaliitPlatformInputContext::setGlobalCorrectionEnabled(bool enable) -{ - d->correctionEnabled = enable; -} - -void QMaliitPlatformInputContext::setLanguage(const QString &) -{ - // Unused at the moment. -} - -void QMaliitPlatformInputContext::setRedirectKeys(bool) -{ - // Not supported. -} - -void QMaliitPlatformInputContext::setSelection(int start, int length) -{ - if (!inputMethodAccepted()) - return; - - QList<QInputMethodEvent::Attribute> attributes; - attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, start, length, QVariant()); - QInputMethodEvent event(QString(), attributes); - QGuiApplication::sendEvent(qGuiApp->focusObject(), &event); -} - -void QMaliitPlatformInputContext::updateInputMethodArea(int x, int y, int width, int height) -{ - d->keyboardRect = QRect(x, y, width, height); - emitKeyboardRectChanged(); -} - -void QMaliitPlatformInputContext::updateServerWindowOrientation(Qt::ScreenOrientation orientation) -{ - d->server->appOrientationChanged(orientationAngle(orientation)); -} - -void QMaliitPlatformInputContext::setFocusObject(QObject *object) -{ - if (!d->valid) - return; - - QWindow *window = qGuiApp->focusWindow(); - if (window != d->window.data()) { - if (d->window) - disconnect(d->window.data(), SIGNAL(contentOrientationChanged(Qt::ScreenOrientation)), - this, SLOT(updateServerWindowOrientation(Qt::ScreenOrientation))); - d->window = window; - if (d->window) - connect(d->window.data(), SIGNAL(contentOrientationChanged(Qt::ScreenOrientation)), - this, SLOT(updateServerWindowOrientation(Qt::ScreenOrientation))); - } - - d->imState["focusState"] = (object != 0); - if (inputMethodAccepted()) { - if (window) - d->imState["winId"] = static_cast<qulonglong>(window->winId()); - - if (!d->active) { - d->active = true; - d->server->activateContext(); - - if (window) - d->server->appOrientationChanged(orientationAngle(window->contentOrientation())); - } - } - d->sendStateUpdate(/*focusChanged*/true); - if (inputMethodAccepted() && window && d->visibility == InputPanelShowRequested) - showInputPanel(); -} - -void QMaliitPlatformInputContext::showInputPanel() -{ - if (debug) - qDebug() << "showInputPanel"; - - if (!inputMethodAccepted()) - d->visibility = InputPanelShowRequested; - else { - d->server->showInputMethod(); - d->visibility = InputPanelShown; - emitInputPanelVisibleChanged(); - } -} - -void QMaliitPlatformInputContext::hideInputPanel() -{ - d->server->hideInputMethod(); - d->visibility = InputPanelHidden; - emitInputPanelVisibleChanged(); -} - -bool QMaliitPlatformInputContext::isInputPanelVisible() const -{ - return d->visibility == InputPanelShown; -} - -QMaliitPlatformInputContextPrivate::QMaliitPlatformInputContextPrivate(QMaliitPlatformInputContext* qq) - : connection(QDBusConnection::connectToPeer(maliitServerAddress(), QLatin1String("MaliitIMProxy"))) - , server(0) - , adaptor(0) - , visibility(InputPanelHidden) - , valid(false) - , active(false) - , correctionEnabled(false) - , q(qq) -{ - if (!connection.isConnected()) - return; - - server = new ComMeegoInputmethodUiserver1Interface(QStringLiteral(""), QStringLiteral("/com/meego/inputmethod/uiserver1"), connection); - adaptor = new Inputcontext1Adaptor(qq); - connection.registerObject("/com/meego/inputmethod/inputcontext", qq); - - enum InputMethodMode { - //! Normal mode allows to use preedit and error correction - InputMethodModeNormal, - - //! Virtual keyboard sends QKeyEvent for every key press or release - InputMethodModeDirect, - - //! Used with proxy widget - InputMethodModeProxy - }; - imState["inputMethodMode"] = InputMethodModeNormal; - - imState["correctionEnabled"] = true; - - valid = true; -} - -void QMaliitPlatformInputContextPrivate::sendStateUpdate(bool focusChanged) -{ - server->updateWidgetInformation(imState, focusChanged); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforminputcontexts/maliit/qmaliitplatforminputcontext.h b/src/plugins/platforminputcontexts/maliit/qmaliitplatforminputcontext.h deleted file mode 100644 index 1686983bd7..0000000000 --- a/src/plugins/platforminputcontexts/maliit/qmaliitplatforminputcontext.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, 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. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QMALIITPLATFORMINPUTCONTEXT_H -#define QMALIITPLATFORMINPUTCONTEXT_H - -#include <qpa/qplatforminputcontext.h> -#include <QDBusArgument> - -QT_BEGIN_NAMESPACE - -class QMaliitPlatformInputContextPrivate; -class QDBusVariant; -class QDBusMessage; - -class QMaliitPlatformInputContext : public QPlatformInputContext -{ - Q_OBJECT -public: - QMaliitPlatformInputContext(); - ~QMaliitPlatformInputContext(); - - bool isValid() const; - - void invokeAction(QInputMethod::Action action, int x); - void reset(void); - void update(Qt::InputMethodQueries); - virtual QRectF keyboardRect() const; - - virtual void showInputPanel(); - virtual void hideInputPanel(); - virtual bool isInputPanelVisible() const; - void setFocusObject(QObject *object); - -public Q_SLOTS: - void activationLostEvent(); - void commitString(const QString &in0, int in1, int in2, int in3); - void updatePreedit(const QDBusMessage &message); - void copy(); - void imInitiatedHide(); - void keyEvent(int type, int key, int modifiers, const QString &text, bool autoRepeat, int count, uchar requestType_); - void paste(); - bool preeditRectangle(int &x, int &y, int &width, int &height); - bool selection(QString &selection); - void setDetectableAutoRepeat(bool in0); - void setGlobalCorrectionEnabled(bool enable); - void setLanguage(const QString &); - void setRedirectKeys(bool ); - void setSelection(int start, int length); - void updateInputMethodArea(int x, int y, int width, int height); - void updateServerWindowOrientation(Qt::ScreenOrientation orientation); - -private: - QMaliitPlatformInputContextPrivate *d; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/plugins/platforminputcontexts/maliit/serveraddressproxy.h b/src/plugins/platforminputcontexts/maliit/serveraddressproxy.h deleted file mode 100644 index a9c31de4af..0000000000 --- a/src/plugins/platforminputcontexts/maliit/serveraddressproxy.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, 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. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef SERVERADDRESSPROXY_H -#define SERVERADDRESSPROXY_H - -#include <QtCore/QObject> -#include <QtCore/QByteArray> -#include <QtCore/QList> -#include <QtCore/QMap> -#include <QtCore/QString> -#include <QtCore/QStringList> -#include <QtCore/QVariant> -#include <QtDBus/QtDBus> - -/* - * Proxy class for interface org.maliit.Server.Address - */ -class OrgMaliitServerAddressInterface: public QDBusAbstractInterface -{ - Q_OBJECT -public: - static inline const char *staticInterfaceName() - { return "org.maliit.Server.Address"; } - -public: - OrgMaliitServerAddressInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); - - ~OrgMaliitServerAddressInterface(); - - Q_PROPERTY(QString address READ address) - inline QString address() const - { return qvariant_cast< QString >(property("address")); } - -public Q_SLOTS: // METHODS -Q_SIGNALS: // SIGNALS -}; - -namespace org { - namespace maliit { - namespace Server { - typedef ::OrgMaliitServerAddressInterface Address; - } - } -} -#endif diff --git a/src/plugins/platforminputcontexts/maliit/serverproxy.h b/src/plugins/platforminputcontexts/maliit/serverproxy.h deleted file mode 100644 index e32adfdd94..0000000000 --- a/src/plugins/platforminputcontexts/maliit/serverproxy.h +++ /dev/null @@ -1,166 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, 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. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef SERVER_H_1318935108 -#define SERVER_H_1318935108 - -#include <QtCore/QObject> -#include <QtCore/QByteArray> -#include <QtCore/QList> -#include <QtCore/QMap> -#include <QtCore/QString> -#include <QtCore/QStringList> -#include <QtCore/QVariant> -#include <QtDBus/QtDBus> - -/* - * Proxy class for interface com.meego.inputmethod.uiserver1 - */ -class ComMeegoInputmethodUiserver1Interface: public QDBusAbstractInterface -{ - Q_OBJECT -public: - static inline const char *staticInterfaceName() - { return "com.meego.inputmethod.uiserver1"; } - -public: - ComMeegoInputmethodUiserver1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); - - ~ComMeegoInputmethodUiserver1Interface(); - -public Q_SLOTS: // METHODS - inline QDBusPendingReply<> activateContext() - { - QList<QVariant> argumentList; - return asyncCallWithArgumentList(QLatin1String("activateContext"), argumentList); - } - - inline QDBusPendingReply<> appOrientationAboutToChange(int in0) - { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QLatin1String("appOrientationAboutToChange"), argumentList); - } - - inline QDBusPendingReply<> appOrientationChanged(int in0) - { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QLatin1String("appOrientationChanged"), argumentList); - } - - inline QDBusPendingReply<> hideInputMethod() - { - QList<QVariant> argumentList; - return asyncCallWithArgumentList(QLatin1String("hideInputMethod"), argumentList); - } - - inline QDBusPendingReply<> mouseClickedOnPreedit(int in0, int in1, int in2, int in3, int in4, int in5) - { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1) << QVariant::fromValue(in2) << QVariant::fromValue(in3) << QVariant::fromValue(in4) << QVariant::fromValue(in5); - return asyncCallWithArgumentList(QLatin1String("mouseClickedOnPreedit"), argumentList); - } - - inline QDBusPendingReply<> processKeyEvent(int in0, int in1, int in2, const QString &in3, bool in4, int in5, uint in6, uint in7, uint in8) - { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1) << QVariant::fromValue(in2) << QVariant::fromValue(in3) << QVariant::fromValue(in4) << QVariant::fromValue(in5) << QVariant::fromValue(in6) << QVariant::fromValue(in7) << QVariant::fromValue(in8); - return asyncCallWithArgumentList(QLatin1String("processKeyEvent"), argumentList); - } - - inline QDBusPendingReply<> setPreedit(const QString &in0, int in1) - { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); - return asyncCallWithArgumentList(QLatin1String("setPreedit"), argumentList); - } - - inline QDBusPendingReply<> showInputMethod() - { - QList<QVariant> argumentList; - return asyncCallWithArgumentList(QLatin1String("showInputMethod"), argumentList); - } - - inline QDBusPendingReply<> updateWidgetInformation(const QMap<QString, QVariant> &stateInformation, bool focusChanged) - { - QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), "updateWidgetInformation"); - - QDBusArgument map; - map.beginMap(QVariant::String, qMetaTypeId<QDBusVariant>()); - for (QMap<QString, QVariant>::ConstIterator it = stateInformation.constBegin(), end = stateInformation.constEnd(); - it != end; ++it) { - map.beginMapEntry(); - map << it.key(); - map << QDBusVariant(it.value()); - map.endMapEntry(); - } - map.endMap(); - - QList<QVariant> args; - args << QVariant::fromValue(map) << QVariant(focusChanged); - msg.setArguments(args); - return connection().asyncCall(msg); - } - - inline QDBusPendingReply<> reset() - { - return asyncCall(QLatin1String("reset")); - } - - inline QDBusPendingReply<> setCopyPasteState(bool in0, bool in1) - { - QList<QVariant> argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); - return asyncCallWithArgumentList(QLatin1String("setCopyPasteState"), argumentList); - } - -Q_SIGNALS: // SIGNALS -}; - -namespace com { - namespace meego { - namespace inputmethod { - typedef ::ComMeegoInputmethodUiserver1Interface uiserver1; - } - } -} -#endif diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro index 733b70be58..60b66bfb35 100644 --- a/src/plugins/platforminputcontexts/platforminputcontexts.pro +++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro @@ -1,7 +1,7 @@ TEMPLATE = subdirs qtHaveModule(dbus) { -!mac:!win32:SUBDIRS += ibus maliit +!mac:!win32:SUBDIRS += ibus } unix:!macx:!contains(DEFINES, QT_NO_XKBCOMMON): { diff --git a/src/plugins/platforms/android/src/androidjniaccessibility.cpp b/src/plugins/platforms/android/src/androidjniaccessibility.cpp new file mode 100644 index 0000000000..07f3371e72 --- /dev/null +++ b/src/plugins/platforms/android/src/androidjniaccessibility.cpp @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "androidjniaccessibility.h" +#include "androidjnimain.h" +#include "qandroidplatformintegration.h" +#include "qpa/qplatformaccessibility.h" +#include "qguiapplication.h" +#include "qwindow.h" +#include "qrect.h" +#include "private/qaccessible2_p.h" + +#include "qdebug.h" + +static const char m_qtTag[] = "QtA11y"; +static const char m_classErrorMsg[] = "Can't find class \"%s\""; +static const char m_methodErrorMsg[] = "Can't find method \"%s%s\""; + +namespace QtAndroidAccessibility +{ + static void setActive(JNIEnv */*env*/, jobject /*thiz*/, jboolean active) + { + QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration(); + if (platformIntegration) + platformIntegration->accessibility()->setActive(active); + else + __android_log_print(ANDROID_LOG_WARN, m_qtTag, "Could not activate platform accessibility."); + } + + QAccessibleInterface *interfaceFromId(jint objectId) + { + QAccessibleInterface *iface = 0; + if (objectId == -1) { + QWindow *win = qApp->focusWindow(); + if (win) + iface = win->accessibleRoot(); + } else { + iface = QAccessible::accessibleInterface(objectId); + } + return iface; + } + + static jintArray childIdListForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId) + { + QAccessibleInterface *iface = interfaceFromId(objectId); + if (iface) { + jintArray jArray = env->NewIntArray(jsize(iface->childCount())); + for (int i = 0; i < iface->childCount(); ++i) { + QAccessibleInterface *child = iface->child(i); + if (child) { + QAccessible::Id ifaceId = QAccessible::uniqueId(child); + jint jid = ifaceId; + env->SetIntArrayRegion(jArray, i, 1, &jid); + } + } + return jArray; + } + + return env->NewIntArray(jsize(0)); + } + + static jint parentId(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) + { + QAccessibleInterface *iface = interfaceFromId(objectId); + if (iface) { + QAccessibleInterface *parent = iface->parent(); + if (parent) { + if (parent->role() == QAccessible::Application) + return -1; + return QAccessible::uniqueId(parent); + } + } + return -1; + } + + static jobject screenRect(JNIEnv *env, jobject /*thiz*/, jint objectId) + { + QRect rect; + QAccessibleInterface *iface = interfaceFromId(objectId); + if (iface && iface->isValid()) { + rect = iface->rect(); + } + + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID ctor = env->GetMethodID(rectClass, "<init>", "(IIII)V"); + jobject jrect = env->NewObject(rectClass, ctor, rect.left(), rect.top(), rect.right(), rect.bottom()); + return jrect; + } + + static jint hitTest(JNIEnv */*env*/, jobject /*thiz*/, jfloat x, jfloat y) + { + QAccessibleInterface *root = interfaceFromId(-1); + if (root) { + QAccessibleInterface *child = root->childAt((int)x, (int)y); + QAccessibleInterface *lastChild = 0; + while (child && (child != lastChild)) { + lastChild = child; + child = child->childAt((int)x, (int)y); + } + if (lastChild) + return QAccessible::uniqueId(lastChild); + } + return -1; + } + + static jboolean clickAction(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) + { +// qDebug() << "A11Y: CLICK: " << objectId; + QAccessibleInterface *iface = interfaceFromId(objectId); + if (iface && iface->actionInterface()) { + if (iface->actionInterface()->actionNames().contains(QAccessibleActionInterface::pressAction())) + iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction()); + else + iface->actionInterface()->doAction(QAccessibleActionInterface::toggleAction()); + } + return false; + } + + +#define FIND_AND_CHECK_CLASS(CLASS_NAME) \ +clazz = env->FindClass(CLASS_NAME); \ +if (!clazz) { \ + __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_classErrorMsg, CLASS_NAME); \ + return JNI_FALSE; \ +} + + //__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); + +#define CALL_METHOD(OBJECT, METHOD_NAME, METHOD_SIGNATURE, VALUE) \ +{ \ + jclass clazz = env->GetObjectClass(OBJECT); \ + jmethodID method = env->GetMethodID(clazz, METHOD_NAME, METHOD_SIGNATURE); \ + if (!method) { \ + __android_log_print(ANDROID_LOG_WARN, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \ + return; \ + } \ + env->CallVoidMethod(OBJECT, method, VALUE); \ +} + + + static jstring descriptionForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId) + { + QString desc; + QAccessibleInterface *iface = interfaceFromId(objectId); + if (iface && iface->isValid()) { + desc = iface->text(QAccessible::Name); + if (desc.isEmpty()) + desc = iface->text(QAccessible::Description); + + desc += QChar(' ') + QString::fromUtf8(qAccessibleRoleString(iface->role())); + } + + jstring jdesc = env->NewString((jchar*) desc.constData(), (jsize) desc.size()); + return jdesc; + } + + static void populateNode(JNIEnv *env, jobject /*thiz*/, jint objectId, jobject node) + { + QAccessibleInterface *iface = interfaceFromId(objectId); + if (!iface || !iface->isValid()) { + __android_log_print(ANDROID_LOG_WARN, m_qtTag, "Accessibility: populateNode for Invalid ID"); + return; + } + QAccessible::State state = iface->state(); + + QString desc = iface->text(QAccessible::Name); + if (desc.isEmpty()) + desc = iface->text(QAccessible::Description); + if ((iface->role() != QAccessible::NoRole) && + (iface->role() != QAccessible::Client) && + (iface->role() != QAccessible::Pane)) { + desc += QChar(' ') + QString::fromUtf8(qAccessibleRoleString(iface->role())); + } + + CALL_METHOD(node, "setEnabled", "(Z)V", !state.disabled) + //CALL_METHOD(node, "setFocusable", "(Z)V", state.focusable) + CALL_METHOD(node, "setFocusable", "(Z)V", true) + //CALL_METHOD(node, "setFocused", "(Z)V", state.focused) + CALL_METHOD(node, "setCheckable", "(Z)V", state.checkable) + CALL_METHOD(node, "setChecked", "(Z)V", state.checked) + CALL_METHOD(node, "setVisibleToUser", "(Z)V", !state.invisible) + + if (iface->actionInterface()) { + QStringList actions = iface->actionInterface()->actionNames(); + bool clickable = actions.contains(QAccessibleActionInterface::pressAction()); + bool toggle = actions.contains(QAccessibleActionInterface::toggleAction()); + if (clickable || toggle) { + CALL_METHOD(node, "setClickable", "(Z)V", clickable) + CALL_METHOD(node, "addAction", "(I)V", 16) // ACTION_CLICK defined in AccessibilityNodeInfo + } + } + + jstring jdesc = env->NewString((jchar*) desc.constData(), (jsize) desc.size()); + //CALL_METHOD(node, "setText", "(Ljava/lang/CharSequence;)V", jdesc) + CALL_METHOD(node, "setContentDescription", "(Ljava/lang/CharSequence;)V", jdesc) + } + + static JNINativeMethod methods[] = { + {"setActive","(Z)V",(void*)setActive}, + {"childIdListForAccessibleObject", "(I)[I", (jintArray)childIdListForAccessibleObject}, + {"parentId", "(I)I", (void*)parentId}, + {"descriptionForAccessibleObject", "(I)Ljava/lang/String;", (jstring)descriptionForAccessibleObject}, + {"screenRect", "(I)Landroid/graphics/Rect;", (jobject)screenRect}, + {"hitTest", "(FF)I", (void*)hitTest}, + {"populateNode", "(ILandroid/view/accessibility/AccessibilityNodeInfo;)V", (void*)populateNode}, + {"clickAction", "(I)Z", (void*)clickAction}, + }; + + bool registerNatives(JNIEnv *env) + { + jclass clazz; + FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/accessibility/QtNativeAccessibility"); + jclass appClass = static_cast<jclass>(env->NewGlobalRef(clazz)); + + if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) { + __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed"); + return false; + } + + return true; + } +} diff --git a/src/plugins/platforms/kms/qkmsudevhandler.cpp b/src/plugins/platforms/android/src/androidjniaccessibility.h index e32723e78f..e708138c33 100644 --- a/src/plugins/platforms/kms/qkmsudevhandler.cpp +++ b/src/plugins/platforms/android/src/androidjniaccessibility.h @@ -39,17 +39,13 @@ ** ****************************************************************************/ -#include <qkmsudevhandler.h> +#ifndef ANDROIDJNIACCESSIBILITY_H +#define ANDROIDJNIACCESSIBILITY_H +#include <jni.h> -QT_BEGIN_NAMESPACE - -QKmsUdevHandler::QKmsUdevHandler(QObject *parent) - : QObject(parent) -{ -} - -QKmsUdevHandler::~QKmsUdevHandler() +namespace QtAndroidAccessibility { + bool registerNatives(JNIEnv *env); } -QT_END_NAMESPACE +#endif // ANDROIDJNIINPUT_H diff --git a/src/plugins/platforms/android/src/androidjniinput.cpp b/src/plugins/platforms/android/src/androidjniinput.cpp index 75cb617ca8..b31e74bb52 100644 --- a/src/plugins/platforms/android/src/androidjniinput.cpp +++ b/src/plugins/platforms/android/src/androidjniinput.cpp @@ -411,6 +411,24 @@ namespace QtAndroidInput case 0x00000018: return Qt::Key_VolumeUp; + case 0x000000b7: // KEYCODE_PROG_RED + return Qt::Key_Red; + + case 0x000000b8: // KEYCODE_PROG_GREEN + return Qt::Key_Green; + + case 0x000000b9: // KEYCODE_PROG_YELLOW + return Qt::Key_Yellow; + + case 0x000000ba: // KEYCODE_PROG_BLUE + return Qt::Key_Blue; + + case 0x000000a6: // KEYCODE_CHANNEL_UP + return Qt::Key_ChannelUp; + + case 0x000000a7: // KEYCODE_CHANNEL_DOWN + return Qt::Key_ChannelDown; + case 0x00000000: // KEYCODE_UNKNOWN case 0x00000011: // KEYCODE_STAR ?!?!? case 0x00000012: // KEYCODE_POUND ?!?!? diff --git a/src/plugins/platforms/android/src/androidjnimain.cpp b/src/plugins/platforms/android/src/androidjnimain.cpp index 74183b3107..b426839f3d 100644 --- a/src/plugins/platforms/android/src/androidjnimain.cpp +++ b/src/plugins/platforms/android/src/androidjnimain.cpp @@ -55,6 +55,7 @@ #include <stdlib.h> #include "androidjnimain.h" +#include "androidjniaccessibility.h" #include "androidjniinput.h" #include "androidjniclipboard.h" #include "androidjnimenu.h" @@ -88,6 +89,9 @@ static AAssetManager *m_assetManager = NULL; static jobject m_resourcesObj; static jobject m_activityObject = NULL; +static bool m_activityActive = true; // defaults to true because when the platform plugin is + // initialized, QtActivity::onResume() has already been called + static jclass m_bitmapClass = 0; static jmethodID m_createBitmapMethodID = 0; static jobject m_ARGB_8888_BitmapConfigValue = 0; @@ -319,6 +323,12 @@ namespace QtAndroid return m_activityObject; } + void setApplicationActive() + { + if (m_activityActive) + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); + } + jobject createBitmap(QImage img, JNIEnv *env) { if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_RGB16) @@ -655,6 +665,16 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/) #endif } +static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state) +{ + m_activityActive = (state == Qt::ApplicationActive); + + if (!m_androidPlatformIntegration) + return; + + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState(state)); +} + static void handleOrientationChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newOrientation) { if (m_androidPlatformIntegration == 0) @@ -681,6 +701,7 @@ static JNINativeMethod methods[] = { {"lockSurface", "()V", (void *)lockSurface}, {"unlockSurface", "()V", (void *)unlockSurface}, {"updateWindow", "()V", (void *)updateWindow}, + {"updateApplicationState", "(I)V", (void *)updateApplicationState}, {"handleOrientationChanged", "(I)V", (void *)handleOrientationChanged} }; @@ -797,7 +818,8 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/) if (!registerNatives(env) || !QtAndroidInput::registerNatives(env) || !QtAndroidClipboard::registerNatives(env) - || !QtAndroidMenu::registerNatives(env)) { + || !QtAndroidMenu::registerNatives(env) + || !QtAndroidAccessibility::registerNatives(env)) { __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed"); return -1; } diff --git a/src/plugins/platforms/android/src/androidjnimain.h b/src/plugins/platforms/android/src/androidjnimain.h index f75df55e02..9a3d8a9607 100644 --- a/src/plugins/platforms/android/src/androidjnimain.h +++ b/src/plugins/platforms/android/src/androidjnimain.h @@ -88,6 +88,8 @@ namespace QtAndroid jclass applicationClass(); jobject activity(); + void setApplicationActive(); + jobject createBitmap(QImage img, JNIEnv *env = 0); jobject createBitmapDrawable(jobject bitmap, JNIEnv *env = 0); diff --git a/src/plugins/platforms/android/src/androidplatformplugin.cpp b/src/plugins/platforms/android/src/androidplatformplugin.cpp index 71c5096e16..79e23c2d32 100644 --- a/src/plugins/platforms/android/src/androidplatformplugin.cpp +++ b/src/plugins/platforms/android/src/androidplatformplugin.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class QAndroidPlatformIntegrationPlugin: public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "android.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "android.json") public: QPlatformIntegration *create(const QString &key, const QStringList ¶mList); }; diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp index 2eac8d248c..4934047af9 100644 --- a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp +++ b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp @@ -135,6 +135,12 @@ void QAndroidOpenGLPlatformWindow::raise() void QAndroidOpenGLPlatformWindow::setVisible(bool visible) { QEglFSWindow::setVisible(visible); + + // The Android Activity is activated before Qt is initialized, causing the application state to + // never be set to 'active'. We explicitly set this state when the first window becomes visible. + if (visible) + QtAndroid::setApplicationActive(); + QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); // Expose event QWindowSystemInterface::flushWindowSystemEvents(); } diff --git a/src/plugins/platforminputcontexts/maliit/serveraddressproxy.cpp b/src/plugins/platforms/android/src/qandroidplatformaccessibility.cpp index 6ff508d66c..229368345b 100644 --- a/src/plugins/platforminputcontexts/maliit/serveraddressproxy.cpp +++ b/src/plugins/platforms/android/src/qandroidplatformaccessibility.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the plugins of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -39,18 +39,20 @@ ** ****************************************************************************/ -#include "serveraddressproxy.h" -/* - * Implementation of interface class OrgMaliitServerAddressInterface - */ +#include "qandroidplatformaccessibility.h" -OrgMaliitServerAddressInterface::OrgMaliitServerAddressInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) - : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) -{ -} +QT_BEGIN_NAMESPACE + +QAndroidPlatformAccessibility::QAndroidPlatformAccessibility() +{} + +QAndroidPlatformAccessibility::~QAndroidPlatformAccessibility() +{} -OrgMaliitServerAddressInterface::~OrgMaliitServerAddressInterface() +void QAndroidPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent */*event*/) { + // FIXME send events } +QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsudevdrmhandler.h b/src/plugins/platforms/android/src/qandroidplatformaccessibility.h index 4ceecb11a8..1b87f11919 100644 --- a/src/plugins/platforms/kms/qkmsudevdrmhandler.h +++ b/src/plugins/platforms/android/src/qandroidplatformaccessibility.h @@ -3,7 +3,7 @@ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the plugins of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -39,28 +39,23 @@ ** ****************************************************************************/ -#ifndef QKMSUDEVDRMHANDLER_H -#define QKMSUDEVDRMHANDLER_H -#include <QObject> +#ifndef QANDROIDPLATFORMACCESSIBILITY_H +#define QANDROIDPLATFORMACCESSIBILITY_H -#include <qkmsudevhandler.h> +#include <qpa/qplatformaccessibility.h> QT_BEGIN_NAMESPACE -class QKmsIntegration; - -class QKmsUdevDRMHandler : public QKmsUdevHandler +class QAndroidPlatformAccessibility: public QPlatformAccessibility { public: - QKmsUdevDRMHandler(QKmsIntegration *integration); - - QObject *create(struct udev_device *device); + QAndroidPlatformAccessibility(); + ~QAndroidPlatformAccessibility(); -private: - QKmsIntegration *m_integration; + virtual void notifyAccessibilityUpdate(QAccessibleEvent *event); }; QT_END_NAMESPACE -#endif // QKMSUDEVDRMHANDLER_H +#endif diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp index 636a2b3853..286d4cc7f2 100644 --- a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp @@ -50,6 +50,7 @@ #include "qandroidplatformservices.h" #include "qandroidplatformfontdatabase.h" #include "qandroidplatformclipboard.h" +#include "qandroidplatformaccessibility.h" #include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> #ifndef ANDROID_PLUGIN_OPENGL @@ -66,6 +67,7 @@ #endif #include "qandroidplatformtheme.h" +#include "qandroidsystemlocale.h" QT_BEGIN_NAMESPACE @@ -86,6 +88,9 @@ void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteA QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶mList) : m_touchDevice(0) +#ifndef QT_NO_ACCESSIBILITY + , m_accessibility(0) +#endif { Q_UNUSED(paramList); @@ -108,13 +113,17 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶ m_androidFDB = new QAndroidPlatformFontDatabase(); m_androidPlatformServices = new QAndroidPlatformServices(); m_androidPlatformClipboard = new QAndroidPlatformClipboard(); + + m_androidSystemLocale = new QAndroidSystemLocale; } bool QAndroidPlatformIntegration::hasCapability(Capability cap) const { switch (cap) { case ThreadedPixmaps: return true; + case ApplicationState: return true; case NonFullScreenWindows: return false; + case NativeWidgets: return false; default: #ifndef ANDROID_PLUGIN_OPENGL return QPlatformIntegration::hasCapability(cap); @@ -184,6 +193,7 @@ QAndroidPlatformIntegration::~QAndroidPlatformIntegration() { delete m_androidPlatformNativeInterface; delete m_androidFDB; + delete m_androidSystemLocale; QtAndroid::setAndroidPlatformIntegration(NULL); } QPlatformFontDatabase *QAndroidPlatformIntegration::fontDatabase() const @@ -255,6 +265,15 @@ void QAndroidPlatformIntegration::setDefaultDesktopSize(int gw, int gh) m_defaultGeometryHeight = gh; } +#ifndef QT_NO_ACCESSIBILITY +QPlatformAccessibility *QAndroidPlatformIntegration::accessibility() const +{ + if (!m_accessibility) + m_accessibility = new QAndroidPlatformAccessibility(); + return m_accessibility; +} +#endif + #ifndef ANDROID_PLUGIN_OPENGL void QAndroidPlatformIntegration::setDesktopSize(int width, int height) diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.h b/src/plugins/platforms/android/src/qandroidplatformintegration.h index 6cc191701d..83d7028665 100644 --- a/src/plugins/platforms/android/src/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/src/qandroidplatformintegration.h @@ -60,6 +60,8 @@ QT_BEGIN_NAMESPACE class QDesktopWidget; class QAndroidPlatformServices; +class QAndroidSystemLocale; +class QPlatformAccessibility; #ifdef ANDROID_PLUGIN_OPENGL class QAndroidOpenGLPlatformWindow; @@ -112,6 +114,10 @@ public: QPlatformNativeInterface *nativeInterface() const; QPlatformServices *services() const; +#ifndef QT_NO_ACCESSIBILITY + virtual QPlatformAccessibility *accessibility() const; +#endif + QVariant styleHint(StyleHint hint) const; QStringList themeNames() const; @@ -154,6 +160,10 @@ private: QAndroidPlatformNativeInterface *m_androidPlatformNativeInterface; QAndroidPlatformServices *m_androidPlatformServices; QPlatformClipboard *m_androidPlatformClipboard; + QAndroidSystemLocale *m_androidSystemLocale; +#ifndef QT_NO_ACCESSIBILITY + mutable QPlatformAccessibility *m_accessibility; +#endif mutable QAndroidInputContext m_platformInputContext; }; diff --git a/src/plugins/platforms/android/src/qandroidsystemlocale.cpp b/src/plugins/platforms/android/src/qandroidsystemlocale.cpp new file mode 100644 index 0000000000..24ae503335 --- /dev/null +++ b/src/plugins/platforms/android/src/qandroidsystemlocale.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qandroidsystemlocale.h" +#include "androidjnimain.h" +#include "private/qjniobject_p.h" +#include "private/qjnihelpers_p.h" +#include "qdatetime.h" +#include "qstringlist.h" +#include "qvariant.h" + +QT_BEGIN_NAMESPACE + +QAndroidSystemLocale::QAndroidSystemLocale() : m_locale(QLocale::C) +{ +} + +void QAndroidSystemLocale::getLocaleFromJava() const +{ + QWriteLocker locker(&m_lock); + + QJNILocalRef<jobject> javaLocaleRef; + QJNIObject javaActivity(QtAndroid::activity()); + if (javaActivity.isValid()) { + QJNIObject resources(javaActivity.callObjectMethod<jobject>("getResources", "()Landroid/content/res/Resources;").object()); + QJNIObject configuration(resources.callObjectMethod<jobject>("getConfiguration", "()Landroid/content/res/Configuration;").object()); + + javaLocaleRef = configuration.getObjectField<jobject>("locale", "Ljava/util/Locale;"); + } else { + javaLocaleRef = QJNIObject::callStaticObjectMethod<jobject>("java/util/Locale", "getDefault", "()Ljava/util/Locale;"); + } + + QJNIObject javaLocaleObject(javaLocaleRef.object()); + QString languageCode = qt_convertJString(javaLocaleObject.callObjectMethod<jstring>("getLanguage", "()Ljava/lang/String;").object()); + QString countryCode = qt_convertJString(javaLocaleObject.callObjectMethod<jstring>("getCountry", "()Ljava/lang/String;").object()); + + m_locale = QLocale(languageCode + QLatin1Char('_') + countryCode); +} + +QVariant QAndroidSystemLocale::query(QueryType type, QVariant in) const +{ + if (type == LocaleChanged) { + getLocaleFromJava(); + return QVariant(); + } + + QReadLocker locker(&m_lock); + + switch (type) { + case DecimalPoint: + return m_locale.decimalPoint(); + case GroupSeparator: + return m_locale.groupSeparator(); + case ZeroDigit: + return m_locale.zeroDigit(); + case NegativeSign: + return m_locale.negativeSign(); + case DateFormatLong: + return m_locale.dateFormat(QLocale::LongFormat); + case DateFormatShort: + return m_locale.dateFormat(QLocale::ShortFormat); + case TimeFormatLong: + return m_locale.timeFormat(QLocale::LongFormat); + case TimeFormatShort: + return m_locale.timeFormat(QLocale::ShortFormat); + case DayNameLong: + return m_locale.dayName(in.toInt(), QLocale::LongFormat); + case DayNameShort: + return m_locale.dayName(in.toInt(), QLocale::ShortFormat); + case MonthNameLong: + return m_locale.monthName(in.toInt(), QLocale::LongFormat); + case MonthNameShort: + return m_locale.monthName(in.toInt(), QLocale::ShortFormat); + case StandaloneMonthNameLong: + return m_locale.standaloneMonthName(in.toInt(), QLocale::LongFormat); + case StandaloneMonthNameShort: + return m_locale.standaloneMonthName(in.toInt(), QLocale::ShortFormat); + case DateToStringLong: + return m_locale.toString(in.toDate(), QLocale::LongFormat); + case DateToStringShort: + return m_locale.toString(in.toDate(), QLocale::ShortFormat); + case TimeToStringLong: + return m_locale.toString(in.toTime(), QLocale::LongFormat); + case TimeToStringShort: + return m_locale.toString(in.toTime(), QLocale::ShortFormat); + case DateTimeFormatLong: + return m_locale.dateTimeFormat(QLocale::LongFormat); + case DateTimeFormatShort: + return m_locale.dateTimeFormat(QLocale::ShortFormat); + case DateTimeToStringLong: + return m_locale.toString(in.toDateTime(), QLocale::LongFormat); + case DateTimeToStringShort: + return m_locale.toString(in.toDateTime(), QLocale::ShortFormat); + case PositiveSign: + return m_locale.positiveSign(); + case AMText: + return m_locale.amText(); + case PMText: + return m_locale.pmText(); + case FirstDayOfWeek: + return m_locale.firstDayOfWeek(); + case CurrencySymbol: + return m_locale .currencySymbol(QLocale::CurrencySymbolFormat(in.toUInt())); + case CurrencyToString: { + switch (in.type()) { + case QVariant::Int: + return m_locale .toCurrencyString(in.toInt()); + case QVariant::UInt: + return m_locale .toCurrencyString(in.toUInt()); + case QVariant::Double: + return m_locale .toCurrencyString(in.toDouble()); + case QVariant::LongLong: + return m_locale .toCurrencyString(in.toLongLong()); + case QVariant::ULongLong: + return m_locale .toCurrencyString(in.toULongLong()); + default: + break; + } + return QString(); + } + case StringToStandardQuotation: + return m_locale.quoteString(in.value<QStringRef>()); + case StringToAlternateQuotation: + return m_locale.quoteString(in.value<QStringRef>(), QLocale::AlternateQuotation); + case ListToSeparatedString: + return m_locale.createSeparatedList(in.value<QStringList>()); + case LocaleChanged: + Q_ASSERT_X(false, Q_FUNC_INFO, "This can't happen."); + default: + break; + } + return QVariant(); +} + +QLocale QAndroidSystemLocale::fallbackUiLocale() const +{ + QReadLocker locker(&m_lock); + return m_locale; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/src/qandroidsystemlocale.h b/src/plugins/platforms/android/src/qandroidsystemlocale.h new file mode 100644 index 0000000000..fc2f6fad98 --- /dev/null +++ b/src/plugins/platforms/android/src/qandroidsystemlocale.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QANDROIDSYSTEMLOCALE_H +#define QANDROIDSYSTEMLOCALE_H + +#include "private/qlocale_p.h" +#include <QtCore/qreadwritelock.h> + +QT_BEGIN_NAMESPACE + +class QAndroidSystemLocale : public QSystemLocale +{ +public: + QAndroidSystemLocale(); + + virtual QVariant query(QueryType type, QVariant in) const; + virtual QLocale fallbackUiLocale() const; + +private: + void getLocaleFromJava() const; + + mutable QLocale m_locale; + mutable QReadWriteLock m_lock; +}; + +QT_END_NAMESPACE + +#endif // QANDROIDSYSTEMLOCALE_H diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp index 94a69c10c7..f5fce0ae34 100644 --- a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp @@ -41,6 +41,9 @@ #include "qandroidplatformwindow.h" +#include "androidjnimain.h" +#include <qpa/qwindowsysteminterface.h> + QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) : QFbWindow(window) { } @@ -54,3 +57,13 @@ void QAndroidPlatformWindow::propagateSizeHints() { //shut up warning from default implementation } + +void QAndroidPlatformWindow::setVisible(bool visible) +{ + QFbWindow::setVisible(visible); + + // The Android Activity is activated before Qt is initialized, causing the application state to + // never be set to 'active'. We explicitly set this state when the first window becomes visible. + if (visible) + QtAndroid::setApplicationActive(); +} diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h index 3ee815fd69..58e6451ea1 100644 --- a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h @@ -52,6 +52,8 @@ public: void propagateSizeHints(); + void setVisible(bool visible); + public slots: void setGeometry(const QRect &rect); diff --git a/src/plugins/platforms/android/src/src.pri b/src/plugins/platforms/android/src/src.pri index 76539b50ab..6cc41c3e68 100644 --- a/src/plugins/platforms/android/src/src.pri +++ b/src/plugins/platforms/android/src/src.pri @@ -11,6 +11,7 @@ INCLUDEPATH += $$PWD/../../../../3rdparty/android/src SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/androidjnimain.cpp \ + $$PWD/androidjniaccessibility.cpp \ $$PWD/androidjniinput.cpp \ $$PWD/androidjnimenu.cpp \ $$PWD/androidjniclipboard.cpp \ @@ -18,28 +19,33 @@ SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/qandroidplatformservices.cpp \ $$PWD/qandroidassetsfileenginehandler.cpp \ $$PWD/qandroidinputcontext.cpp \ + $$PWD/qandroidplatformaccessibility.cpp \ $$PWD/qandroidplatformfontdatabase.cpp \ $$PWD/qandroidplatformclipboard.cpp \ $$PWD/qandroidplatformtheme.cpp \ $$PWD/qandroidplatformmenubar.cpp \ $$PWD/qandroidplatformmenu.cpp \ - $$PWD/qandroidplatformmenuitem.cpp + $$PWD/qandroidplatformmenuitem.cpp \ + $$PWD/qandroidsystemlocale.cpp HEADERS += $$PWD/qandroidplatformintegration.h \ $$PWD/androidjnimain.h \ + $$PWD/androidjniaccessibility.h \ $$PWD/androidjniinput.h \ $$PWD/androidjnimenu.h \ $$PWD/androidjniclipboard.h \ $$PWD/qandroidplatformservices.h \ $$PWD/qandroidassetsfileenginehandler.h \ $$PWD/qandroidinputcontext.h \ + $$PWD/qandroidplatformaccessibility.h \ $$PWD/qandroidplatformfontdatabase.h \ $$PWD/qandroidplatformclipboard.h \ $$PWD/qandroidplatformtheme.h \ $$PWD/qandroidplatformmenubar.h \ $$PWD/qandroidplatformmenu.h \ - $$PWD/qandroidplatformmenuitem.h + $$PWD/qandroidplatformmenuitem.h \ + $$PWD/qandroidsystemlocale.h #Non-standard install directory, QTBUG-29859 diff --git a/src/plugins/platforms/cocoa/main.mm b/src/plugins/platforms/cocoa/main.mm index 6adcb27817..b730514b12 100644 --- a/src/plugins/platforms/cocoa/main.mm +++ b/src/plugins/platforms/cocoa/main.mm @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QCocoaIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "cocoa.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "cocoa.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.h b/src/plugins/platforms/cocoa/qcocoaapplication.h index 2376b35501..ffb12ea846 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplication.h +++ b/src/plugins/platforms/cocoa/qcocoaapplication.h @@ -89,8 +89,10 @@ Cocoa Application Categories */ #include "qglobal.h" +#include "private/qcore_mac_p.h" #import <AppKit/AppKit.h> + @class QT_MANGLE_NAMESPACE(QCocoaMenuLoader); @interface NSApplication (QT_MANGLE_NAMESPACE(QApplicationIntegration)) @@ -106,6 +108,8 @@ } @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSApplication); + QT_BEGIN_NAMESPACE void qt_redirectNSApplicationSendEvent(); diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm index d962ef8f75..c293f4cd52 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplication.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm @@ -87,12 +87,12 @@ QT_USE_NAMESPACE - (void)QT_MANGLE_NAMESPACE(qt_setDockMenu):(NSMenu *)newMenu { - [[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] setDockMenu:newMenu]; + [[QCocoaApplicationDelegate sharedDelegate] setDockMenu:newMenu]; } - (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader) { - return [[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] menuLoader]; + return [[QCocoaApplicationDelegate sharedDelegate] menuLoader]; } - (int)QT_MANGLE_NAMESPACE(qt_validModesForFontPanel):(NSFontPanel *)fontPanel @@ -155,7 +155,7 @@ static const QByteArray q_macLocalEventType = QByteArrayLiteral("mac_generic_NSE @end -@implementation QT_MANGLE_NAMESPACE(QNSApplication) +@implementation QNSApplication - (void)qt_sendEvent_original:(NSEvent *)event { @@ -189,7 +189,7 @@ QT_BEGIN_NAMESPACE void qt_redirectNSApplicationSendEvent() { - if ([NSApp isMemberOfClass:[QT_MANGLE_NAMESPACE(QNSApplication) class]]) { + if ([NSApp isMemberOfClass:[QNSApplication class]]) { // No need to change implementation since Qt // already controls a subclass of NSApplication return; @@ -202,7 +202,7 @@ void qt_redirectNSApplicationSendEvent() qt_cocoa_change_implementation( [NSApplication class], @selector(sendEvent:), - [QT_MANGLE_NAMESPACE(QNSApplication) class], + [QNSApplication class], @selector(qt_sendEvent_replacement:), @selector(qt_sendEvent_original:)); } diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h index e44b2d1b6d..7f6c4224df 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h @@ -90,6 +90,7 @@ #import <Cocoa/Cocoa.h> #include <qglobal.h> +#include <private/qcore_mac_p.h> @class QT_MANGLE_NAMESPACE(QCocoaMenuLoader); @@ -108,3 +109,5 @@ - (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent; - (void) removeAppleEventHandlers; @end + +QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaApplicationDelegate); diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 3ec6ad7a20..423d552627 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -88,14 +88,14 @@ QT_USE_NAMESPACE -static QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *sharedCocoaApplicationDelegate = nil; +static QCocoaApplicationDelegate *sharedCocoaApplicationDelegate = nil; static void cleanupCocoaApplicationDelegate() { [sharedCocoaApplicationDelegate release]; } -@implementation QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) +@implementation QCocoaApplicationDelegate - (id)init { @@ -144,7 +144,7 @@ static void cleanupCocoaApplicationDelegate() return nil; } -+ (QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)*)sharedDelegate ++ (QCocoaApplicationDelegate *)sharedDelegate { @synchronized(self) { if (sharedCocoaApplicationDelegate == nil) @@ -166,14 +166,14 @@ static void cleanupCocoaApplicationDelegate() return [[dockMenu retain] autorelease]; } -- (void)setMenuLoader:(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader +- (void)setMenuLoader:(QCocoaMenuLoader *)menuLoader { [menuLoader retain]; [qtMenuLoader release]; qtMenuLoader = menuLoader; } -- (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader +- (QCocoaMenuLoader *)menuLoader { return [[qtMenuLoader retain] autorelease]; } @@ -183,7 +183,7 @@ static void cleanupCocoaApplicationDelegate() [[NSApp mainMenu] cancelTracking]; bool handle_quit = true; - NSMenuItem *quitMenuItem = [[[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] menuLoader] quitMenuItem]; + NSMenuItem *quitMenuItem = [[[QCocoaApplicationDelegate sharedDelegate] menuLoader] quitMenuItem]; if (!QGuiApplicationPrivate::instance()->modalWindowList.isEmpty() && [quitMenuItem isEnabled]) { int visible = 0; diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm index 3379a26650..d90d77ec1d 100644 --- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm @@ -87,7 +87,9 @@ static NSButton *macCreateButton(const char *text, NSView *superview) - (void)finishOffWithCode:(NSInteger)code; @end -@implementation QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); + +@implementation QNSColorPanelDelegate - (id)init { @@ -308,12 +310,13 @@ static NSButton *macCreateButton(const char *text, NSView *superview) // close down during the cleanup. qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers); [NSApp runModalForWindow:mColorPanel]; + mDialogIsExecuting = false; return (mResultCode == NSOKButton); } -- (QT_PREPEND_NAMESPACE(QPlatformDialogHelper::DialogCode))dialogResultCode +- (QPlatformDialogHelper::DialogCode)dialogResultCode { - return (mResultCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Accepted) : QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Rejected); + return (mResultCode == NSOKButton) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected; } - (BOOL)windowShouldClose:(id)window diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h index 701e8e2dbf..8a8b1d946c 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h @@ -62,10 +62,10 @@ public: bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent); void hide(); - void setDirectory(const QString &directory); - QString directory() const; - void selectFile(const QString &filename); - QStringList selectedFiles() const; + void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + QUrl directory() const Q_DECL_OVERRIDE; + void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; + QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; void setFilter(); void selectNameFilter(const QString &filter); QString selectedNameFilter() const; diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 76cd235514..b3bc4a8ebf 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -139,7 +139,9 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions; @end -@implementation QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate); + +@implementation QNSOpenSavePanelDelegate - (id)initWithAcceptMode: (const QString &)selectFile @@ -148,7 +150,7 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions; { self = [super init]; mOptions = options; - if (mOptions->acceptMode() == QT_PREPEND_NAMESPACE(QFileDialogOptions::AcceptOpen)){ + if (mOptions->acceptMode() == QFileDialogOptions::AcceptOpen){ mOpenPanel = [NSOpenPanel openPanel]; mSavePanel = mOpenPanel; } else { @@ -234,7 +236,7 @@ static QString strippedText(QString s) - (void)closePanel { - *mCurrentSelection = QT_PREPEND_NAMESPACE(QCFString::toQString)([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C); + *mCurrentSelection = QCFString::toQString([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C); if ([mSavePanel respondsToSelector:@selector(close)]) [mSavePanel close]; if ([mSavePanel isSheet]) @@ -245,7 +247,7 @@ static QString strippedText(QString s) { if (mOpenPanel){ QFileInfo info(*mCurrentSelection); - NSString *filepath = QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.filePath()); + NSString *filepath = QCFString::toNSString(info.filePath()); bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) || [self panel:nil shouldShowFilename:filepath]; @@ -264,12 +266,12 @@ static QString strippedText(QString s) - (BOOL)runApplicationModalPanel { QFileInfo info(*mCurrentSelection); - NSString *filepath = QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.filePath()); + NSString *filepath = QCFString::toNSString(info.filePath()); bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) || [self panel:nil shouldShowFilename:filepath]; [mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]]; - [mSavePanel setNameFieldStringValue:selectable ? QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.fileName()) : @""]; + [mSavePanel setNameFieldStringValue:selectable ? QCFString::toNSString(info.fileName()) : @""]; // Call processEvents in case the event dispatcher has been interrupted, and needs to do // cleanup of modal sessions. Do this before showing the native dialog, otherwise it will @@ -281,22 +283,22 @@ static QString strippedText(QString s) return (mReturnCode == NSOKButton); } -- (QT_PREPEND_NAMESPACE(QPlatformDialogHelper::DialogCode))dialogResultCode +- (QPlatformDialogHelper::DialogCode)dialogResultCode { - return (mReturnCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Accepted) : QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Rejected); + return (mReturnCode == NSOKButton) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected; } - (void)showWindowModalSheet:(QWindow *)parent { QFileInfo info(*mCurrentSelection); - NSString *filepath = QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.filePath()); + NSString *filepath = QCFString::toNSString(info.filePath()); bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) || [self panel:nil shouldShowFilename:filepath]; [self updateProperties]; [mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]]; - [mSavePanel setNameFieldStringValue:selectable ? QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.fileName()) : @""]; + [mSavePanel setNameFieldStringValue:selectable ? QCFString::toNSString(info.fileName()) : @""]; NSWindow *nsparent = static_cast<NSWindow *>(qGuiApp->platformNativeInterface()->nativeResourceForWindow("nswindow", parent)); [mSavePanel beginSheetModalForWindow:nsparent completionHandler:^(NSInteger result){ @@ -322,8 +324,8 @@ static QString strippedText(QString s) } } - QString qtFileName = QT_PREPEND_NAMESPACE(QCFString::toQString)(filename); - QFileInfo info(qtFileName.normalized(QT_PREPEND_NAMESPACE(QString::NormalizationForm_C))); + QString qtFileName = QCFString::toQString(filename); + QFileInfo info(qtFileName.normalized(QString::NormalizationForm_C)); QString path = info.absolutePath(); if (mCachedEntries->directory() != path) { mCachedEntries->updateDirCache(path); @@ -363,7 +365,7 @@ static QString strippedText(QString s) if (filters.size() > 0){ for (int i=0; i<filters.size(); ++i) { QString filter = hideDetails ? [self removeExtensions:filters.at(i)] : filters.at(i); - [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(QCFString::toNSString)(filter)]; + [mPopUpButton addItemWithTitle:QCFString::toNSString(filter)]; } [mPopUpButton selectItemAtIndex:0]; [mSavePanel setAccessoryView:mAccessoryView]; @@ -391,18 +393,20 @@ static QString strippedText(QString s) return mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]); } -- (QStringList)selectedFiles +- (QList<QUrl>)selectedFiles { if (mOpenPanel) { - QStringList result; + QList<QUrl> result; NSArray* array = [mOpenPanel URLs]; - for (NSUInteger i=0; i<[array count]; ++i) - result << QCFString::toQString([[array objectAtIndex:i] path]).normalized(QString::NormalizationForm_C); + for (NSUInteger i=0; i<[array count]; ++i) { + QString path = QCFString::toQString([[array objectAtIndex:i] path]).normalized(QString::NormalizationForm_C); + result << QUrl::fromLocalFile(path); + } return result; } else { - QStringList result; - QString filename = QT_PREPEND_NAMESPACE(QCFString::toQString)([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C); - result << filename.remove(QLatin1String("___qt_very_unlikely_prefix_")); + QList<QUrl> result; + QString filename = QCFString::toQString([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C); + result << QUrl::fromLocalFile(filename.remove(QLatin1String("___qt_very_unlikely_prefix_"))); return result; } } @@ -412,18 +416,18 @@ static QString strippedText(QString s) // Call this functions if mFileMode, mFileOptions, // mNameFilterDropDownList or mQDirFilter changes. // The savepanel does not contain the neccessary functions for this. - const QT_PREPEND_NAMESPACE(QFileDialogOptions::FileMode) fileMode = mOptions->fileMode(); - bool chooseFilesOnly = fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::ExistingFile) - || fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::ExistingFiles); - bool chooseDirsOnly = fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::Directory) - || fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::DirectoryOnly) - || mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::ShowDirsOnly)); + const QFileDialogOptions::FileMode fileMode = mOptions->fileMode(); + bool chooseFilesOnly = fileMode == QFileDialogOptions::ExistingFile + || fileMode == QFileDialogOptions::ExistingFiles; + bool chooseDirsOnly = fileMode == QFileDialogOptions::Directory + || fileMode == QFileDialogOptions::DirectoryOnly + || mOptions->testOption(QFileDialogOptions::ShowDirsOnly); [mOpenPanel setCanChooseFiles:!chooseDirsOnly]; [mOpenPanel setCanChooseDirectories:!chooseFilesOnly]; - [mSavePanel setCanCreateDirectories:!(mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::ReadOnly)))]; - [mOpenPanel setAllowsMultipleSelection:(fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::ExistingFiles))]; - [mOpenPanel setResolvesAliases:!(mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::DontResolveSymlinks)))]; + [mSavePanel setCanCreateDirectories:!(mOptions->testOption(QFileDialogOptions::ReadOnly))]; + [mOpenPanel setAllowsMultipleSelection:(fileMode == QFileDialogOptions::ExistingFiles)]; + [mOpenPanel setResolvesAliases:!(mOptions->testOption(QFileDialogOptions::DontResolveSymlinks))]; [mOpenPanel setTitle:QCFString::toNSString(mOptions->windowTitle())]; [mSavePanel setTitle:QCFString::toNSString(mOptions->windowTitle())]; [mPopUpButton setHidden:chooseDirsOnly]; // TODO hide the whole sunken pane instead? @@ -432,7 +436,7 @@ static QString strippedText(QString s) const QString defaultSuffix = mOptions->defaultSuffix(); if (!ext.isEmpty() && !defaultSuffix.isEmpty()) ext.prepend(defaultSuffix); - [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : QT_PREPEND_NAMESPACE(qt_mac_QStringListToNSMutableArray(ext))]; + [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : qt_mac_QStringListToNSMutableArray(ext)]; if ([mSavePanel respondsToSelector:@selector(isVisible)] && [mSavePanel isVisible]) { if ([mSavePanel respondsToSelector:@selector(validateVisibleColumns)]) @@ -444,7 +448,7 @@ static QString strippedText(QString s) { Q_UNUSED(sender); if (mHelper) { - QString selection = QT_PREPEND_NAMESPACE(QCFString::toQString([[mSavePanel URL] path])); + QString selection = QCFString::toQString([[mSavePanel URL] path]); if (selection != mCurrentSelection) { *mCurrentSelection = selection; mHelper->QNSOpenSavePanelDelegate_selectionChanged(selection); @@ -462,7 +466,7 @@ static QString strippedText(QString s) [mCurrentDir release]; mCurrentDir = [path retain]; - mHelper->QNSOpenSavePanelDelegate_directoryEntered(QT_PREPEND_NAMESPACE(QCFString::toQString(mCurrentDir))); + mHelper->QNSOpenSavePanelDelegate_directoryEntered(QCFString::toQString(mCurrentDir)); } /* @@ -489,7 +493,7 @@ static QString strippedText(QString s) - (QString)removeExtensions:(const QString &)filter { - QRegExp regExp(QT_PREPEND_NAMESPACE(QString::fromLatin1)(QT_PREPEND_NAMESPACE(QPlatformFileDialogHelper::filterRegExp))); + QRegExp regExp(QString::fromLatin1(QPlatformFileDialogHelper::filterRegExp)); if (regExp.indexIn(filter) != -1) return regExp.cap(1).trimmed(); return filter; @@ -525,7 +529,7 @@ static QString strippedText(QString s) (filterToUse == -1 && currentFilter.startsWith(selectedFilter))) filterToUse = i; QString filter = hideDetails ? [self removeExtensions:currentFilter] : currentFilter; - [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(QCFString::toNSString)(filter)]; + [mPopUpButton addItemWithTitle:QCFString::toNSString(filter)]; } if (filterToUse != -1) [mPopUpButton selectItemAtIndex:filterToUse]; @@ -563,13 +567,13 @@ QCocoaFileDialogHelper::~QCocoaFileDialogHelper() if (!mDelegate) return; QCocoaAutoReleasePool pool; - [reinterpret_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate) release]; + [reinterpret_cast<QNSOpenSavePanelDelegate *>(mDelegate) release]; mDelegate = 0; } void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath) { - emit currentChanged(newPath); + emit currentChanged(QUrl::fromLocalFile(newPath)); } void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_panelClosed(bool accepted) @@ -584,7 +588,7 @@ void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_panelClosed(bool accepted) void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir) { // ### fixme: priv->setLastVisitedDirectory(newDir); - emit directoryEntered(newDir); + emit directoryEntered(QUrl::fromLocalFile(newDir)); } void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_filterSelected(int menuIndex) @@ -596,43 +600,45 @@ void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_filterSelected(int menuInd extern OSErr qt_mac_create_fsref(const QString &, FSRef *); // qglobal.cpp extern void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding=0, int len=-1); // qglobal.cpp -void QCocoaFileDialogHelper::setDirectory(const QString &directory) +void QCocoaFileDialogHelper::setDirectory(const QUrl &directory) { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if (delegate) - [delegate->mSavePanel setDirectoryURL:[NSURL fileURLWithPath:QCFString::toNSString(directory)]]; + [delegate->mSavePanel setDirectoryURL:[NSURL fileURLWithPath:QCFString::toNSString(directory.toLocalFile())]]; } -QString QCocoaFileDialogHelper::directory() const +QUrl QCocoaFileDialogHelper::directory() const { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); - if (delegate) - return QCFString::toQString([[delegate->mSavePanel directoryURL] path]).normalized(QString::NormalizationForm_C); - return QString(); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); + if (delegate) { + QString path = QCFString::toQString([[delegate->mSavePanel directoryURL] path]).normalized(QString::NormalizationForm_C); + return QUrl::fromLocalFile(path); + } + return QUrl(); } -void QCocoaFileDialogHelper::selectFile(const QString &filename) +void QCocoaFileDialogHelper::selectFile(const QUrl &filename) { - QString filePath = filename; + QString filePath = filename.toLocalFile(); if (QDir::isRelativePath(filePath)) - filePath = QFileInfo(directory(), filePath).filePath(); + filePath = QFileInfo(directory().toLocalFile(), filePath).filePath(); // There seems to no way to select a file once the dialog is running. // So do the next best thing, set the file's directory: setDirectory(QFileInfo(filePath).absolutePath()); } -QStringList QCocoaFileDialogHelper::selectedFiles() const +QList<QUrl> QCocoaFileDialogHelper::selectedFiles() const { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if (delegate) return [delegate selectedFiles]; - return QStringList(); + return QList<QUrl>(); } void QCocoaFileDialogHelper::setFilter() { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if (!delegate) return; const SharedPointerFileDialogOptions &opts = options(); @@ -651,7 +657,7 @@ void QCocoaFileDialogHelper::selectNameFilter(const QString &filter) return; const int index = options()->nameFilters().indexOf(filter); if (index != -1) { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if (!delegate) return; [delegate->mPopUpButton selectItemAtIndex:index]; @@ -661,7 +667,7 @@ void QCocoaFileDialogHelper::selectNameFilter(const QString &filter) QString QCocoaFileDialogHelper::selectedNameFilter() const { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if (!delegate) return QString(); int index = [delegate->mPopUpButton indexOfSelectedItem]; @@ -695,11 +701,11 @@ void QCocoaFileDialogHelper::createNSOpenSavePanelDelegate() return; QCocoaAutoReleasePool pool; const SharedPointerFileDialogOptions &opts = options(); - const QStringList selectedFiles = opts->initiallySelectedFiles(); - const QString directory = opts->initialDirectory(); + const QList<QUrl> selectedFiles = opts->initiallySelectedFiles(); + const QUrl directory = opts->initialDirectory(); const bool selectDir = selectedFiles.isEmpty(); - QString selection(selectDir ? directory : selectedFiles.front()); - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) alloc] + QString selection(selectDir ? directory.toLocalFile() : selectedFiles.front().toLocalFile()); + QNSOpenSavePanelDelegate *delegate = [[QNSOpenSavePanelDelegate alloc] initWithAcceptMode: selection options:opts @@ -711,7 +717,7 @@ void QCocoaFileDialogHelper::createNSOpenSavePanelDelegate() bool QCocoaFileDialogHelper::showCocoaFilePanel(Qt::WindowModality windowModality, QWindow *parent) { createNSOpenSavePanelDelegate(); - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if (!delegate) return false; if (windowModality == Qt::NonModal) @@ -729,7 +735,7 @@ bool QCocoaFileDialogHelper::hideCocoaFilePanel() // open regarding whether or not to go native: return false; } else { - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); [delegate closePanel]; // Even when we hide it, we are still using a // native dialog, so return true: @@ -744,7 +750,7 @@ void QCocoaFileDialogHelper::exec() // yet been reactivated (regardless if [NSApp run] is still on the stack)), // showing a native modal dialog will fail. QCocoaAutoReleasePool pool; - QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); + QNSOpenSavePanelDelegate *delegate = static_cast<QNSOpenSavePanelDelegate *>(mDelegate); if ([delegate runApplicationModalPanel]) emit accept(); else diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h index c1fef68f42..83aebba6d3 100644 --- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h +++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h @@ -47,9 +47,6 @@ QT_BEGIN_NAMESPACE -class QFontDialog; -class QFontDialogPrivate; - class QCocoaFontDialogHelper : public QPlatformFontDialogHelper { public: @@ -63,14 +60,6 @@ public: void setCurrentFont(const QFont &); QFont currentFont() const; - -protected: - void createNSFontPanelDelegate(); - bool showCocoaFontPanel(Qt::WindowModality windowModality, QWindow *parent); - bool hideCocoaFontPanel(); - -private: - void *mDelegate; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm index a70ba3749f..91fb52eb6d 100644 --- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm @@ -128,14 +128,18 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) - (void)finishOffWithCode:(NSInteger)code; @end -@implementation QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); -- (id)initWithDialogHelper: - (QCocoaFontDialogHelper *)helper +@implementation QNSFontPanelDelegate + +- (id)init { self = [super init]; mFontPanel = [NSFontPanel sharedFontPanel]; - mHelper = helper; + mHelper = 0; + mStolenContentView = 0; + mOkButton = 0; + mCancelButton = 0; mResultCode = NSCancelButton; mDialogIsExecuting = false; mResultSet = false; @@ -145,13 +149,32 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) [mFontPanel setRestorable:NO]; #endif + [mFontPanel setDelegate:self]; + [[NSFontManager sharedFontManager] setDelegate:self]; + + [mFontPanel retain]; + return self; +} + +- (void)dealloc +{ + [self restoreOriginalContentView]; + [mFontPanel setDelegate:nil]; + [[NSFontManager sharedFontManager] setDelegate:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [super dealloc]; +} + +- (void)setDialogHelper:(QCocoaFontDialogHelper *)helper +{ + mHelper = helper; + [mFontPanel setTitle:QCFString::toNSString(helper->options()->windowTitle())]; if (mHelper->options()->testOption(QFontDialogOptions::NoButtons)) { - mStolenContentView = 0; - mOkButton = 0; - mCancelButton = 0; - } else { + [self restoreOriginalContentView]; + } else if (!mStolenContentView) { // steal the font panel's contents view mStolenContentView = [mFontPanel contentView]; [mStolenContentView retain]; @@ -176,14 +199,22 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) [mCancelButton setAction:@selector(onCancelClicked)]; [mCancelButton setTarget:self]; } +} - [mFontPanel retain]; - return self; +- (void)closePanel +{ + [mFontPanel close]; } -- (void)dealloc +- (void)windowDidResize:(NSNotification *)notification { - if (mOkButton) { + Q_UNUSED(notification); + [self relayout]; +} + +- (void)restoreOriginalContentView +{ + if (mStolenContentView) { NSView *ourContentView = [mFontPanel contentView]; // return stolen stuff to its rightful owner @@ -192,28 +223,17 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) [mOkButton release]; [mCancelButton release]; [ourContentView release]; + mOkButton = 0; + mCancelButton = 0; + mStolenContentView = 0; } - - [mFontPanel setDelegate:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - [super dealloc]; -} - -- (void)closePanel -{ - [mFontPanel close]; -} - -- (void)windowDidResize:(NSNotification *)notification -{ - Q_UNUSED(notification); - if (mOkButton) - [self relayout]; } - (void)relayout { + if (!mOkButton) + return; + [self relayoutToContentSize:[[mStolenContentView superview] frame].size]; } @@ -289,30 +309,32 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) NSFont *panelFont = [fontManager convertFont:selectedFont]; mQtFont = qfontForCocoaFont(panelFont, mQtFont); - emit mHelper->currentFontChanged(mQtFont); + if (mHelper) + emit mHelper->currentFontChanged(mQtFont); } - (void)showModelessPanel { mDialogIsExecuting = false; + mResultSet = false; [mFontPanel makeKeyAndOrderFront:mFontPanel]; } - (BOOL)runApplicationModalPanel { mDialogIsExecuting = true; - [mFontPanel setDelegate:self]; // Call processEvents in case the event dispatcher has been interrupted, and needs to do // cleanup of modal sessions. Do this before showing the native dialog, otherwise it will // close down during the cleanup. qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers); [NSApp runModalForWindow:mFontPanel]; + mDialogIsExecuting = false; return (mResultCode == NSOKButton); } -- (QT_PREPEND_NAMESPACE(QPlatformDialogHelper::DialogCode))dialogResultCode +- (QPlatformDialogHelper::DialogCode)dialogResultCode { - return (mResultCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Accepted) : QT_PREPEND_NAMESPACE(QPlatformDialogHelper::Rejected); + return (mResultCode == NSOKButton) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected; } - (BOOL)windowShouldClose:(id)window @@ -324,7 +346,8 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) [self finishOffWithCode:NSCancelButton]; } else { mResultSet = true; - emit mHelper->reject(); + if (mHelper) + emit mHelper->reject(); } return true; } @@ -359,27 +382,101 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) QT_BEGIN_NAMESPACE -QCocoaFontDialogHelper::QCocoaFontDialogHelper() : - mDelegate(0) +class QCocoaFontPanel +{ +public: + QCocoaFontPanel() + { + mDelegate = [[QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) alloc] init]; + } + + ~QCocoaFontPanel() + { + [mDelegate release]; + } + + void init(QCocoaFontDialogHelper *helper) + { + [mDelegate setDialogHelper:helper]; + } + + void cleanup(QCocoaFontDialogHelper *helper) + { + if (mDelegate->mHelper == helper) + mDelegate->mHelper = 0; + } + + bool exec() + { + // Note: If NSApp is not running (which is the case if e.g a top-most + // QEventLoop has been interrupted, and the second-most event loop has not + // yet been reactivated (regardless if [NSApp run] is still on the stack)), + // showing a native modal dialog will fail. + return [mDelegate runApplicationModalPanel]; + } + + bool show(Qt::WindowModality windowModality, QWindow *parent) + { + Q_UNUSED(parent); + if (windowModality != Qt::WindowModal) + [mDelegate showModelessPanel]; + // no need to show a Qt::WindowModal dialog here, because it's necessary to call exec() in that case + return true; + } + + void hide() + { + [mDelegate closePanel]; + } + + QFont currentFont() const + { + return mDelegate->mQtFont; + } + + void setCurrentFont(const QFont &font) + { + NSFontManager *mgr = [NSFontManager sharedFontManager]; + const NSFont *nsFont = 0; + + int weight = 5; + NSFontTraitMask mask = 0; + if (font.style() == QFont::StyleItalic) { + mask |= NSItalicFontMask; + } + if (font.weight() == QFont::Bold) { + weight = 9; + mask |= NSBoldFontMask; + } + + QFontInfo fontInfo(font); + nsFont = [mgr fontWithFamily:QCFString::toNSString(fontInfo.family()) + traits:mask + weight:weight + size:fontInfo.pointSize()]; + + [mgr setSelectedFont:const_cast<NSFont *>(nsFont) isMultiple:NO]; + mDelegate->mQtFont = font; + } + +private: + QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *mDelegate; +}; + +Q_GLOBAL_STATIC(QCocoaFontPanel, sharedFontPanel) + +QCocoaFontDialogHelper::QCocoaFontDialogHelper() { } QCocoaFontDialogHelper::~QCocoaFontDialogHelper() { - if (!mDelegate) - return; - [reinterpret_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate) release]; - mDelegate = 0; + sharedFontPanel()->cleanup(this); } void QCocoaFontDialogHelper::exec() { - // Note: If NSApp is not running (which is the case if e.g a top-most - // QEventLoop has been interrupted, and the second-most event loop has not - // yet been reactivated (regardless if [NSApp run] is still on the stack)), - // showing a native modal dialog will fail. - QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate); - if ([delegate runApplicationModalPanel]) + if (sharedFontPanel()->exec()) emit accept(); else emit reject(); @@ -387,86 +484,26 @@ void QCocoaFontDialogHelper::exec() bool QCocoaFontDialogHelper::show(Qt::WindowFlags, Qt::WindowModality windowModality, QWindow *parent) { - if (windowModality == Qt::WindowModal) { - // Cocoa's shared font panel cannot be shown as a sheet - return false; - } - return showCocoaFontPanel(windowModality, parent); + if (windowModality == Qt::WindowModal) + windowModality = Qt::ApplicationModal; + sharedFontPanel()->init(this); + return sharedFontPanel()->show(windowModality, parent); } void QCocoaFontDialogHelper::hide() { - if (!mDelegate) - return; - [reinterpret_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate)->mFontPanel close]; + sharedFontPanel()->hide(); } void QCocoaFontDialogHelper::setCurrentFont(const QFont &font) { - NSFontManager *mgr = [NSFontManager sharedFontManager]; - const NSFont *nsFont = 0; - - int weight = 5; - NSFontTraitMask mask = 0; - if (font.style() == QFont::StyleItalic) { - mask |= NSItalicFontMask; - } - if (font.weight() == QFont::Bold) { - weight = 9; - mask |= NSBoldFontMask; - } - - QFontInfo fontInfo(font); - nsFont = [mgr fontWithFamily:QCFString::toNSString(fontInfo.family()) - traits:mask - weight:weight - size:fontInfo.pointSize()]; - - if (!mDelegate) - createNSFontPanelDelegate(); - - [mgr setSelectedFont:const_cast<NSFont *>(nsFont) isMultiple:NO]; - static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate)->mQtFont = font; + sharedFontPanel()->init(this); + sharedFontPanel()->setCurrentFont(font); } QFont QCocoaFontDialogHelper::currentFont() const { - if (!mDelegate) - return QFont(); - return reinterpret_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate)->mQtFont; -} - -void QCocoaFontDialogHelper::createNSFontPanelDelegate() -{ - if (mDelegate) - return; - - QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) alloc] - initWithDialogHelper:this]; - - mDelegate = delegate; -} - -bool QCocoaFontDialogHelper::showCocoaFontPanel(Qt::WindowModality windowModality, QWindow *parent) -{ - Q_UNUSED(parent); - createNSFontPanelDelegate(); - QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate); - if (windowModality == Qt::NonModal) - [delegate showModelessPanel]; - // no need to show a Qt::ApplicationModal dialog here, since it will be done in _q_platformRunNativeAppModalPanel() - return true; -} - -bool QCocoaFontDialogHelper::hideCocoaFontPanel() -{ - if (!mDelegate){ - return false; - } else { - QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) *>(mDelegate); - [delegate closePanel]; - return true; - } + return sharedFontPanel()->currentFont(); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 3ade0a2a45..901efbfb39 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -53,6 +53,8 @@ #include <QtWidgets/QWidget> #endif +#include <algorithm> + QT_BEGIN_NAMESPACE // @@ -320,7 +322,7 @@ QChar qt_mac_qtKey2CocoaKey(Qt::Key key) mustInit = false; for (int i=0; i<NumEntries; ++i) rev_entries[i] = entries[i]; - qSort(rev_entries.begin(), rev_entries.end(), qtKey2CocoaKeySortLessThan); + std::sort(rev_entries.begin(), rev_entries.end(), qtKey2CocoaKeySortLessThan); } const QVector<KeyPair>::iterator i = qBinaryFind(rev_entries.begin(), rev_entries.end(), key); @@ -508,7 +510,6 @@ CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget) CGColorSpaceRef colorSpace; CGDirectDisplayID displayID; - CMProfileRef displayProfile = 0; if (widget == 0) { displayID = CGMainDisplayID(); } else { @@ -526,18 +527,11 @@ CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget) if ((colorSpace = m_displayColorSpaceHash.value(displayID))) return colorSpace; - CMError err = CMGetProfileByAVID((CMDisplayIDType)displayID, &displayProfile); - if (err == noErr) { - colorSpace = CGColorSpaceCreateWithPlatformColorSpace(displayProfile); - } else if (widget) { - return qt_mac_displayColorSpace(0); // fall back on main display - } - + colorSpace = CGDisplayCopyColorSpace(displayID); if (colorSpace == 0) colorSpace = CGColorSpaceCreateDeviceRGB(); m_displayColorSpaceHash.insert(displayID, colorSpace); - CMCloseProfile(displayProfile); if (!m_postRoutineRegistered) { m_postRoutineRegistered = true; void qt_mac_cleanUpMacColorSpaces(); @@ -810,20 +804,7 @@ CGImageRef qt_mac_toCGImage(const QImage &qImage, bool isMask, uchar **dataCopy) NULL, false); } else { - // Try get a device color space. Using the device color space means - // that the CGImage can be drawn to screen without per-pixel color - // space conversion, at the cost of less color accuracy. - CGColorSpaceRef cgColourSpaceRef = 0; - CMProfileRef sysProfile; - if (CMGetSystemProfile(&sysProfile) == noErr) - { - cgColourSpaceRef = CGColorSpaceCreateWithPlatformColorSpace(sysProfile); - CMCloseProfile(sysProfile); - } - - // Fall back to Generic RGB if a profile was not found. - if (!cgColourSpaceRef) - cgColourSpaceRef = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + CGColorSpaceRef cgColourSpaceRef = qt_mac_displayColorSpace(0); // Create a CGBitmapInfo contiaining the image format. // Support the 8-bit per component (A)RGB formats. @@ -857,7 +838,6 @@ CGImageRef qt_mac_toCGImage(const QImage &qImage, bool isMask, uchar **dataCopy) NULL, false, kCGRenderingIntentDefault); - CGColorSpaceRelease(cgColourSpaceRef); } CGDataProviderRelease(cgDataProviderRef); return cgImage; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index fad743439e..6d1882f622 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -232,7 +232,7 @@ QCocoaIntegration::QCocoaIntegration() qApp->setAttribute(Qt::AA_DontUseNativeMenuBar, false); - NSApplication *cocoaApplication = [QT_MANGLE_NAMESPACE(QNSApplication) sharedApplication]; + NSApplication *cocoaApplication = [QNSApplication sharedApplication]; qt_redirectNSApplicationSendEvent(); if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) { @@ -256,12 +256,12 @@ QCocoaIntegration::QCocoaIntegration() if (!QCoreApplication::testAttribute(Qt::AA_MacPluginApplication)) { // Set app delegate, link to the current delegate (if any) - QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate]; + QCocoaApplicationDelegate *newDelegate = [QCocoaApplicationDelegate sharedDelegate]; [newDelegate setReflectionDelegate:[cocoaApplication delegate]]; [cocoaApplication setDelegate:newDelegate]; // Load the application menu. This menu contains Preferences, Hide, Quit. - QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader = [[QT_MANGLE_NAMESPACE(QCocoaMenuLoader) alloc] init]; + QCocoaMenuLoader *qtMenuLoader = [[QCocoaMenuLoader alloc] init]; qt_mac_loadMenuNib(qtMenuLoader); [cocoaApplication setMenu:[qtMenuLoader menu]]; [newDelegate setMenuLoader:qtMenuLoader]; @@ -279,7 +279,7 @@ QCocoaIntegration::~QCocoaIntegration() QCocoaAutoReleasePool pool; if (!QCoreApplication::testAttribute(Qt::AA_MacPluginApplication)) { // remove the apple event handlers installed by QCocoaApplicationDelegate - QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *delegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate]; + QCocoaApplicationDelegate *delegate = [QCocoaApplicationDelegate sharedDelegate]; [delegate removeAppleEventHandlers]; // reset the application delegate [[NSApplication sharedApplication] setDelegate: 0]; diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 2e53000596..14b8dee101 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -74,7 +74,7 @@ NSString *qt_mac_removePrivateUnicode(NSString* string) return string; } -static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() +static inline QCocoaMenuLoader *getMenuLoader() { return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)]; } @@ -87,7 +87,9 @@ static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() @end -@implementation QT_MANGLE_NAMESPACE(QCocoaMenuDelegate) +QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate); + +@implementation QCocoaMenuDelegate - (id) initWithMenu:(QCocoaMenu*) m { @@ -220,11 +222,11 @@ QCocoaMenu::QCocoaMenu() : m_tag(0), m_menuBar(0) { - m_delegate = [[QT_MANGLE_NAMESPACE(QCocoaMenuDelegate) alloc] initWithMenu:this]; + m_delegate = [[QCocoaMenuDelegate alloc] initWithMenu:this]; m_nativeItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; m_nativeMenu = [[NSMenu alloc] initWithTitle:@"Untitled"]; [m_nativeMenu setAutoenablesItems:YES]; - m_nativeMenu.delegate = (QT_MANGLE_NAMESPACE(QCocoaMenuDelegate) *) m_delegate; + m_nativeMenu.delegate = (QCocoaMenuDelegate *) m_delegate; [m_nativeItem setSubmenu:m_nativeMenu]; } diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index ddfa9fff96..0fea55ac68 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -52,7 +52,7 @@ static QList<QCocoaMenuBar*> static_menubars; -static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() +static inline QCocoaMenuLoader *getMenuLoader() { return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)]; } @@ -240,7 +240,7 @@ void QCocoaMenuBar::updateMenuBarImmediately() } } - QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + QCocoaMenuLoader *loader = getMenuLoader(); [loader ensureAppMenuInMenu:mb->nsMenu()]; NSMutableSet *mergedItems = [[NSMutableSet setWithCapacity:0] retain]; diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 6d8174c667..013f9931ff 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -52,7 +52,7 @@ #include <QtCore/QDebug> -static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() +static inline QCocoaMenuLoader *getMenuLoader() { return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)]; } @@ -199,7 +199,7 @@ NSMenuItem *QCocoaMenuItem::sync() if ((m_role != NoRole && !m_textSynced) || m_merged) { NSMenuItem *mergeItem = nil; - QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + QCocoaMenuLoader *loader = getMenuLoader(); switch (m_role) { case ApplicationSpecificRole: mergeItem = [loader appSpecificMenuItem:reinterpret_cast<NSInteger>(this)]; @@ -326,7 +326,7 @@ QT_END_NAMESPACE QString QCocoaMenuItem::mergeText() { - QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + QCocoaMenuLoader *loader = getMenuLoader(); if (m_native == [loader aboutMenuItem]) { return qt_mac_applicationmenu_string(6).arg(qt_mac_applicationName()); } else if (m_native== [loader aboutQtMenuItem]) { @@ -344,7 +344,7 @@ QString QCocoaMenuItem::mergeText() QKeySequence QCocoaMenuItem::mergeAccel() { - QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); + QCocoaMenuLoader *loader = getMenuLoader(); if (m_native == [loader preferencesMenuItem]) return QKeySequence(QKeySequence::Preferences); else if (m_native == [loader quitMenuItem]) diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.h b/src/plugins/platforms/cocoa/qcocoamenuloader.h index a45ec0fa89..e07da39995 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.h +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.h @@ -92,9 +92,11 @@ - (NSArray *)mergeable; @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuLoader); + QT_BEGIN_NAMESPACE -void qt_mac_loadMenuNib(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader); +void qt_mac_loadMenuNib(QCocoaMenuLoader *qtMenuLoader); QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm index 62b722d2d2..29fc0fb674 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm @@ -69,7 +69,7 @@ QT_BEGIN_NAMESPACE and written to QDir::temp() before loading. (Earlier Qt versions used to require having the nib file in the Qt GUI framework.) */ -void qt_mac_loadMenuNib(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader) +void qt_mac_loadMenuNib(QCocoaMenuLoader *qtMenuLoader) { // Create qt_menu.nib dir in temp. QDir temp = QDir::temp(); @@ -106,7 +106,7 @@ void qt_mac_loadMenuNib(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader) QT_END_NAMESPACE -@implementation QT_MANGLE_NAMESPACE(QCocoaMenuLoader) +@implementation QCocoaMenuLoader - (void)awakeFromNib { diff --git a/src/plugins/platforms/cocoa/qcocoaservices.mm b/src/plugins/platforms/cocoa/qcocoaservices.mm index e4cec8c5f8..de4c688b71 100644 --- a/src/plugins/platforms/cocoa/qcocoaservices.mm +++ b/src/plugins/platforms/cocoa/qcocoaservices.mm @@ -55,7 +55,7 @@ bool QCocoaServices::openUrl(const QUrl &url) const QString scheme = url.scheme(); if (scheme.isEmpty()) return openDocument(url); - return [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:QT_PREPEND_NAMESPACE(QCFString::toNSString)(url.toString(QUrl::FullyEncoded))]]; + return [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:QCFString::toNSString(url.toString(QUrl::FullyEncoded))]]; } bool QCocoaServices::openDocument(const QUrl &url) @@ -63,7 +63,7 @@ bool QCocoaServices::openDocument(const QUrl &url) if (!url.isValid()) return false; - return [[NSWorkspace sharedWorkspace] openFile:QT_PREPEND_NAMESPACE(QCFString::toNSString)(url.toLocalFile())]; + return [[NSWorkspace sharedWorkspace] openFile:QCFString::toNSString(url.toLocalFile())]; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm index af817bd4c5..194394d11a 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -264,6 +264,10 @@ QHash<QPlatformTheme::Font, QFont *> qt_mac_createRoleFonts() fonts.insert(QPlatformTheme::SmallFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont)); fonts.insert(QPlatformTheme::MiniFont, qt_mac_qfontForThemeFont(kThemeMiniSystemFont)); + QFont* fixedFont = new QFont(QStringLiteral("Monaco"), fonts[QPlatformTheme::SystemFont]->pointSize()); + fixedFont->setStyleHint(QFont::TypeWriter); + fonts.insert(QPlatformTheme::FixedFont, fixedFont); + return fonts; } diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index 99f533b33a..83c960d931 100755 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -135,12 +135,16 @@ QT_USE_NAMESPACE -(id)initWithQMenu:(QPlatformMenu*)qmenu; @end +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSStatusItem); +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSImageView); +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSMenu); + QT_BEGIN_NAMESPACE class QSystemTrayIconSys { public: QSystemTrayIconSys(QCocoaSystemTrayIcon *sys) { - item = [[QT_MANGLE_NAMESPACE(QNSStatusItem) alloc] initWithSysTray:sys]; + item = [[QNSStatusItem alloc] initWithSysTray:sys]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:item]; @@ -156,7 +160,7 @@ public: #endif [item release]; } - QT_MANGLE_NAMESPACE(QNSStatusItem) *item; + QNSStatusItem *item; }; void QCocoaSystemTrayIcon::init() @@ -310,8 +314,8 @@ QT_END_NAMESPACE @implementation NSStatusItem (Qt) @end -@implementation QT_MANGLE_NAMESPACE(QNSImageView) --(id)initWithParent:(QT_MANGLE_NAMESPACE(QNSStatusItem)*)myParent { +@implementation QNSImageView +-(id)initWithParent:(QNSStatusItem*)myParent { self = [super init]; parent = myParent; down = NO; @@ -406,7 +410,7 @@ QT_END_NAMESPACE } @end -@implementation QT_MANGLE_NAMESPACE(QNSStatusItem) +@implementation QNSStatusItem -(id)initWithSysTray:(QCocoaSystemTrayIcon *)sys { @@ -416,7 +420,7 @@ QT_END_NAMESPACE menu = 0; menuVisible = false; systray = sys; - imageCell = [[QT_MANGLE_NAMESPACE(QNSImageView) alloc] initWithParent:self]; + imageCell = [[QNSImageView alloc] initWithParent:self]; [item setView: imageCell]; } return self; @@ -494,7 +498,7 @@ private: QSystemTrayIconQMenu(); }; -@implementation QT_MANGLE_NAMESPACE(QNSMenu) +@implementation QNSMenu -(id)initWithQMenu:(QPlatformMenu*)qm { self = [super init]; if (self) { diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index cac059763d..e4237c9b3e 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -68,7 +68,9 @@ public: const QPalette *palette(Palette type = SystemPalette) const; const QFont *font(Font type = SystemFont) const; QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; - QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; + QPixmap fileIconPixmap(const QFileInfo &fileInfo, + const QSizeF &size, + QPlatformTheme::IconOptions options = 0) const; QVariant themeHint(ThemeHint hint) const; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 13a387a0a3..1484ae2ba3 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -249,8 +249,10 @@ QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const return QPlatformTheme::standardPixmap(sp, size); } -QPixmap QCocoaTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +QPixmap QCocoaTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions) const { + Q_UNUSED(iconOptions); QCocoaAutoReleasePool pool; NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFile:QCFString::toNSString(fileInfo.canonicalFilePath())]; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index b82d096bb5..8967445f59 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -61,7 +61,7 @@ QT_FORWARD_DECLARE_CLASS(QCocoaWindow) @end @interface QNSPanel : NSPanel { - @public QT_PREPEND_NAMESPACE(QCocoaWindow) *m_cocoaPlatformWindow; + @public QCocoaWindow *m_cocoaPlatformWindow; } - (void)clearPlatformWindow; - (BOOL)canBecomeKeyWindow; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index c239aedb05..5fc2975a9d 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -155,6 +155,9 @@ static bool isMouseEvent(NSEvent *ev) - (BOOL)canBecomeKeyWindow { + if (!m_cocoaPlatformWindow) + return NO; + // Only tool or dialog windows should become key: if (m_cocoaPlatformWindow && (m_cocoaPlatformWindow->window()->type() == Qt::Tool || m_cocoaPlatformWindow->window()->type() == Qt::Dialog)) diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 3ee994427b..ca2a15a1cc 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -110,6 +110,10 @@ QT_END_NAMESPACE - (void)otherMouseUp:(NSEvent *)theEvent; - (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent; +- (void)handleTabletEvent: (NSEvent *)theEvent; +- (void)tabletPoint: (NSEvent *)theEvent; +- (void)tabletProximity: (NSEvent *)theEvent; + - (int) convertKeyCode : (QChar)keyCode; + (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags; - (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index c2ffe96f8c..b8a31329fe 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -489,7 +489,7 @@ static QTouchDevice *touchDevice = 0; return YES; } -- (void)convertFromEvent:(NSEvent *)event toWindowPoint:(QPoint *)qtWindowPoint andScreenPoint:(QPoint *)qtScreenPoint +- (void)convertFromEvent:(NSEvent *)event toWindowPoint:(QPointF *)qtWindowPoint andScreenPoint:(QPointF *)qtScreenPoint { // Calculate the mouse position in the QWindow and Qt screen coordinate system, // starting from coordinates in the NSWindow coordinate system. @@ -512,19 +512,19 @@ static QTouchDevice *touchDevice = 0; NSPoint nsWindowPoint = [event locationInWindow]; // NSWindow coordinates NSPoint nsViewPoint = [self convertPoint: nsWindowPoint fromView: nil]; // NSView/QWindow coordinates - *qtWindowPoint = QPoint(nsViewPoint.x, nsViewPoint.y); // NSView/QWindow coordinates + *qtWindowPoint = QPointF(nsViewPoint.x, nsViewPoint.y); // NSView/QWindow coordinates NSWindow *window = [self window]; // Use convertRectToScreen if available (added in 10.7). #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if ([window respondsToSelector:@selector(convertRectToScreen:)]) { NSRect screenRect = [window convertRectToScreen : NSMakeRect(nsWindowPoint.x, nsWindowPoint.y, 0, 0)]; // OS X screen coordinates - *qtScreenPoint = QPoint(screenRect.origin.x, qt_mac_flipYCoordinate(screenRect.origin.y)); // Qt screen coordinates + *qtScreenPoint = QPointF(screenRect.origin.x, qt_mac_flipYCoordinate(screenRect.origin.y)); // Qt screen coordinates } else #endif { NSPoint screenPoint = [window convertBaseToScreen : NSMakePoint(nsWindowPoint.x, nsWindowPoint.y)]; - *qtScreenPoint = QPoint(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y)); + *qtScreenPoint = QPointF(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y)); } } @@ -535,7 +535,10 @@ static QTouchDevice *touchDevice = 0; - (void)handleMouseEvent:(NSEvent *)theEvent { - QPoint qtWindowPoint, qtScreenPoint; + [self handleTabletEvent: theEvent]; + + QPointF qtWindowPoint; + QPointF qtScreenPoint; [self convertFromEvent:theEvent toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; ulong timestamp = [theEvent timestamp] * 1000; @@ -676,9 +679,10 @@ static QTouchDevice *touchDevice = 0; if (m_window->flags() & Qt::WindowTransparentForInput) return [super mouseMoved:theEvent]; - QPoint windowPoint, screenPoint; + QPointF windowPoint; + QPointF screenPoint; [self convertFromEvent:theEvent toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; - QWindow *childWindow = m_platformWindow->childWindowAt(windowPoint); + QWindow *childWindow = m_platformWindow->childWindowAt(windowPoint.toPoint()); // Top-level windows generate enter-leave events for sub-windows. // Qt wants to know which window (if any) will be entered at the @@ -709,9 +713,10 @@ static QTouchDevice *touchDevice = 0; if (!m_platformWindow->m_nsWindow) return; - QPoint windowPoint, screenPoint; + QPointF windowPoint; + QPointF screenPoint; [self convertFromEvent:theEvent toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; - m_platformWindow->m_underMouseWindow = m_platformWindow->childWindowAt(windowPoint); + m_platformWindow->m_underMouseWindow = m_platformWindow->childWindowAt(windowPoint.toPoint()); QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_underMouseWindow, windowPoint, screenPoint); } @@ -779,6 +784,162 @@ static QTouchDevice *touchDevice = 0; [self handleMouseEvent:theEvent]; } +struct QCocoaTabletDeviceData +{ + QTabletEvent::TabletDevice device; + QTabletEvent::PointerType pointerType; + uint capabilityMask; + qint64 uid; +}; + +typedef QHash<uint, QCocoaTabletDeviceData> QCocoaTabletDeviceDataHash; +Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash) + +- (void)handleTabletEvent: (NSEvent *)theEvent +{ + NSEventType eventType = [theEvent type]; + if (eventType != NSTabletPoint && [theEvent subtype] != NSTabletPointEventSubtype) + return; // Not a tablet event. + + ulong timestamp = [theEvent timestamp] * 1000; + + QPointF windowPoint; + QPointF screenPoint; + [self convertFromEvent: theEvent toWindowPoint: &windowPoint andScreenPoint: &screenPoint]; + + uint deviceId = [theEvent deviceID]; + if (!tabletDeviceDataHash->contains(deviceId)) { + qWarning("QNSView handleTabletEvent: This tablet device is unknown" + " (received no proximity event for it). Discarding event."); + return; + } + const QCocoaTabletDeviceData &deviceData = tabletDeviceDataHash->value(deviceId); + + bool down = (eventType != NSMouseMoved); + + qreal pressure; + if (down) { + pressure = [theEvent pressure]; + } else { + pressure = 0.0; + } + + NSPoint tilt = [theEvent tilt]; + int xTilt = qRound(tilt.x * 60.0); + int yTilt = qRound(tilt.y * -60.0); + qreal tangentialPressure = 0; + qreal rotation = 0; + int z = 0; + if (deviceData.capabilityMask & 0x0200) + z = [theEvent absoluteZ]; + + if (deviceData.capabilityMask & 0x0800) + tangentialPressure = [theEvent tangentialPressure]; + + rotation = [theEvent rotation]; + + Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; + + QWindowSystemInterface::handleTabletEvent(m_window, timestamp, down, windowPoint, screenPoint, + deviceData.device, deviceData.pointerType, pressure, xTilt, yTilt, + tangentialPressure, rotation, z, deviceData.uid, + keyboardModifiers); +} + +- (void)tabletPoint: (NSEvent *)theEvent +{ + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super tabletPoint:theEvent]; + + [self handleTabletEvent: theEvent]; +} + +static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) +{ + qint64 uid = [theEvent uniqueID]; + uint bits = [theEvent vendorPointingDeviceType]; + if (bits == 0 && uid != 0) { + // Fallback. It seems that the driver doesn't always include all the information. + // High-End Wacom devices store their "type" in the uper bits of the Unique ID. + // I'm not sure how to handle it for consumer devices, but I'll test that in a bit. + bits = uid >> 32; + } + + QTabletEvent::TabletDevice device; + // Defined in the "EN0056-NxtGenImpGuideX" + // on Wacom's Developer Website (www.wacomeng.com) + if (((bits & 0x0006) == 0x0002) && ((bits & 0x0F06) != 0x0902)) { + device = QTabletEvent::Stylus; + } else { + switch (bits & 0x0F06) { + case 0x0802: + device = QTabletEvent::Stylus; + break; + case 0x0902: + device = QTabletEvent::Airbrush; + break; + case 0x0004: + device = QTabletEvent::FourDMouse; + break; + case 0x0006: + device = QTabletEvent::Puck; + break; + case 0x0804: + device = QTabletEvent::RotationStylus; + break; + default: + device = QTabletEvent::NoDevice; + } + } + return device; +} + +- (void)tabletProximity: (NSEvent *)theEvent +{ + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super tabletProximity:theEvent]; + + ulong timestamp = [theEvent timestamp] * 1000; + + QCocoaTabletDeviceData deviceData; + deviceData.uid = [theEvent uniqueID]; + deviceData.capabilityMask = [theEvent capabilityMask]; + + switch ([theEvent pointingDeviceType]) { + case NSUnknownPointingDevice: + default: + deviceData.pointerType = QTabletEvent::UnknownPointer; + break; + case NSPenPointingDevice: + deviceData.pointerType = QTabletEvent::Pen; + break; + case NSCursorPointingDevice: + deviceData.pointerType = QTabletEvent::Cursor; + break; + case NSEraserPointingDevice: + deviceData.pointerType = QTabletEvent::Eraser; + break; + } + + deviceData.device = wacomTabletDevice(theEvent); + + // The deviceID is "unique" while in the proximity, it's a key that we can use for + // linking up QCocoaTabletDeviceData to an event (especially if there are two devices in action). + bool entering = [theEvent isEnteringProximity]; + uint deviceId = [theEvent deviceID]; + if (entering) { + tabletDeviceDataHash->insert(deviceId, deviceData); + } else { + tabletDeviceDataHash->remove(deviceId); + } + + if (entering) { + QWindowSystemInterface::handleTabletEnterProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid); + } else { + QWindowSystemInterface::handleTabletLeaveProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid); + } +} + - (void)touchesBeganWithEvent:(NSEvent *)event { const NSTimeInterval timestamp = [event timestamp]; @@ -859,7 +1020,8 @@ static QTouchDevice *touchDevice = 0; } #endif - QPoint qt_windowPoint, qt_screenPoint; + QPointF qt_windowPoint; + QPointF qt_screenPoint; [self convertFromEvent:theEvent toWindowPoint:&qt_windowPoint andScreenPoint:&qt_screenPoint]; NSTimeInterval timestamp = [theEvent timestamp]; ulong qt_timestamp = timestamp * 1000; @@ -878,7 +1040,23 @@ static QTouchDevice *touchDevice = 0; currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; } - QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers); + Qt::ScrollPhase ph = Qt::ScrollUpdate; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { + // On 10.8 and above, MayBegin is likely to happen. We treat it the same as an actual begin. + if (phase == NSEventPhaseMayBegin) + ph = Qt::ScrollBegin; + } else +#endif + if (phase == NSEventPhaseBegan) { + // On 10.7, MayBegin will not happen, so Began is the actual beginning. + ph = Qt::ScrollBegin; + } + if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled) { + ph = Qt::ScrollEnd; + } + + QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph); if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled || phase == NSEventPhaseNone) { currentWheelModifiers = Qt::NoModifier; @@ -921,14 +1099,11 @@ static QTouchDevice *touchDevice = 0; NSString *charactersIgnoringModifiers = [nsevent charactersIgnoringModifiers]; NSString *characters = [nsevent characters]; - // [from Qt 4 impl] There is no way to get the scan code from carbon. But we cannot + // There is no way to get the scan code from carbon/cocoa. But we cannot // use the value 0, since it indicates that the event originates from somewhere // else than the keyboard. quint32 nativeScanCode = 1; - - UInt32 nativeVirtualKey = 0; - EventRef eventRef = EventRef([nsevent eventRef]); - GetEventParameter(eventRef, kEventParamKeyCode, typeUInt32, 0, sizeof(nativeVirtualKey), 0, &nativeVirtualKey); + quint32 nativeVirtualKey = [nsevent keyCode]; QChar ch = QChar::ReplacementCharacter; int keyCode = Qt::Key_unknown; diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 301beb11c1..dc3757ce3c 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -362,7 +362,6 @@ CGColorSpaceRef QCoreGraphicsPaintEngine::macDisplayColorSpace(const QWidget *wi CGColorSpaceRef colorSpace; CGDirectDisplayID displayID; - CMProfileRef displayProfile = 0; if (widget == 0) { displayID = CGMainDisplayID(); } else { @@ -376,18 +375,11 @@ CGColorSpaceRef QCoreGraphicsPaintEngine::macDisplayColorSpace(const QWidget *wi if ((colorSpace = m_displayColorSpaceHash.value(displayID))) return colorSpace; - CMError err = CMGetProfileByAVID((CMDisplayIDType)displayID, &displayProfile); - if (err == noErr) { - colorSpace = CGColorSpaceCreateWithPlatformColorSpace(displayProfile); - } else if (widget) { - return macDisplayColorSpace(0); // fall back on main display - } - + colorSpace = CGDisplayCopyColorSpace(displayID); if (colorSpace == 0) colorSpace = CGColorSpaceCreateDeviceRGB(); m_displayColorSpaceHash.insert(displayID, colorSpace); - CMCloseProfile(displayProfile); if (!m_postRoutineRegistered) { m_postRoutineRegistered = true; qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces); diff --git a/src/plugins/platforms/directfb/main.cpp b/src/plugins/platforms/directfb/main.cpp index 3d5d60abaa..5ba1b0996b 100644 --- a/src/plugins/platforms/directfb/main.cpp +++ b/src/plugins/platforms/directfb/main.cpp @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE class QDirectFbIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "directfb.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "directfb.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp index 939d8c0686..5b4c958616 100644 --- a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp +++ b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp @@ -286,6 +286,14 @@ QDirectFbKeyMap::QDirectFbKeyMap() insert(DIKS_MAIL , Qt::Key_LaunchMail); insert(DIKS_FAVORITES , Qt::Key_Favorites); + insert(DIKS_RED , Qt::Key_Red); + insert(DIKS_GREEN , Qt::Key_Green); + insert(DIKS_YELLOW , Qt::Key_Yellow); + insert(DIKS_BLUE , Qt::Key_Blue); + + insert(DIKS_CHANNEL_UP , Qt::Key_ChannelUp); + insert(DIKS_CHANNEL_DOWN , Qt::Key_ChannelDown); + insert(DIKS_BACK , Qt::Key_Back); insert(DIKS_FORWARD , Qt::Key_Forward); insert(DIKS_VOLUME_UP , Qt::Key_VolumeUp); diff --git a/src/plugins/platforms/eglfs/main.cpp b/src/plugins/platforms/eglfs/main.cpp index df77127b4a..d8e7a3792e 100644 --- a/src/plugins/platforms/eglfs/main.cpp +++ b/src/plugins/platforms/eglfs/main.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class QEglFSIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "eglfs.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "eglfs.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp index cf1503b7f9..c2d04b17c8 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -74,6 +74,8 @@ QT_BEGIN_NAMESPACE +static void *eglContextForContext(QOpenGLContext *context); + QEglFSIntegration::QEglFSIntegration() : mEventDispatcher(createUnixEventDispatcher()), mFontDb(new QGenericUnixFontDatabase()) { @@ -200,6 +202,20 @@ void *QEglFSIntegration::nativeResourceForIntegration(const QByteArray &resource return 0; } +void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window) +{ + QByteArray lowerCaseResource = resource.toLower(); + + if (lowerCaseResource == "egldisplay") { + if (window && window->handle()) + return static_cast<QEglFSScreen *>(window->handle()->screen())->display(); + else + return static_cast<QEglFSScreen *>(mScreen)->display(); + } + + return 0; +} + void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { QByteArray lowerCaseResource = resource.toLower(); @@ -215,6 +231,26 @@ void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QO return 0; } +QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::nativeResourceFunctionForContext(const QByteArray &resource) +{ + QByteArray lowerCaseResource = resource.toLower(); + if (lowerCaseResource == "get_egl_context") + return NativeResourceForContextFunction(eglContextForContext); + + return 0; +} + +static void *eglContextForContext(QOpenGLContext *context) +{ + Q_ASSERT(context); + + QEGLPlatformContext *handle = static_cast<QEGLPlatformContext *>(context->handle()); + if (!handle) + return 0; + + return handle->eglContext(); +} + EGLConfig QEglFSIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format) { class Chooser : public QEglConfigChooser { diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h index bf044d6919..dd85788bd8 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsintegration.h @@ -72,8 +72,11 @@ public: // QPlatformNativeInterface void *nativeResourceForIntegration(const QByteArray &resource); + void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE; void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context); + NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) Q_DECL_OVERRIDE; + QPlatformScreen *screen() const { return mScreen; } static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format); diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/qeglfsscreen.cpp index 6cb1f88c66..1fe8bcc11b 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp +++ b/src/plugins/platforms/eglfs/qeglfsscreen.cpp @@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE QEglFSScreen::QEglFSScreen(EGLDisplay dpy) : m_dpy(dpy) + , m_surface(0) , m_cursor(0) { #ifdef QEGL_EXTRA_DEBUG @@ -95,4 +96,9 @@ QPlatformCursor *QEglFSScreen::cursor() const return m_cursor; } +void QEglFSScreen::setPrimarySurface(EGLSurface surface) +{ + m_surface = surface; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h index 298a67cd3a..b04c85797f 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.h +++ b/src/plugins/platforms/eglfs/qeglfsscreen.h @@ -69,9 +69,16 @@ public: QPlatformCursor *cursor() const; EGLDisplay display() const { return m_dpy; } + EGLSurface primarySurface() const { return m_surface; } + +protected: + void setPrimarySurface(EGLSurface surface); private: + friend class QEglFSWindow; + EGLDisplay m_dpy; + EGLSurface m_surface; QEglFSCursor *m_cursor; }; diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index 28ce8c8a33..bf6e375ac0 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -42,6 +42,8 @@ #include "qeglfswindow.h" #include "qeglfshooks.h" #include <qpa/qwindowsysteminterface.h> +#include <qpa/qplatformintegration.h> +#include <private/qguiapplication_p.h> #include <QtPlatformSupport/private/qeglconvenience_p.h> @@ -66,6 +68,11 @@ QEglFSWindow::~QEglFSWindow() destroy(); } +static inline bool supportsMultipleWindows() +{ + return QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::MultipleWindows); +} + void QEglFSWindow::create() { if (has_window) @@ -80,6 +87,9 @@ void QEglFSWindow::create() return; } + if (!supportsMultipleWindows() && screen()->primarySurface()) + return; + EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display(); QSurfaceFormat platformFormat = QEglFSHooks::hooks()->surfaceFormatFor(window()->requestedFormat()); m_config = QEglFSIntegration::chooseConfig(display, platformFormat); @@ -105,11 +115,14 @@ void QEglFSWindow::resetSurface() m_window = QEglFSHooks::hooks()->createNativeWindow(QEglFSHooks::hooks()->screenSize(), m_format); has_window = true; m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL); + if (m_surface == EGL_NO_SURFACE) { EGLint error = eglGetError(); eglTerminate(display); qFatal("EGL Error : Could not create the egl surface: error = 0x%x\n", error); } + + screen()->setPrimarySurface(m_surface); } void QEglFSWindow::destroy() @@ -117,6 +130,12 @@ void QEglFSWindow::destroy() if (m_surface) { EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display(); eglDestroySurface(display, m_surface); + + if (!supportsMultipleWindows()) { + // ours must be the primary surface + screen()->setPrimarySurface(0); + } + m_surface = 0; } @@ -145,9 +164,21 @@ WId QEglFSWindow::winId() const return WId(m_window); } +EGLSurface QEglFSWindow::surface() const +{ + if (!supportsMultipleWindows()) + return screen()->primarySurface(); + return m_surface; +} + QSurfaceFormat QEglFSWindow::format() const { return m_format; } +QEglFSScreen *QEglFSWindow::screen() const +{ + return static_cast<QEglFSScreen *>(QPlatformWindow::screen()); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h index 0997f80e74..936537807a 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.h +++ b/src/plugins/platforms/eglfs/qeglfswindow.h @@ -59,9 +59,11 @@ public: void setWindowState(Qt::WindowState state); WId winId() const; - EGLSurface surface() const { return m_surface; } + EGLSurface surface() const; QSurfaceFormat format() const; + QEglFSScreen *screen() const; + void create(); void destroy(); diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro index 842ff17f1c..5a2129eb08 100644 --- a/src/plugins/platforms/ios/ios.pro +++ b/src/plugins/platforms/ios/ios.pro @@ -1,3 +1,39 @@ -TEMPLATE = subdirs +TARGET = qios -SUBDIRS += plugin.pro qtmain.pro +PLUGIN_TYPE = platforms +PLUGIN_CLASS_NAME = QIOSIntegrationPlugin +load(qt_plugin) + +QT += core-private gui-private platformsupport-private +LIBS += -framework Foundation -framework UIKit -framework QuartzCore + +OBJECTIVE_SOURCES = \ + plugin.mm \ + qiosmain_wrapper.mm \ + qiosmain_dummy.mm \ + qiosintegration.mm \ + qioswindow.mm \ + qiosscreen.mm \ + qiosbackingstore.mm \ + qiosapplicationdelegate.mm \ + qiosapplicationstate.mm \ + qiosviewcontroller.mm \ + qioscontext.mm \ + qiosinputcontext.mm \ + qiostheme.mm \ + qiosglobal.mm + +HEADERS = \ + qiosintegration.h \ + qioswindow.h \ + qiosscreen.h \ + qiosbackingstore.h \ + qiosapplicationdelegate.h \ + qiosapplicationstate.h \ + qiosviewcontroller.h \ + qioscontext.h \ + qiosinputcontext.h \ + qiostheme.h \ + qiosglobal.h + +#HEADERS = qiossoftwareinputhandler.h diff --git a/src/plugins/platforms/ios/plugin.mm b/src/plugins/platforms/ios/plugin.mm index a93b6037ad..efb1ad8d74 100644 --- a/src/plugins/platforms/ios/plugin.mm +++ b/src/plugins/platforms/ios/plugin.mm @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE class QIOSIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "ios.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "ios.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; @@ -66,4 +66,8 @@ QT_END_NAMESPACE #include "plugin.moc" +// Dummy function that we explicitly tell the linker to look for, +// so that the plugin's static initializer is included and run. +extern "C" void qt_registerPlatformPlugin() {} + Q_IMPORT_PLUGIN(QIOSIntegrationPlugin) diff --git a/src/plugins/platforms/ios/plugin.pro b/src/plugins/platforms/ios/plugin.pro deleted file mode 100644 index 591a0a67ed..0000000000 --- a/src/plugins/platforms/ios/plugin.pro +++ /dev/null @@ -1,36 +0,0 @@ -TARGET = qios - -PLUGIN_TYPE = platforms -load(qt_plugin) - -QT += core-private gui-private platformsupport-private -LIBS += -framework UIKit -framework QuartzCore - -OBJECTIVE_SOURCES = \ - plugin.mm \ - qiosintegration.mm \ - qioswindow.mm \ - qiosscreen.mm \ - qioseventdispatcher.mm \ - qiosbackingstore.mm \ - qiosapplicationdelegate.mm \ - qiosviewcontroller.mm \ - qioscontext.mm \ - qiosinputcontext.mm \ - qiostheme.mm \ - qiosglobal.mm - -HEADERS = \ - qiosintegration.h \ - qioswindow.h \ - qiosscreen.h \ - qioseventdispatcher.h \ - qiosbackingstore.h \ - qiosapplicationdelegate.h \ - qiosviewcontroller.h \ - qioscontext.h \ - qiosinputcontext.h \ - qiostheme.h \ - qiosglobal.h - -#HEADERS = qiossoftwareinputhandler.h diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.h b/src/plugins/platforms/ios/qiosapplicationdelegate.h index 3d3ba58049..bfe31af198 100644 --- a/src/plugins/platforms/ios/qiosapplicationdelegate.h +++ b/src/plugins/platforms/ios/qiosapplicationdelegate.h @@ -50,7 +50,3 @@ @property (strong, nonatomic) QIOSViewController *qiosViewController; @end - -@interface QIOSMainWrapperApplicationDelegate : QIOSApplicationDelegate -@end - diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm index 10cbe529c4..52d94f38fb 100644 --- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm +++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm @@ -39,10 +39,15 @@ ** ****************************************************************************/ -#import "qiosapplicationdelegate.h" +#include "qiosapplicationdelegate.h" + +#include "qiosviewcontroller.h" #include "qioswindow.h" + #include <QtCore/QtCore> +extern int qt_user_main(int argc, char *argv[]); + @implementation QIOSApplicationDelegate @synthesize window; @@ -50,40 +55,43 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - Q_UNUSED(application) - Q_UNUSED(launchOptions) + Q_UNUSED(application); + Q_UNUSED(launchOptions); - return YES; -} + self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; + self.qiosViewController = [[[QIOSViewController alloc] init] autorelease]; + self.window.rootViewController = self.qiosViewController; -- (void)applicationWillResignActive:(UIApplication *)application -{ - Q_UNUSED(application) -} +#ifdef QT_DEBUG + self.window.backgroundColor = [UIColor cyanColor]; +#endif -- (void)applicationDidEnterBackground:(UIApplication *)application -{ - Q_UNUSED(application) -} + [self.window makeKeyAndVisible]; -- (void)applicationWillEnterForeground:(UIApplication *)application -{ - Q_UNUSED(application) - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. -} + // We schedule the main-redirection for the next eventloop pass so that we + // can return from this function and let UIApplicationMain finish its job. + [NSTimer scheduledTimerWithTimeInterval:.01f target:self + selector:@selector(runUserMain) userInfo:nil repeats:NO]; -- (void)applicationDidBecomeActive:(UIApplication *)application -{ - Q_UNUSED(application) - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + return YES; } -- (void)applicationWillTerminate:(UIApplication *)application +- (void)runUserMain { - Q_UNUSED(application) - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + NSArray *arguments = [[NSProcessInfo processInfo] arguments]; + int argc = arguments.count; + char **argv = new char*[argc]; + for (int i = 0; i < argc; ++i) { + NSString *arg = [arguments objectAtIndex:i]; + argv[i] = reinterpret_cast<char *>(malloc([arg lengthOfBytesUsingEncoding:[NSString defaultCStringEncoding]])); + strcpy(argv[i], [arg cStringUsingEncoding:[NSString defaultCStringEncoding]]); + } + + qt_user_main(argc, argv); + delete[] argv; } + - (void)dealloc { [qiosViewController release]; @@ -93,4 +101,3 @@ @end - diff --git a/src/plugins/platforms/kms/qkmsudevhandler.h b/src/plugins/platforms/ios/qiosapplicationstate.h index e95960628a..e726ad895e 100644 --- a/src/plugins/platforms/kms/qkmsudevhandler.h +++ b/src/plugins/platforms/ios/qiosapplicationstate.h @@ -39,26 +39,22 @@ ** ****************************************************************************/ -#ifndef QKMSUDEVHANDLER_H -#define QKMSUDEVHANDLER_H - -#include <QObject> - -#include <libudev.h> +#ifndef QIOSAPPLICATIONSTATE_H +#define QIOSAPPLICATIONSTATE_H QT_BEGIN_NAMESPACE -class QKmsUdevHandler : public QObject -{ - Q_OBJECT +@class QIOSApplicationStateListener; +class QIOSApplicationState +{ public: - QKmsUdevHandler(QObject *parent = 0); - virtual ~QKmsUdevHandler(); - - virtual QObject *create(struct udev_device *) = 0; + QIOSApplicationState(); + ~QIOSApplicationState(); +private: + QIOSApplicationStateListener *m_listener; }; QT_END_NAMESPACE -#endif // QKMSUDEVHANDLER_H +#endif diff --git a/src/plugins/platforms/ios/qiosapplicationstate.mm b/src/plugins/platforms/ios/qiosapplicationstate.mm new file mode 100644 index 0000000000..df64edf465 --- /dev/null +++ b/src/plugins/platforms/ios/qiosapplicationstate.mm @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import <UIKit/UIKit.h> + +#include <qpa/qwindowsysteminterface.h> +#include "qiosapplicationstate.h" + +@interface QIOSApplicationStateListener : NSObject +@end + +@implementation QIOSApplicationStateListener + +- (id) init +{ + self = [super init]; + if (self) { + // Listen for application state changes. + // Note: We use notifications rather than application delegate callbacks to + // also support hybrid applications were QIOSApplicationDelegate is not in use. + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(applicationDidBecomeActive) + name:UIApplicationDidBecomeActiveNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(applicationWillResignActive) + name:UIApplicationWillResignActiveNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(applicationDidEnterBackground) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; + } + return self; +} + +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:UIApplicationDidBecomeActiveNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:UIApplicationWillResignActiveNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:UIApplicationDidEnterBackgroundNotification + object:nil]; + [super dealloc]; +} + +- (void) applicationDidBecomeActive +{ + [self handleApplicationStateChanged:UIApplicationStateActive]; +} + +- (void) applicationWillResignActive +{ + // Note that UIApplication is still UIApplicationStateActive at this + // point, but since there is no separate notification for the inactive + // state, we report UIApplicationStateInactive now: + [self handleApplicationStateChanged:UIApplicationStateInactive]; +} + +- (void) applicationDidEnterBackground +{ + [self handleApplicationStateChanged:UIApplicationStateBackground]; +} + +- (void) handleApplicationStateChanged:(UIApplicationState) uiApplicationState +{ + Qt::ApplicationState state; + switch (uiApplicationState) { + case UIApplicationStateActive: + // The application is visible in front, and receiving events: + state = Qt::ApplicationActive; + break; + case UIApplicationStateInactive: + // The app is running in the foreground but is not receiving events. This + // typically happens while transitioning to/from active/background, like + // upon app launch or when receiving incoming calls: + state = Qt::ApplicationInactive; + break; + case UIApplicationStateBackground: + // Normally the app would enter this state briefly before it gets + // suspeded (you have five seconds, according to Apple). + // You can request more time and start a background task, which would + // normally map closer to Qt::ApplicationHidden. But since we have no + // API for doing that yet, we handle this state as "about to be suspended". + // Note: A screen-shot for the SpringBoard will also be taken after this + // call returns. + state = Qt::ApplicationSuspended; + break; + } + QWindowSystemInterface::handleApplicationStateChanged(state); +} + +@end + +QT_BEGIN_NAMESPACE + +QIOSApplicationState::QIOSApplicationState() + : m_listener([[QIOSApplicationStateListener alloc] init]) +{ + // Update the current state now, since we have missed all the updates + // posted from AppKit so far. But let QPA finish initialization first: + dispatch_async(dispatch_get_main_queue(), ^{ + UIApplicationState state = [UIApplication sharedApplication].applicationState; + [m_listener handleApplicationStateChanged:state]; + }); +} + +QIOSApplicationState::~QIOSApplicationState() +{ + [m_listener release]; +} + +QT_END_NAMESPACE + diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm index 87bcc01d04..0c4bee1ef0 100644 --- a/src/plugins/platforms/ios/qioscontext.mm +++ b/src/plugins/platforms/ios/qioscontext.mm @@ -151,17 +151,17 @@ GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const connect(window, SIGNAL(destroyed(QObject*)), this, SLOT(windowDestroyed(QObject*))); } - // Ensure that the FBO's buffers match the size of the window + // Ensure that the FBO's buffers match the size of the layer QIOSWindow *platformWindow = static_cast<QIOSWindow *>(surface); - if (framebufferObject.renderbufferWidth != platformWindow->effectiveWidth() || - framebufferObject.renderbufferHeight != platformWindow->effectiveHeight()) { + UIView *view = reinterpret_cast<UIView *>(platformWindow->winId()); + CAEAGLLayer *layer = static_cast<CAEAGLLayer *>(view.layer); + if (framebufferObject.renderbufferWidth != (layer.frame.size.width * layer.contentsScale) || + framebufferObject.renderbufferHeight != (layer.frame.size.height * layer.contentsScale)) { [EAGLContext setCurrentContext:m_eaglContext]; glBindFramebuffer(GL_FRAMEBUFFER, framebufferObject.handle); glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.colorRenderbuffer); - UIView *view = reinterpret_cast<UIView *>(platformWindow->winId()); - CAEAGLLayer *layer = static_cast<CAEAGLLayer *>(view.layer); [m_eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer]; glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &framebufferObject.renderbufferWidth); @@ -200,7 +200,7 @@ void QIOSContext::windowDestroyed(QObject *object) QFunctionPointer QIOSContext::getProcAddress(const QByteArray& functionName) { - return reinterpret_cast<QFunctionPointer>(dlsym(RTLD_NEXT, functionName.constData())); + return QFunctionPointer(dlsym(RTLD_DEFAULT, functionName.constData())); } #include "moc_qioscontext.cpp" diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/plugins/platforms/ios/qioseventdispatcher.h deleted file mode 100644 index 53a75618ce..0000000000 --- a/src/plugins/platforms/ios/qioseventdispatcher.h +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, 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. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/**************************************************************************** -** -** Copyright (c) 2007-2008, Apple, Inc. -** -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are met: -** -** * Redistributions of source code must retain the above copyright notice, -** this list of conditions and the following disclaimer. -** -** * Redistributions in binary form must reproduce the above copyright notice, -** this list of conditions and the following disclaimer in the documentation -** and/or other materials provided with the distribution. -** -** * Neither the name of Apple, Inc. nor the names of its contributors -** may be used to endorse or promote products derived from this software -** without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -** -****************************************************************************/ - -#ifndef QEVENTDISPATCHER_IOS_P_H -#define QEVENTDISPATCHER_IOS_P_H - -#include <QtCore/qabstracteventdispatcher.h> -#include <QtCore/private/qtimerinfo_unix_p.h> -#include <QtPlatformSupport/private/qcfsocketnotifier_p.h> -#include <CoreFoundation/CoreFoundation.h> - -QT_BEGIN_NAMESPACE - -class QIOSEventDispatcher : public QAbstractEventDispatcher -{ - Q_OBJECT - -public: - explicit QIOSEventDispatcher(QObject *parent = 0); - ~QIOSEventDispatcher(); - - bool processEvents(QEventLoop::ProcessEventsFlags flags); - bool hasPendingEvents(); - - void registerSocketNotifier(QSocketNotifier *notifier); - void unregisterSocketNotifier(QSocketNotifier *notifier); - - void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object); - bool unregisterTimer(int timerId); - bool unregisterTimers(QObject *object); - QList<QAbstractEventDispatcher::TimerInfo> registeredTimers(QObject *object) const; - - int remainingTime(int timerId); - - void wakeUp(); - void interrupt(); - void flush(); - -private: - bool m_interrupted; - - CFRunLoopSourceRef m_postedEventsRunLoopSource; - CFRunLoopSourceRef m_blockingTimerRunLoopSource; - - QTimerInfoList m_timerInfoList; - CFRunLoopTimerRef m_runLoopTimerRef; - - QCFSocketNotifier m_cfSocketNotifier; - - void processPostedEvents(); - void maybeStartCFRunLoopTimer(); - void maybeStopCFRunLoopTimer(); - - static void postedEventsRunLoopCallback(void *info); - static void nonBlockingTimerRunLoopCallback(CFRunLoopTimerRef, void *info); - static void blockingTimerRunLoopCallback(void *info); -}; - -QT_END_NAMESPACE - -#endif // QEVENTDISPATCHER_IOS_P_H diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm deleted file mode 100644 index e9bf039047..0000000000 --- a/src/plugins/platforms/ios/qioseventdispatcher.mm +++ /dev/null @@ -1,322 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, 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. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qioseventdispatcher.h" -#import "qiosapplicationdelegate.h" -#include <qdebug.h> -#include <qpa/qwindowsysteminterface.h> -#include <QtCore/QThread> -#include <QtCore/private/qcoreapplication_p.h> -#include <UIKit/UIApplication.h> - -QT_BEGIN_NAMESPACE -QT_USE_NAMESPACE - -static Boolean runLoopSourceEqualCallback(const void *info1, const void *info2) -{ - return info1 == info2; -} - -void QIOSEventDispatcher::postedEventsRunLoopCallback(void *info) -{ - QIOSEventDispatcher *self = static_cast<QIOSEventDispatcher *>(info); - self->processPostedEvents(); -} - -void QIOSEventDispatcher::nonBlockingTimerRunLoopCallback(CFRunLoopTimerRef, void *info) -{ - // The (one and only) CFRunLoopTimer has fired, which means that at least - // one QTimer should now fire as well. Note that CFRunLoopTimer's callback will - // never recurse. So if the app starts a new QEventLoop within this callback, other - // timers will stop working. The work-around is to forward the callback to a - // dedicated CFRunLoopSource that can recurse: - QIOSEventDispatcher *self = static_cast<QIOSEventDispatcher *>(info); - CFRunLoopSourceSignal(self->m_blockingTimerRunLoopSource); -} - -void QIOSEventDispatcher::blockingTimerRunLoopCallback(void *info) -{ - // TODO: - // We also need to block this new timer source - // along with the posted event source when calling processEvents() - // "manually" to prevent livelock deep in CFRunLoop. - - QIOSEventDispatcher *self = static_cast<QIOSEventDispatcher *>(info); - self->m_timerInfoList.activateTimers(); - self->maybeStartCFRunLoopTimer(); -} - -void QIOSEventDispatcher::maybeStartCFRunLoopTimer() -{ - // Find out when the next registered timer should fire, and schedule - // runLoopTimer accordingly. If the runLoopTimer does not yet exist, and - // at least one timer is registered, start by creating the timer: - if (m_timerInfoList.isEmpty()) { - Q_ASSERT(m_runLoopTimerRef == 0); - return; - } - - CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent(); - CFTimeInterval interval; - - if (m_runLoopTimerRef == 0) { - // start the CFRunLoopTimer - CFTimeInterval oneyear = CFTimeInterval(3600. * 24. * 365.); - - // calculate when the next timer should fire: - struct timespec tv; - if (m_timerInfoList.timerWait(tv)) { - interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001); - } else { - // this shouldn't really happen, but in case it does, set the timer - // to fire a some point in the distant future: - interval = oneyear; - } - - ttf += interval; - CFRunLoopTimerContext info = { 0, this, 0, 0, 0 }; - // create the timer with a large interval, as recommended by the CFRunLoopTimerSetNextFireDate() - // documentation, since we will adjust the timer's time-to-fire as needed to keep Qt timers working - m_runLoopTimerRef = CFRunLoopTimerCreate(0, ttf, oneyear, 0, 0, QIOSEventDispatcher::nonBlockingTimerRunLoopCallback, &info); - Q_ASSERT(m_runLoopTimerRef != 0); - - CFRunLoopAddTimer(CFRunLoopGetMain(), m_runLoopTimerRef, kCFRunLoopCommonModes); - } else { - struct timespec tv; - // Calculate when the next timer should fire: - if (m_timerInfoList.timerWait(tv)) { - interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001); - } else { - // no timers can fire, but we cannot stop the CFRunLoopTimer, set the timer to fire at some - // point in the distant future (the timer interval is one year) - interval = CFRunLoopTimerGetInterval(m_runLoopTimerRef); - } - - ttf += interval; - CFRunLoopTimerSetNextFireDate(m_runLoopTimerRef, ttf); - } -} - -void QIOSEventDispatcher::maybeStopCFRunLoopTimer() -{ - if (m_runLoopTimerRef == 0) - return; - - CFRunLoopTimerInvalidate(m_runLoopTimerRef); - CFRelease(m_runLoopTimerRef); - m_runLoopTimerRef = 0; -} - -void QIOSEventDispatcher::processPostedEvents() -{ - QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents); -} - -QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent) - : QAbstractEventDispatcher(parent) - , m_interrupted(false) - , m_runLoopTimerRef(0) -{ - m_cfSocketNotifier.setHostEventDispatcher(this); - - CFRunLoopRef mainRunLoop = CFRunLoopGetMain(); - CFRunLoopSourceContext context; - bzero(&context, sizeof(CFRunLoopSourceContext)); - context.equal = runLoopSourceEqualCallback; - context.info = this; - - // source used to handle timers: - context.perform = QIOSEventDispatcher::blockingTimerRunLoopCallback; - m_blockingTimerRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); - Q_ASSERT(m_blockingTimerRunLoopSource); - CFRunLoopAddSource(mainRunLoop, m_blockingTimerRunLoopSource, kCFRunLoopCommonModes); - - // source used to handle posted events: - context.perform = QIOSEventDispatcher::postedEventsRunLoopCallback; - m_postedEventsRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); - Q_ASSERT(m_postedEventsRunLoopSource); - CFRunLoopAddSource(mainRunLoop, m_postedEventsRunLoopSource, kCFRunLoopCommonModes); -} - -QIOSEventDispatcher::~QIOSEventDispatcher() -{ - CFRunLoopRef mainRunLoop = CFRunLoopGetMain(); - CFRunLoopRemoveSource(mainRunLoop, m_postedEventsRunLoopSource, kCFRunLoopCommonModes); - CFRelease(m_postedEventsRunLoopSource); - - qDeleteAll(m_timerInfoList); - maybeStopCFRunLoopTimer(); - CFRunLoopRemoveSource(CFRunLoopGetMain(), m_blockingTimerRunLoopSource, kCFRunLoopCommonModes); - CFRelease(m_blockingTimerRunLoopSource); - - m_cfSocketNotifier.removeSocketNotifiers(); -} - -bool QIOSEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) -{ - m_interrupted = false; - bool eventsProcessed = false; - - bool excludeUserEvents = flags & QEventLoop::ExcludeUserInputEvents; - bool execFlagSet = (flags & QEventLoop::DialogExec) || (flags & QEventLoop::EventLoopExec); - bool useExecMode = execFlagSet && !excludeUserEvents; - - if (useExecMode) { - NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; - while ([runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] && !m_interrupted); - eventsProcessed = true; - } else { - if (!(flags & QEventLoop::WaitForMoreEvents)) - wakeUp(); - eventsProcessed = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; - } - return eventsProcessed; -} - -bool QIOSEventDispatcher::hasPendingEvents() -{ - qDebug() << __FUNCTION__ << "not implemented"; - return false; -} - -void QIOSEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier) -{ - m_cfSocketNotifier.registerSocketNotifier(notifier); -} - -void QIOSEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier) -{ - m_cfSocketNotifier.unregisterSocketNotifier(notifier); -} - -void QIOSEventDispatcher::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *obj) -{ -#ifndef QT_NO_DEBUG - if (timerId < 1 || interval < 0 || !obj) { - qWarning("QIOSEventDispatcher::registerTimer: invalid arguments"); - return; - } else if (obj->thread() != thread() || thread() != QThread::currentThread()) { - qWarning("QIOSEventDispatcher: timers cannot be started from another thread"); - return; - } -#endif - - m_timerInfoList.registerTimer(timerId, interval, timerType, obj); - maybeStartCFRunLoopTimer(); -} - -bool QIOSEventDispatcher::unregisterTimer(int timerId) -{ -#ifndef QT_NO_DEBUG - if (timerId < 1) { - qWarning("QIOSEventDispatcher::unregisterTimer: invalid argument"); - return false; - } else if (thread() != QThread::currentThread()) { - qWarning("QObject::killTimer: timers cannot be stopped from another thread"); - return false; - } -#endif - - bool returnValue = m_timerInfoList.unregisterTimer(timerId); - m_timerInfoList.isEmpty() ? maybeStopCFRunLoopTimer() : maybeStartCFRunLoopTimer(); - return returnValue; -} - -bool QIOSEventDispatcher::unregisterTimers(QObject *object) -{ -#ifndef QT_NO_DEBUG - if (!object) { - qWarning("QIOSEventDispatcher::unregisterTimers: invalid argument"); - return false; - } else if (object->thread() != thread() || thread() != QThread::currentThread()) { - qWarning("QObject::killTimers: timers cannot be stopped from another thread"); - return false; - } -#endif - - bool returnValue = m_timerInfoList.unregisterTimers(object); - m_timerInfoList.isEmpty() ? maybeStopCFRunLoopTimer() : maybeStartCFRunLoopTimer(); - return returnValue; -} - -QList<QAbstractEventDispatcher::TimerInfo> QIOSEventDispatcher::registeredTimers(QObject *object) const -{ -#ifndef QT_NO_DEBUG - if (!object) { - qWarning("QIOSEventDispatcher:registeredTimers: invalid argument"); - return QList<TimerInfo>(); - } -#endif - - return m_timerInfoList.registeredTimers(object); -} - -int QIOSEventDispatcher::remainingTime(int timerId) -{ -#ifndef QT_NO_DEBUG - if (timerId < 1) { - qWarning("QIOSEventDispatcher::remainingTime: invalid argument"); - return -1; - } -#endif - - return m_timerInfoList.timerRemainingTime(timerId); -} - -void QIOSEventDispatcher::wakeUp() -{ - CFRunLoopSourceSignal(m_postedEventsRunLoopSource); - CFRunLoopWakeUp(CFRunLoopGetMain()); -} - -void QIOSEventDispatcher::interrupt() -{ - wakeUp(); - m_interrupted = true; -} - -void QIOSEventDispatcher::flush() -{ - // X11 only. -} - -QT_END_NAMESPACE - diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h index 176ad05733..78c1b260e6 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.h +++ b/src/plugins/platforms/ios/qiosinputcontext.h @@ -66,6 +66,7 @@ public: private: QIOSKeyboardListener *m_keyboardListener; UIView *m_focusView; + bool m_hasPendingHideRequest; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 1d3ab12de9..d430589037 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -99,6 +99,7 @@ QIOSInputContext::QIOSInputContext() : QPlatformInputContext() , m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this]) , m_focusView(0) + , m_hasPendingHideRequest(false) { } @@ -120,12 +121,20 @@ void QIOSInputContext::showInputPanel() // responder. Rather than searching for it from the top, we let the active QIOSWindow tell us which view to use. // Note that Qt will forward keyevents to whichever QObject that needs it, regardless of which UIView the input // actually came from. So in this respect, we're undermining iOS' responder chain. + m_hasPendingHideRequest = false; [m_focusView becomeFirstResponder]; } void QIOSInputContext::hideInputPanel() { - [m_focusView resignFirstResponder]; + // Delay hiding the keyboard for cases where the user is transferring focus between + // 'line edits'. In that case the 'line edit' that lost focus will close the input + // panel, just to see that the new 'line edit' will open it again: + m_hasPendingHideRequest = true; + dispatch_async(dispatch_get_main_queue(), ^{ + if (m_hasPendingHideRequest) + [m_focusView resignFirstResponder]; + }); } bool QIOSInputContext::isInputPanelVisible() const diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h index c352e0f2d2..4aaf98f839 100644 --- a/src/plugins/platforms/ios/qiosintegration.h +++ b/src/plugins/platforms/ios/qiosintegration.h @@ -46,6 +46,8 @@ #include <qpa/qplatformnativeinterface.h> #include <qpa/qwindowsysteminterface.h> +#include "qiosapplicationstate.h" + QT_BEGIN_NAMESPACE class QIOSIntegration : public QPlatformIntegration, public QPlatformNativeInterface @@ -79,6 +81,7 @@ private: QPlatformInputContext *m_inputContext; QPlatformScreen *m_screen; QTouchDevice *m_touchDevice; + QIOSApplicationState m_applicationState; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index 61fd1c3d60..7fd6015a2f 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -43,12 +43,13 @@ #include "qioswindow.h" #include "qiosbackingstore.h" #include "qiosscreen.h" -#include "qioseventdispatcher.h" #include "qioscontext.h" #include "qiosinputcontext.h" #include "qiostheme.h" +#include <QtPlatformSupport/private/qeventdispatcher_cf_p.h> #include <QtPlatformSupport/private/qcoretextfontdatabase_p.h> +#include <QDir> #include <QtDebug> @@ -71,6 +72,9 @@ QIOSIntegration::QIOSIntegration() exit(-1); } + // Set current directory to app bundle folder + QDir::setCurrent(QString::fromUtf8([[[NSBundle mainBundle] bundlePath] UTF8String])); + screenAdded(m_screen); m_touchDevice = new QTouchDevice; @@ -86,6 +90,8 @@ bool QIOSIntegration::hasCapability(Capability cap) const return true; case MultipleWindows: return true; + case ApplicationState: + return true; default: return QPlatformIntegration::hasCapability(cap); } @@ -111,7 +117,7 @@ QPlatformOpenGLContext *QIOSIntegration::createPlatformOpenGLContext(QOpenGLCont QAbstractEventDispatcher *QIOSIntegration::guiThreadEventDispatcher() const { - return new QIOSEventDispatcher(); + return new QEventDispatcherCoreFoundation; } QPlatformFontDatabase * QIOSIntegration::fontDatabase() const @@ -129,6 +135,8 @@ QVariant QIOSIntegration::styleHint(StyleHint hint) const switch (hint) { case ShowIsFullScreen: return true; + case SetFocusOnTouchRelease: + return true; default: return QPlatformIntegration::styleHint(hint); } diff --git a/src/plugins/platforminputcontexts/maliit/serverproxy.cpp b/src/plugins/platforms/ios/qiosmain_dummy.mm index fe104c23f9..28d7e59381 100644 --- a/src/plugins/platforminputcontexts/maliit/serverproxy.cpp +++ b/src/plugins/platforms/ios/qiosmain_dummy.mm @@ -39,18 +39,18 @@ ** ****************************************************************************/ -#include "serverproxy.h" +#include <QtCore/qglobal.h> /* - * Implementation of interface class ComMeegoInputmethodUiserver1Interface - */ + This file provides a dummy implementation of qt_user_main, so that + we don't get an undefined symbol in the hybrid use-case, where we + don't rename main() to qt_user_main(). As long as the linker is not + passed -all_load, this translation unit is only picked up and used + if qt_user_main is not defined by the user's code. +*/ -ComMeegoInputmethodUiserver1Interface::ComMeegoInputmethodUiserver1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) - : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +int qt_user_main(int, char **) { + qFatal("Hit dummy qt_user_main, this should never happen!"); + return 0; } - -ComMeegoInputmethodUiserver1Interface::~ComMeegoInputmethodUiserver1Interface() -{ -} - diff --git a/src/plugins/platforms/kms/qkmsudevdrmhandler.cpp b/src/plugins/platforms/ios/qiosmain_wrapper.mm index 68a4aaacdb..d9b8c7311e 100644 --- a/src/plugins/platforms/kms/qkmsudevdrmhandler.cpp +++ b/src/plugins/platforms/ios/qiosmain_wrapper.mm @@ -39,28 +39,22 @@ ** ****************************************************************************/ -#include <QtCore/QRegExp> +#include "qiosapplicationdelegate.h" -#include <qkmsintegration.h> -#include <qkmsudevdrmhandler.h> +/* + This file provides a wrapper implementation of main() for the non- + hybrid use-case. The user's main is renamed to qt_user_main by the + build rules, and we'll call out to that main at the appropriate time. -QT_BEGIN_NAMESPACE + This file purposly only exports a single symbol, _main, so that + when the linker considers the translation unit for inclusion it + will discard it when main has already been defined in the user's + application for the hybrid use-case. +*/ -QKmsUdevDRMHandler::QKmsUdevDRMHandler(QKmsIntegration *integration) - : m_integration(integration) +int main(int argc, char *argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSApplicationDelegate class])); + } } - -QObject *QKmsUdevDRMHandler::create(struct udev_device *device) -{ - if (strcmp(udev_device_get_subsystem(device), "drm")) - return 0; - - QRegExp regexp("^card\\d+$"); - if (!regexp.exactMatch(udev_device_get_sysname(device))) - return 0; - - return m_integration->createDevice(udev_device_get_devnode(device)); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 0c3ae8e834..c8d0f823f6 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -183,12 +183,6 @@ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - QWindow *window = m_qioswindow->window(); - - // Transfer focus to the touched window: - if (window != QGuiApplication::focusWindow()) - m_qioswindow->requestActivateWindow(); - // UIKit generates [Began -> Moved -> Ended] event sequences for // each touch point. Internally we keep a hashmap of active UITouch // points to QWindowSystemInterface::TouchPoints, and assigns each TouchPoint @@ -210,6 +204,14 @@ - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + QWindow *window = m_qioswindow->window(); + if (window != QGuiApplication::focusWindow() && m_activeTouches.size() == 1) { + // Activate the touched window if the last touch was released inside it: + UITouch *touch = static_cast<UITouch *>([[touches allObjects] lastObject]); + if (CGRectContainsPoint([self bounds], [touch locationInView:self])) + m_qioswindow->requestActivateWindow(); + } + [self updateTouchList:touches withState:Qt::TouchPointReleased]; [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)]; @@ -247,6 +249,23 @@ return YES; } +- (BOOL)becomeFirstResponder +{ + // On iOS, a QWindow should only have input focus when the input panel is + // open. This is to stop cursors and focus rects from being drawn when the + // user cannot type. And since the keyboard will open when a view becomes + // the first responder, it's now a good time to inform QPA that the QWindow + // this view backs became active: + QWindowSystemInterface::handleWindowActivated(m_qioswindow->window()); + return [super becomeFirstResponder]; +} + +- (BOOL)resignFirstResponder +{ + QWindowSystemInterface::handleWindowActivated(0); + return [super resignFirstResponder]; +} + - (BOOL)hasText { return YES; @@ -416,7 +435,6 @@ void QIOSWindow::requestActivateWindow() raise(); QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); static_cast<QIOSInputContext *>(context)->focusViewChanged(m_view); - QPlatformWindow::requestActivateWindow(); } void QIOSWindow::raiseOrLower(bool raise) diff --git a/src/plugins/platforms/ios/qtmain.mm b/src/plugins/platforms/ios/qtmain.mm deleted file mode 100644 index 19c98f2c59..0000000000 --- a/src/plugins/platforms/ios/qtmain.mm +++ /dev/null @@ -1,94 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, 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. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qiosapplicationdelegate.h" -#include "qiosviewcontroller.h" - -int main(int argc, char *argv[]) -{ - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSMainWrapperApplicationDelegate class])); - } -} - -extern int qt_main(int argc, char *argv[]); - -@implementation QIOSMainWrapperApplicationDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; - self.qiosViewController = [[[QIOSViewController alloc] init] autorelease]; - self.window.rootViewController = self.qiosViewController; - -#ifdef QT_DEBUG - self.window.backgroundColor = [UIColor cyanColor]; -#endif - - [self.window makeKeyAndVisible]; - - // We schedule the main-redirection for the next eventloop pass so that we - // can return from this function and let UIApplicationMain finish its job. - [NSTimer scheduledTimerWithTimeInterval:.01f target:self - selector:@selector(runUserMain) userInfo:nil repeats:NO]; - - if ([QIOSApplicationDelegate instancesRespondToSelector:_cmd]) - return [super application:application didFinishLaunchingWithOptions:launchOptions]; - else - return YES; -} - -- (void)runUserMain -{ - NSArray *arguments = [[NSProcessInfo processInfo] arguments]; - int argc = arguments.count; - char **argv = new char*[argc]; - for (int i = 0; i < argc; ++i) { - NSString *arg = [arguments objectAtIndex:i]; - argv[i] = reinterpret_cast<char *>(malloc([arg lengthOfBytesUsingEncoding:[NSString defaultCStringEncoding]])); - strcpy(argv[i], [arg cStringUsingEncoding:[NSString defaultCStringEncoding]]); - } - - qt_main(argc, argv); - delete[] argv; -} - -@end diff --git a/src/plugins/platforms/ios/qtmain.pro b/src/plugins/platforms/ios/qtmain.pro deleted file mode 100644 index cbcb272217..0000000000 --- a/src/plugins/platforms/ios/qtmain.pro +++ /dev/null @@ -1,8 +0,0 @@ -TARGET = qiosmain - -PLUGIN_TYPE = platforms -load(qt_plugin) - -QT += gui-private - -OBJECTIVE_SOURCES = qtmain.mm diff --git a/src/plugins/platforms/kms/kms.pro b/src/plugins/platforms/kms/kms.pro index 711cf9e5c7..612a878736 100644 --- a/src/plugins/platforms/kms/kms.pro +++ b/src/plugins/platforms/kms/kms.pro @@ -22,9 +22,6 @@ SOURCES = main.cpp \ qkmsdevice.cpp \ qkmsbackingstore.cpp \ qkmsnativeinterface.cpp \ - qkmsudevlistener.cpp \ - qkmsudevhandler.cpp \ - qkmsudevdrmhandler.cpp \ qkmsvthandler.cpp HEADERS = qkmsintegration.h \ qkmsscreen.h \ @@ -34,9 +31,6 @@ HEADERS = qkmsintegration.h \ qkmsdevice.h \ qkmsbackingstore.h \ qkmsnativeinterface.h \ - qkmsudevlistener.h \ - qkmsudevhandler.h \ - qkmsudevdrmhandler.h \ qkmsvthandler.h OTHER_FILES += \ diff --git a/src/plugins/platforms/kms/main.cpp b/src/plugins/platforms/kms/main.cpp index 75f7ef5278..db0582e694 100644 --- a/src/plugins/platforms/kms/main.cpp +++ b/src/plugins/platforms/kms/main.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class QKmsIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "kms.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "kms.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/kms/qkmsintegration.cpp b/src/plugins/platforms/kms/qkmsintegration.cpp index 8210b54535..539363722d 100644 --- a/src/plugins/platforms/kms/qkmsintegration.cpp +++ b/src/plugins/platforms/kms/qkmsintegration.cpp @@ -46,10 +46,14 @@ #include "qkmsbackingstore.h" #include "qkmscontext.h" #include "qkmsnativeinterface.h" -#include "qkmsudevlistener.h" -#include "qkmsudevdrmhandler.h" #include "qkmsvthandler.h" +#if !defined(QT_NO_EVDEV) +#include <QtPlatformSupport/private/qevdevmousemanager_p.h> +#include <QtPlatformSupport/private/qevdevkeyboardmanager_p.h> +#include <QtPlatformSupport/private/qevdevtouch_p.h> +#endif + #include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> #include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> #include <QtGui/private/qguiapplication_p.h> @@ -62,18 +66,32 @@ QKmsIntegration::QKmsIntegration() : QPlatformIntegration(), m_fontDatabase(new QGenericUnixFontDatabase()), m_eventDispatcher(createUnixEventDispatcher()), - m_nativeInterface(new QKmsNativeInterface), - m_udevListener(new QKmsUdevListener) + m_nativeInterface(new QKmsNativeInterface) { QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher); setenv("EGL_PLATFORM", "drm",1); m_vtHandler = new QKmsVTHandler; - m_drmHandler = new QKmsUdevDRMHandler(this); - m_udevListener->addHandler(m_drmHandler); + + m_deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_DRM | QDeviceDiscovery::Device_DRM_PrimaryGPU, 0); + if (m_deviceDiscovery) { + QStringList devices = m_deviceDiscovery->scanConnectedDevices(); + foreach (QString device, devices) + addDevice(device); + + connect(m_deviceDiscovery, SIGNAL(deviceDetected(QString)), this, SLOT(addDevice(QString))); + connect(m_deviceDiscovery, SIGNAL(deviceRemoved(QString)), this, SLOT(removeDevice(QString))); + } + +#if !defined(QT_NO_EVDEV) + new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString() /* spec */, this); + new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString() /* spec */, this); + new QEvdevTouchScreenHandlerThread(QString() /* spec */, this); +#endif } QKmsIntegration::~QKmsIntegration() { + delete m_deviceDiscovery; foreach (QKmsDevice *device, m_devices) { delete device; } @@ -81,15 +99,18 @@ QKmsIntegration::~QKmsIntegration() delete screen; } delete m_fontDatabase; - delete m_udevListener; delete m_vtHandler; } -QObject *QKmsIntegration::createDevice(const char *path) +void QKmsIntegration::addDevice(const QString &deviceNode) +{ + m_devices.append(new QKmsDevice(deviceNode, this)); +} + +void QKmsIntegration::removeDevice(const QString &deviceNode) { - QKmsDevice *device = new QKmsDevice(path, this); - m_devices.append(device); - return device; + // TODO: support hot-plugging some day? + Q_UNUSED(deviceNode); } bool QKmsIntegration::hasCapability(QPlatformIntegration::Capability cap) const diff --git a/src/plugins/platforms/kms/qkmsintegration.h b/src/plugins/platforms/kms/qkmsintegration.h index c08396ba3f..5069753aa5 100644 --- a/src/plugins/platforms/kms/qkmsintegration.h +++ b/src/plugins/platforms/kms/qkmsintegration.h @@ -44,17 +44,18 @@ #include <qpa/qplatformintegration.h> #include <qpa/qplatformnativeinterface.h> +#include <QtPlatformSupport/private/qdevicediscovery_p.h> QT_BEGIN_NAMESPACE class QKmsScreen; class QKmsDevice; -class QKmsUdevListener; -class QKmsUdevDRMHandler; class QKmsVTHandler; -class QKmsIntegration : public QPlatformIntegration +class QKmsIntegration : public QObject, public QPlatformIntegration { + Q_OBJECT + public: QKmsIntegration(); ~QKmsIntegration(); @@ -73,6 +74,10 @@ public: void addScreen(QKmsScreen *screen); QObject *createDevice(const char *); +private slots: + void addDevice(const QString &deviceNode); + void removeDevice(const QString &deviceNode); + private: QStringList findDrmDevices(); @@ -81,9 +86,8 @@ private: QPlatformFontDatabase *m_fontDatabase; QAbstractEventDispatcher *m_eventDispatcher; QPlatformNativeInterface *m_nativeInterface; - QKmsUdevListener *m_udevListener; - QKmsUdevDRMHandler *m_drmHandler; QKmsVTHandler *m_vtHandler; + QDeviceDiscovery *m_deviceDiscovery; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsudevlistener.cpp b/src/plugins/platforms/kms/qkmsudevlistener.cpp deleted file mode 100644 index b2fb110479..0000000000 --- a/src/plugins/platforms/kms/qkmsudevlistener.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, 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. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qkmsudevlistener.h> - -QT_BEGIN_NAMESPACE - -QKmsUdevListener::QKmsUdevListener(QObject *parent) - : QObject(parent) -{ - m_udev = udev_new(); -} - -QKmsUdevListener::~QKmsUdevListener() -{ - udev_unref(m_udev); -} - -void QKmsUdevListener::addHandler(QKmsUdevHandler *handler) -{ - m_handlers.removeAll((QKmsUdevHandler *) 0); - m_handlers.removeAll(handler); - m_handlers.prepend(handler); - - scan(); -} - -bool QKmsUdevListener::create(struct udev_device *device) -{ - foreach (QKmsUdevHandler *handler, m_handlers) { - if (!handler) - continue; - - QObject *obj = handler->create(device); - if (obj) { - m_devices[udev_device_get_syspath(device)] = obj; - return true; - } - } - - return false; -} - -void QKmsUdevListener::scan() -{ - struct udev_enumerate *e; - struct udev_list_entry *entry; - - e = udev_enumerate_new(m_udev); - udev_enumerate_scan_devices(e); - udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { - const char *path = udev_list_entry_get_name(entry); - if (m_devices.contains(path)) - continue; - - struct udev_device *device = udev_device_new_from_syspath(m_udev, path); - create(device); - udev_device_unref(device); - } - udev_enumerate_unref(e); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/linuxfb/main.cpp b/src/plugins/platforms/linuxfb/main.cpp index a1037c4feb..579984d2fc 100644 --- a/src/plugins/platforms/linuxfb/main.cpp +++ b/src/plugins/platforms/linuxfb/main.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class QLinuxFbIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "linuxfb.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "linuxfb.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/minimal/main.cpp b/src/plugins/platforms/minimal/main.cpp index 811f1fe5ee..7846b5b387 100644 --- a/src/plugins/platforms/minimal/main.cpp +++ b/src/plugins/platforms/minimal/main.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE class QMinimalIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "minimal.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "minimal.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/minimalegl/main.cpp b/src/plugins/platforms/minimalegl/main.cpp index 414f45c745..c951bfb0dc 100644 --- a/src/plugins/platforms/minimalegl/main.cpp +++ b/src/plugins/platforms/minimalegl/main.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class QMinimalEglIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "minimalegl.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "minimalegl.json") public: QStringList keys() const; QPlatformIntegration *create(const QString&, const QStringList&); diff --git a/src/plugins/platforms/offscreen/main.cpp b/src/plugins/platforms/offscreen/main.cpp index ca7dc1d18b..f48451d00d 100644 --- a/src/plugins/platforms/offscreen/main.cpp +++ b/src/plugins/platforms/offscreen/main.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE class QOffscreenIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "offscreen.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "offscreen.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro index 9f10eaad94..5db5e32e65 100644 --- a/src/plugins/platforms/offscreen/offscreen.pro +++ b/src/plugins/platforms/offscreen/offscreen.pro @@ -1,6 +1,7 @@ TARGET = qoffscreen PLUGIN_TYPE = platforms +PLUGIN_CLASS_NAME = QOffscreenIntegrationPlugin load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/openwfd/main.cpp b/src/plugins/platforms/openwfd/main.cpp index 724c5cfa4b..cea3c50e56 100644 --- a/src/plugins/platforms/openwfd/main.cpp +++ b/src/plugins/platforms/openwfd/main.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE class QOpenWFDIntegrationPlugin : public QPlatformIntegrationPlugin { - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/qnx/main.cpp b/src/plugins/platforms/qnx/main.cpp index ea50b12cb3..fb81928625 100644 --- a/src/plugins/platforms/qnx/main.cpp +++ b/src/plugins/platforms/qnx/main.cpp @@ -46,9 +46,8 @@ QT_BEGIN_NAMESPACE QPlatformIntegration *QQnxIntegrationPlugin::create(const QString& system, const QStringList& paramList) { - Q_UNUSED(paramList); if (system.toLower() == QLatin1String("qnx")) - return new QQnxIntegration; + return new QQnxIntegration(paramList); return 0; } diff --git a/src/plugins/platforms/qnx/main.h b/src/plugins/platforms/qnx/main.h index 0b5f6323c4..683b20efd2 100644 --- a/src/plugins/platforms/qnx/main.h +++ b/src/plugins/platforms/qnx/main.h @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE class QQnxIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "qnx.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "qnx.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro index 398b64640e..7c497b4434 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -11,11 +11,11 @@ QT += platformsupport-private core-private gui-private CONFIG(blackberry) { CONFIG += qqnx_pps - # Unomment this to enable screen event handling - # through a dedicated thread. - # DEFINES += QQNX_SCREENEVENTTHREAD + # Uncomment following line to enable screen event + # handling through a dedicated thread. + # CONFIG += qqnx_screeneventthread } else { - DEFINES += QQNX_SCREENEVENTTHREAD + CONFIG += qqnx_screeneventthread } # Uncomment these to enable debugging output for various aspects of the plugin @@ -40,11 +40,11 @@ CONFIG(blackberry) { #DEFINES += QQNXVIRTUALKEYBOARD_DEBUG #DEFINES += QQNXWINDOW_DEBUG #DEFINES += QQNXCURSOR_DEBUG +#DEFINES += QQNXFILEPICKER_DEBUG SOURCES = main.cpp \ qqnxbuffer.cpp \ - qqnxscreeneventthread.cpp \ qqnxintegration.cpp \ qqnxscreen.cpp \ qqnxwindow.cpp \ @@ -60,7 +60,6 @@ SOURCES = main.cpp \ HEADERS = main.h \ qqnxbuffer.h \ - qqnxscreeneventthread.h \ qqnxkeytranslator.h \ qqnxintegration.h \ qqnxscreen.h \ @@ -75,6 +74,12 @@ HEADERS = main.h \ qqnxservices.h \ qqnxcursor.h +CONFIG(qqnx_screeneventthread) { + DEFINES += QQNX_SCREENEVENTTHREAD + SOURCES += qqnxscreeneventthread.cpp + HEADERS += qqnxscreeneventthread.h +} + LIBS += -lscreen contains(QT_CONFIG, opengles2) { @@ -91,8 +96,7 @@ CONFIG(blackberry) { qqnxbpseventfilter.cpp \ qqnxvirtualkeyboardbps.cpp \ qqnxtheme.cpp \ - qqnxsystemsettings.cpp \ - qqnxfiledialoghelper.cpp + qqnxsystemsettings.cpp HEADERS += qqnxnavigatorbps.h \ qqnxeventdispatcher_blackberry.h \ @@ -105,6 +109,17 @@ CONFIG(blackberry) { LIBS += -lbps } +CONFIG(blackberry-playbook) { + SOURCES += qqnxfiledialoghelper_playbook.cpp +} else { + CONFIG(blackberry) { + SOURCES += qqnxfiledialoghelper_bb10.cpp \ + qqnxfilepicker.cpp + + HEADERS += qqnxfilepicker.h + } +} + CONFIG(qqnx_pps) { DEFINES += QQNX_PPS diff --git a/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp b/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp index e723e32301..4c36a97ab6 100644 --- a/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp +++ b/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp @@ -41,11 +41,12 @@ #include "qqnxbpseventfilter.h" #include "qqnxnavigatoreventhandler.h" -#include "qqnxfiledialoghelper.h" #include "qqnxscreen.h" #include "qqnxscreeneventhandler.h" #include "qqnxvirtualkeyboardbps.h" +#include "qqnxfiledialoghelper.h" +#include <QCoreApplication> #include <QAbstractEventDispatcher> #include <QDebug> @@ -126,6 +127,7 @@ void QQnxBpsEventFilter::unregisterForScreenEvents(QQnxScreen *screen) qWarning("QQNX: failed to unregister for screen events on screen %p", screen->nativeContext()); } +#if defined(Q_OS_BLACKBERRY_TABLET) void QQnxBpsEventFilter::registerForDialogEvents(QQnxFileDialogHelper *dialog) { if (dialog_request_events(0) != BPS_SUCCESS) @@ -141,6 +143,7 @@ void QQnxBpsEventFilter::unregisterForDialogEvents(QQnxFileDialogHelper *dialog) if (count == 0) qWarning("QQNX: attempting to unregister dialog that was not registered"); } +#endif // Q_OS_BLACKBERRY_TABLET bool QQnxBpsEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result) { @@ -160,12 +163,14 @@ bool QQnxBpsEventFilter::nativeEventFilter(const QByteArray &eventType, void *me return m_screenEventHandler->handleEvent(screenEvent); } +#if defined(Q_OS_BLACKBERRY_TABLET) if (eventDomain == dialog_get_domain()) { dialog_instance_t nativeDialog = dialog_event_get_dialog_instance(event); QQnxFileDialogHelper *dialog = m_dialogMapper.value(nativeDialog, 0); if (dialog) return dialog->handleEvent(event); } +#endif if (eventDomain == navigator_get_domain()) return handleNavigatorEvent(event); @@ -249,6 +254,11 @@ bool QQnxBpsEventFilter::handleNavigatorEvent(bps_event_t *event) break; } + case NAVIGATOR_LOW_MEMORY: + qWarning() << "QGuiApplication based process" << QCoreApplication::applicationPid() + << "received \"NAVIGATOR_LOW_MEMORY\" event"; + return false; + default: qBpsEventFilterDebug() << Q_FUNC_INFO << "Unhandled navigator event. code=" << bps_event_get_code(event); return false; diff --git a/src/plugins/platforms/qnx/qqnxbpseventfilter.h b/src/plugins/platforms/qnx/qqnxbpseventfilter.h index e897863efb..f8e36823d5 100644 --- a/src/plugins/platforms/qnx/qqnxbpseventfilter.h +++ b/src/plugins/platforms/qnx/qqnxbpseventfilter.h @@ -73,8 +73,10 @@ public: void registerForScreenEvents(QQnxScreen *screen); void unregisterForScreenEvents(QQnxScreen *screen); +#ifdef Q_OS_BLACKBERRY_TABLET void registerForDialogEvents(QQnxFileDialogHelper *dialog); void unregisterForDialogEvents(QQnxFileDialogHelper *dialog); +#endif private: bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/qnx/qqnxfiledialoghelper.h b/src/plugins/platforms/qnx/qqnxfiledialoghelper.h index e17ea80501..e7c68f6ff5 100644 --- a/src/plugins/platforms/qnx/qqnxfiledialoghelper.h +++ b/src/plugins/platforms/qnx/qqnxfiledialoghelper.h @@ -44,12 +44,19 @@ #include <qpa/qplatformdialoghelper.h> -#include <bps/dialog.h> QT_BEGIN_NAMESPACE class QQnxIntegration; +#if defined(Q_OS_BLACKBERRY_TABLET) +#include <bps/dialog.h> +#define NativeDialogPtr dialog_instance_t +#else +class QQnxFilePicker; +#define NativeDialogPtr QQnxFilePicker * +#endif + class QQnxFileDialogHelper : public QPlatformFileDialogHelper { Q_OBJECT @@ -57,7 +64,9 @@ public: explicit QQnxFileDialogHelper(const QQnxIntegration *); ~QQnxFileDialogHelper(); +#if defined(Q_OS_BLACKBERRY_TABLET) bool handleEvent(bps_event_t *event); +#endif void exec(); @@ -65,29 +74,32 @@ public: void hide(); bool defaultNameFilterDisables() const; - void setDirectory(const QString &directory); - QString directory() const; - void selectFile(const QString &fileName); - QStringList selectedFiles() const; + void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + QUrl directory() const Q_DECL_OVERRIDE; + void selectFile(const QUrl &fileName) Q_DECL_OVERRIDE; + QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; void setFilter(); void selectNameFilter(const QString &filter); QString selectedNameFilter() const; - dialog_instance_t nativeDialog() const { return m_dialog; } + NativeDialogPtr nativeDialog() const { return m_dialog; } Q_SIGNALS: void dialogClosed(); private: void setNameFilter(const QString &filter); + void setNameFilters(const QStringList &filters); const QQnxIntegration *m_integration; - dialog_instance_t m_dialog; + NativeDialogPtr m_dialog; QFileDialogOptions::AcceptMode m_acceptMode; QString m_selectedFilter; QPlatformDialogHelper::DialogCode m_result; - QStringList m_paths; +#if defined(Q_OS_BLACKBERRY_TABLET) + QList<QUrl> m_paths; +#endif }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxfiledialoghelper_bb10.cpp b/src/plugins/platforms/qnx/qqnxfiledialoghelper_bb10.cpp new file mode 100644 index 0000000000..dc841eb1a9 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxfiledialoghelper_bb10.cpp @@ -0,0 +1,217 @@ +/*************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqnxfiledialoghelper.h" + +#include "qqnxfilepicker.h" +#include "qqnxbpseventfilter.h" +#include "qqnxscreen.h" +#include "qqnxintegration.h" + +#include <QDebug> +#include <QEventLoop> +#include <QScreen> +#include <QTimer> +#include <QWindow> + +#ifdef QQNXFILEDIALOGHELPER_DEBUG +#define qFileDialogHelperDebug qDebug +#else +#define qFileDialogHelperDebug QT_NO_QDEBUG_MACRO +#endif + +QT_BEGIN_NAMESPACE + +QQnxFileDialogHelper::QQnxFileDialogHelper(const QQnxIntegration *integration) + : QPlatformFileDialogHelper(), + m_integration(integration), + m_dialog(new QQnxFilePicker), + m_acceptMode(QFileDialogOptions::AcceptOpen), + m_selectedFilter(), + m_result(QPlatformDialogHelper::Rejected) +{ +} + +QQnxFileDialogHelper::~QQnxFileDialogHelper() +{ + delete m_dialog; +} + +void QQnxFileDialogHelper::exec() +{ + qFileDialogHelperDebug() << Q_FUNC_INFO; + + // Clear any previous results + m_dialog->setDirectories(QStringList()); + + QEventLoop loop; + connect(m_dialog, SIGNAL(closed()), &loop, SLOT(quit())); + loop.exec(); + + if (m_dialog->selectedFiles().isEmpty()) + Q_EMIT reject(); + else + Q_EMIT accept(); +} + +bool QQnxFileDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) +{ + Q_UNUSED(flags); + Q_UNUSED(parent); + Q_UNUSED(modality); + + qFileDialogHelperDebug() << Q_FUNC_INFO; + + // Create dialog + const QSharedPointer<QFileDialogOptions> &opts = options(); + if (opts->acceptMode() == QFileDialogOptions::AcceptOpen) { + // Select one or many files? + const QQnxFilePicker::Mode mode = (opts->fileMode() == QFileDialogOptions::ExistingFiles) + ? QQnxFilePicker::PickerMultiple : QQnxFilePicker::Picker; + + m_dialog->setMode(mode); + + // Set the actual list of extensions + if (!opts->nameFilters().isEmpty()) + setNameFilters(opts->nameFilters()); + else + setNameFilter(tr("All files (*.*)")); + } else { + const QQnxFilePicker::Mode mode = (opts->initiallySelectedFiles().count() >= 2) + ? QQnxFilePicker::SaverMultiple : QQnxFilePicker::Saver; + + m_dialog->setMode(mode); + + if (!opts->initiallySelectedFiles().isEmpty()) { + QStringList files; + Q_FOREACH ( const QUrl &url, opts->initiallySelectedFiles() ) + files.append(url.toLocalFile()); + m_dialog->setDefaultSaveFileNames(files); + } + } + + // Cache the accept mode so we know which functions to use to get the results back + m_acceptMode = opts->acceptMode(); + m_dialog->setTitle(opts->windowTitle()); + m_dialog->open(); + + return true; +} + +void QQnxFileDialogHelper::hide() +{ + qFileDialogHelperDebug() << Q_FUNC_INFO; + m_dialog->close(); +} + +bool QQnxFileDialogHelper::defaultNameFilterDisables() const +{ + qFileDialogHelperDebug() << Q_FUNC_INFO; + return false; +} + +void QQnxFileDialogHelper::setDirectory(const QUrl &directory) +{ + m_dialog->addDirectory(directory.toLocalFile()); +} + +QUrl QQnxFileDialogHelper::directory() const +{ + qFileDialogHelperDebug() << Q_FUNC_INFO; + if (!m_dialog->directories().isEmpty()) + return QUrl::fromLocalFile(m_dialog->directories().first()); + + return QUrl(); +} + +void QQnxFileDialogHelper::selectFile(const QUrl &fileName) +{ + m_dialog->addDefaultSaveFileName(fileName.toLocalFile()); +} + +QList<QUrl> QQnxFileDialogHelper::selectedFiles() const +{ + qFileDialogHelperDebug() << Q_FUNC_INFO; + QList<QUrl> urls; + QStringList files = m_dialog->selectedFiles(); + Q_FOREACH (const QString &file, files) + urls.append(QUrl::fromLocalFile(file)); + return urls; +} + +void QQnxFileDialogHelper::setFilter() +{ + // No native api to support setting a filter from QDir::Filters + qFileDialogHelperDebug() << Q_FUNC_INFO; +} + +void QQnxFileDialogHelper::selectNameFilter(const QString &filter) +{ + qFileDialogHelperDebug() << Q_FUNC_INFO << "filter =" << filter; + setNameFilter(filter); +} + +QString QQnxFileDialogHelper::selectedNameFilter() const +{ + // For now there is no way for the user to change the selected filter + // so this just reflects what the developer has set programmatically. + qFileDialogHelperDebug() << Q_FUNC_INFO; + return m_selectedFilter; +} + +void QQnxFileDialogHelper::setNameFilter(const QString &filter) +{ + qFileDialogHelperDebug() << Q_FUNC_INFO << "filter =" << filter; + + setNameFilters(QPlatformFileDialogHelper::cleanFilterList(filter)); +} + +void QQnxFileDialogHelper::setNameFilters(const QStringList &filters) +{ + qFileDialogHelperDebug() << Q_FUNC_INFO << "filters =" << filters; + + Q_ASSERT(!filters.isEmpty()); + + m_dialog->setFilters(filters); + m_selectedFilter = filters.first(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxfiledialoghelper.cpp b/src/plugins/platforms/qnx/qqnxfiledialoghelper_playbook.cpp index 0325a33268..2a743d03f7 100644 --- a/src/plugins/platforms/qnx/qqnxfiledialoghelper.cpp +++ b/src/plugins/platforms/qnx/qqnxfiledialoghelper_playbook.cpp @@ -102,7 +102,7 @@ bool QQnxFileDialogHelper::handleEvent(bps_event_t *event) for (int i = 0; i < pathCount; ++i) { QString path = QFile::decodeName(filePaths[i]); - m_paths.append(path); + m_paths.append(QUrl::fromLocalFile(path)); qFileDialogHelperDebug() << "path =" << path; } @@ -112,13 +112,13 @@ bool QQnxFileDialogHelper::handleEvent(bps_event_t *event) const char *filePath = dialog_event_get_filesave_filepath(event); QString path = QFile::decodeName(filePath); qFileDialogHelperDebug() << "path =" << path; - m_paths.append(path); + m_paths.append(QUrl::fromLocalFile(path)); } } else { // Cancel m_result = QPlatformDialogHelper::Rejected; } - emit dialogClosed(); + Q_EMIT dialogClosed(); return true; } @@ -135,9 +135,9 @@ void QQnxFileDialogHelper::exec() loop.exec(); if (m_result == QPlatformDialogHelper::Accepted) - emit accept(); + Q_EMIT accept(); else - emit reject(); + Q_EMIT reject(); } bool QQnxFileDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) @@ -188,7 +188,7 @@ bool QQnxFileDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modali // Maybe pre-select a filename if (!opts->initiallySelectedFiles().isEmpty()) { - QString fileName = opts->initiallySelectedFiles().first(); + QString fileName = opts->initiallySelectedFiles().first().toLocalFile(); dialog_set_filesave_filename(m_dialog, QFile::encodeName(fileName).constData()); } @@ -240,29 +240,29 @@ bool QQnxFileDialogHelper::defaultNameFilterDisables() const return false; } -void QQnxFileDialogHelper::setDirectory(const QString &directory) +void QQnxFileDialogHelper::setDirectory(const QUrl &directory) { qFileDialogHelperDebug() << Q_FUNC_INFO << "directory =" << directory; // No native API for setting the directory(!). The best we can do is to // set it as the file name but even then only with a file save dialog. if (m_dialog && m_acceptMode == QFileDialogOptions::AcceptSave) - dialog_set_filesave_filename(m_dialog, QFile::encodeName(directory).constData()); + dialog_set_filesave_filename(m_dialog, QFile::encodeName(directory.toLocalFile()).constData()); } -QString QQnxFileDialogHelper::directory() const +QUrl QQnxFileDialogHelper::directory() const { qFileDialogHelperDebug() << Q_FUNC_INFO; return m_paths.first(); } -void QQnxFileDialogHelper::selectFile(const QString &fileName) +void QQnxFileDialogHelper::selectFile(const QUrl &fileName) { qFileDialogHelperDebug() << Q_FUNC_INFO << "filename =" << fileName; if (m_dialog && m_acceptMode == QFileDialogOptions::AcceptSave) - dialog_set_filesave_filename(m_dialog, QFile::encodeName(fileName).constData()); + dialog_set_filesave_filename(m_dialog, QFile::encodeName(fileName.toLocalFile()).constData()); } -QStringList QQnxFileDialogHelper::selectedFiles() const +QList<QUrl> QQnxFileDialogHelper::selectedFiles() const { qFileDialogHelperDebug() << Q_FUNC_INFO; return m_paths; @@ -291,9 +291,15 @@ QString QQnxFileDialogHelper::selectedNameFilter() const void QQnxFileDialogHelper::setNameFilter(const QString &filter) { qFileDialogHelperDebug() << Q_FUNC_INFO << "filter =" << filter; + setNameFilters(QPlatformFileDialogHelper::cleanFilterList(filter)); +} + +void QQnxFileDialogHelper::setNameFilters(const QStringList &filters) +{ + qFileDialogHelperDebug() << Q_FUNC_INFO << "filters =" << filters; + + Q_ASSERT(!filters.isEmpty()); - // Extract the globbing expressions - QStringList filters = QPlatformFileDialogHelper::cleanFilterList(filter); char **globs = new char*[filters.size()]; for (int i = 0; i < filters.size(); ++i) { QByteArray glob = filters.at(i).toLocal8Bit(); @@ -303,7 +309,7 @@ void QQnxFileDialogHelper::setNameFilter(const QString &filter) // Set the filters dialog_set_filebrowse_filter(m_dialog, const_cast<const char**>(globs), filters.size()); - m_selectedFilter = filter; + m_selectedFilter = filters.first(); // Cleanup for (int i = 0; i < filters.size(); ++i) diff --git a/src/plugins/platforms/qnx/qqnxfilepicker.cpp b/src/plugins/platforms/qnx/qqnxfilepicker.cpp new file mode 100644 index 0000000000..5229d1f1f5 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxfilepicker.cpp @@ -0,0 +1,289 @@ +/*************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqnxfilepicker.h" + +#include <QAbstractEventDispatcher> +#include <QCoreApplication> +#include <QDebug> +#include <QJsonDocument> +#include <QJsonObject> +#include <QJsonArray> +#include <QJsonParseError> +#include <QUrl> + +#include <bps/navigator.h> +#include <bps/navigator_invoke.h> + +#include <errno.h> + +#ifdef QQNXFILEPICKER_DEBUG +#define qFilePickerDebug qDebug +#else +#define qFilePickerDebug QT_NO_QDEBUG_MACRO +#endif + +static const char s_filePickerTarget[] = "sys.filepicker.target"; + +QQnxFilePicker::QQnxFilePicker(QObject *parent) + : QObject(parent) + , m_invocationHandle(0) + , m_mode(QQnxFilePicker::Picker) + , m_title(tr("Pick a file")) +{ + QCoreApplication::eventDispatcher()->installNativeEventFilter(this); +} + +QQnxFilePicker::~QQnxFilePicker() +{ + cleanup(); + + QCoreApplication::eventDispatcher()->removeNativeEventFilter(this); +} + +void QQnxFilePicker::open() +{ + if (m_invocationHandle) + return; + + int errorCode = BPS_SUCCESS; + + errorCode = navigator_invoke_invocation_create(&m_invocationHandle); + if (errorCode != BPS_SUCCESS) { + qWarning() << "QQnxFilePicker: unable to create invocation:" << strerror(errno); + return; + } + + errorCode = navigator_invoke_invocation_set_target(m_invocationHandle, s_filePickerTarget); + + if (errorCode != BPS_SUCCESS) { + cleanup(); + qWarning() << "QQnxFilePicker: unable to set target:" << strerror(errno); + return; + } + + errorCode = navigator_invoke_invocation_set_action(m_invocationHandle, "bb.action.OPEN"); + if (errorCode != BPS_SUCCESS) { + cleanup(); + qWarning() << "QQnxFilePicker: unable to set action:" << strerror(errno); + return; + } + + errorCode = navigator_invoke_invocation_set_type(m_invocationHandle, "application/vnd.blackberry.file_picker"); + if (errorCode != BPS_SUCCESS) { + cleanup(); + qWarning() << "QQnxFilePicker: unable to set mime type:" << strerror(errno); + return; + } + + QVariantMap map; + map[QStringLiteral("Type")] = QStringLiteral("Other"); + map[QStringLiteral("Mode")] = modeToString(m_mode); + map[QStringLiteral("Title")] = m_title; + map[QStringLiteral("ViewMode")] = QStringLiteral("Default"); + map[QStringLiteral("SortBy")] = QStringLiteral("Default"); + map[QStringLiteral("SortOrder")] = QStringLiteral("Default"); + map[QStringLiteral("ImageCrop")] = false; + map[QStringLiteral("AllowOverwrite")] = false; + + if (!m_defaultSaveFileNames.isEmpty()) + map[QStringLiteral("DefaultFileNames")] = m_defaultSaveFileNames.join(","); + if (!m_filters.isEmpty()) + map[QStringLiteral("Filter")] = m_filters.join(";"); + + QJsonDocument document; + document.setObject(QJsonObject::fromVariantMap(map)); + const QByteArray jsonData = document.toJson(QJsonDocument::Compact); + + errorCode = navigator_invoke_invocation_set_data(m_invocationHandle, jsonData.constData(), jsonData.size()); + if (errorCode != BPS_SUCCESS) { + cleanup(); + qWarning() << "QQnxFilePicker: unable to set data:" << strerror(errno); + return; + } + + navigator_invoke_invocation_send(m_invocationHandle); +} + +void QQnxFilePicker::close() +{ + navigator_card_close_child(); + cleanup(); +} + +bool QQnxFilePicker::nativeEventFilter(const QByteArray&, void *message, long*) +{ + bps_event_t * const event = static_cast<bps_event_t*>(message); + if (!event) + return false; + + if (bps_event_get_code(event) == NAVIGATOR_INVOKE_TARGET_RESULT) { + const char *id = navigator_event_get_id(event); + const char *err = navigator_event_get_err(event); + qFilePickerDebug("received invocation response: id=%s err=%s", id, err); + } else if (bps_event_get_code(event) == NAVIGATOR_CHILD_CARD_CLOSED) { + const char *data = navigator_event_get_card_closed_data(event); + qFilePickerDebug("received data: data='%s'", data); + handleFilePickerResponse(data); + } + + return false; // do not drop the event +} + +void QQnxFilePicker::setMode(QQnxFilePicker::Mode mode) +{ + m_mode = mode; +} + +void QQnxFilePicker::setDefaultSaveFileNames(const QStringList &fileNames) +{ + m_defaultSaveFileNames = fileNames; +} + +void QQnxFilePicker::addDefaultSaveFileName(const QString &fileName) +{ + m_defaultSaveFileNames.append(fileName); +} + +void QQnxFilePicker::setDirectories(const QStringList &directories) +{ + m_directories = directories; +} + +void QQnxFilePicker::addDirectory(const QString &directory) +{ + m_directories.append(directory); +} + +void QQnxFilePicker::setFilters(const QStringList &filters) +{ + m_filters = filters; +} + +void QQnxFilePicker::setTitle(const QString &title) +{ + m_title = title; +} + +QQnxFilePicker::Mode QQnxFilePicker::mode() const +{ + return m_mode; +} + +QStringList QQnxFilePicker::defaultSaveFileNames() const +{ + return m_defaultSaveFileNames; +} + +QStringList QQnxFilePicker::directories() const +{ + return m_directories; +} + +QStringList QQnxFilePicker::filters() const +{ + return m_filters; +} + +QStringList QQnxFilePicker::selectedFiles() const +{ + return m_selectedFiles; +} + +QString QQnxFilePicker::title() const +{ + return m_title; +} + +void QQnxFilePicker::cleanup() +{ + if (m_invocationHandle) { + navigator_invoke_invocation_destroy(m_invocationHandle); + m_invocationHandle = 0; + } +} + +void QQnxFilePicker::handleFilePickerResponse(const char *data) +{ + QJsonParseError jsonError; + QJsonDocument document = QJsonDocument::fromJson(data, &jsonError); + + if (jsonError.error != QJsonParseError::NoError) { + qFilePickerDebug() << "Error parsing FilePicker response: " + << jsonError.errorString(); + Q_EMIT closed(); + cleanup(); + return; + } + + // The response is a list of Json objects. + const QVariantList array = document.array().toVariantList(); + + foreach (const QVariant &variant, array) { + const QJsonObject object = QJsonObject::fromVariantMap(variant.toMap()); + const QUrl url(object.value(QStringLiteral("uri")).toString()); + const QString localFile = url.toLocalFile(); // strip "file://" + + if (!localFile.isEmpty()) + m_selectedFiles << localFile; + + qFilePickerDebug() << "FilePicker uri response:" << localFile; + } + + Q_EMIT closed(); + cleanup(); +} + +QString QQnxFilePicker::modeToString(QQnxFilePicker::Mode mode) const +{ + switch (mode) { + case Picker: + return QStringLiteral("Picker"); + case Saver: + return QStringLiteral("Saver"); + case PickerMultiple: + return QStringLiteral("PickerMultiple"); + case SaverMultiple: + return QStringLiteral("SaverMultiple"); + } + + return QStringLiteral("Picker"); +} diff --git a/src/plugins/platforminputcontexts/maliit/main.cpp b/src/plugins/platforms/qnx/qqnxfilepicker.h index ca4845afd7..5bb8f0969f 100644 --- a/src/plugins/platforminputcontexts/maliit/main.cpp +++ b/src/plugins/platforms/qnx/qqnxfilepicker.h @@ -1,6 +1,6 @@ -/**************************************************************************** +/*************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Research In Motion ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -39,30 +39,72 @@ ** ****************************************************************************/ -#include <qpa/qplatforminputcontextplugin_p.h> -#include <QtCore/QStringList> -#include "qmaliitplatforminputcontext.h" +#ifndef QQNXFILEPICKER_H +#define QQNXFILEPICKER_H -QT_BEGIN_NAMESPACE +#include <QAbstractNativeEventFilter> +#include <QObject> +#include <QStringList> -class QMaliitPlatformInputContextPlugin : public QPlatformInputContextPlugin +struct navigator_invoke_invocation_t; + +class QQnxFilePicker : public QObject, public QAbstractNativeEventFilter { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPlatformInputContextFactoryInterface" FILE "maliit.json") public: - QPlatformInputContext *create(const QString&, const QStringList&); -}; + explicit QQnxFilePicker(QObject *parent = 0); + ~QQnxFilePicker(); -QPlatformInputContext *QMaliitPlatformInputContextPlugin::create(const QString& system, const QStringList& paramList) -{ - Q_UNUSED(paramList); + enum Mode { + Picker, + Saver, + PickerMultiple, + SaverMultiple + }; + + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE; + + void setMode(Mode mode); + void setDefaultSaveFileNames(const QStringList &fileNames); + void addDefaultSaveFileName(const QString &fileName); + void setDirectories(const QStringList &directories); + void addDirectory(const QString &directory); + void setFilters(const QStringList &filters); + void setTitle(const QString &title); + + Mode mode() const; + + QStringList defaultSaveFileNames() const; + QStringList directories() const; + QStringList filters() const; + QStringList selectedFiles() const; + + QString title() const; - if (system.compare(system, QStringLiteral("maliit"), Qt::CaseInsensitive) == 0) - return new QMaliitPlatformInputContext; - return 0; -} +Q_SIGNALS: + void closed(); -QT_END_NAMESPACE +public Q_SLOTS: + void open(); + void close(); + +private: + void cleanup(); + void handleFilePickerResponse(const char *data); + + QString modeToString(Mode mode) const; + + navigator_invoke_invocation_t *m_invocationHandle; + + Mode m_mode; + + QStringList m_defaultSaveFileNames; + QStringList m_directories; + QStringList m_filters; + QStringList m_selectedFiles; + + QString m_title; +}; -#include "main.moc" +#endif // QQNXFILEPICKER_H diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp index ed959467ff..448509c69d 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.cpp +++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp @@ -60,36 +60,10 @@ QT_BEGIN_NAMESPACE EGLDisplay QQnxGLContext::ms_eglDisplay = EGL_NO_DISPLAY; -static EGLenum checkEGLError(const char *msg) -{ - static const char *errmsg[] = - { - "EGL function succeeded", - "EGL is not initialized, or could not be initialized, for the specified display", - "EGL cannot access a requested resource", - "EGL failed to allocate resources for the requested operation", - "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list", - "EGLConfig argument does not name a valid EGLConfig", - "EGLContext argument does not name a valid EGLContext", - "EGL current surface of the calling thread is no longer valid", - "EGLDisplay argument does not name a valid EGLDisplay", - "EGL arguments are inconsistent", - "EGLNativePixmapType argument does not refer to a valid native pixmap", - "EGLNativeWindowType argument does not refer to a valid native window", - "EGL one or more argument values are invalid", - "EGLSurface argument does not name a valid surface configured for rendering", - "EGL power management event has occurred", - }; - EGLenum error = eglGetError(); - fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]); - return error; -} - QQnxGLContext::QQnxGLContext(QOpenGLContext *glContext) : QPlatformOpenGLContext(), m_glContext(glContext), - m_eglSurface(EGL_NO_SURFACE), - m_newSurfaceRequested(true) // Create a surface the first time makeCurrent() is called + m_currentEglSurface(EGL_NO_SURFACE) { qGLContextDebug() << Q_FUNC_INFO; QSurfaceFormat format = m_glContext->format(); @@ -168,9 +142,31 @@ QQnxGLContext::~QQnxGLContext() // Cleanup EGL context if it exists if (m_eglContext != EGL_NO_CONTEXT) eglDestroyContext(ms_eglDisplay, m_eglContext); +} - // Cleanup EGL surface if it exists - destroySurface(); +EGLenum QQnxGLContext::checkEGLError(const char *msg) +{ + static const char *errmsg[] = + { + "EGL function succeeded", + "EGL is not initialized, or could not be initialized, for the specified display", + "EGL cannot access a requested resource", + "EGL failed to allocate resources for the requested operation", + "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list", + "EGLConfig argument does not name a valid EGLConfig", + "EGLContext argument does not name a valid EGLContext", + "EGL current surface of the calling thread is no longer valid", + "EGLDisplay argument does not name a valid EGLDisplay", + "EGL arguments are inconsistent", + "EGLNativePixmapType argument does not refer to a valid native pixmap", + "EGLNativeWindowType argument does not refer to a valid native window", + "EGL one or more argument values are invalid", + "EGLSurface argument does not name a valid surface configured for rendering", + "EGL power management event has occurred", + }; + EGLenum error = eglGetError(); + fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]); + return error; } void QQnxGLContext::initialize() @@ -199,12 +195,6 @@ void QQnxGLContext::shutdown() eglTerminate(ms_eglDisplay); } -void QQnxGLContext::requestSurfaceChange() -{ - qGLContextDebug() << Q_FUNC_INFO; - m_newSurfaceRequested.testAndSetRelease(false, true); -} - bool QQnxGLContext::makeCurrent(QPlatformSurface *surface) { qGLContextDebug() << Q_FUNC_INFO; @@ -216,14 +206,18 @@ bool QQnxGLContext::makeCurrent(QPlatformSurface *surface) if (eglResult != EGL_TRUE) qFatal("QQnxGLContext: failed to set EGL API, err=%d", eglGetError()); - if (m_newSurfaceRequested.testAndSetOrdered(true, false)) { - qGLContextDebug() << "New EGL surface requested"; + QQnxWindow *platformWindow = dynamic_cast<QQnxWindow*>(surface); + if (!platformWindow) + return false; + + platformWindow->setPlatformOpenGLContext(this); + + if (m_currentEglSurface == EGL_NO_SURFACE || m_currentEglSurface != platformWindow->getSurface()) { + m_currentEglSurface = platformWindow->getSurface(); doneCurrent(); - destroySurface(); - createSurface(surface); } - eglResult = eglMakeCurrent(ms_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext); + eglResult = eglMakeCurrent(ms_eglDisplay, m_currentEglSurface, m_currentEglSurface, m_eglContext); if (eglResult != EGL_TRUE) { checkEGLError("eglMakeCurrent"); qFatal("QQNX: failed to set current EGL context, err=%d", eglGetError()); @@ -248,18 +242,12 @@ void QQnxGLContext::doneCurrent() void QQnxGLContext::swapBuffers(QPlatformSurface *surface) { - Q_UNUSED(surface); qGLContextDebug() << Q_FUNC_INFO; + QQnxWindow *platformWindow = dynamic_cast<QQnxWindow*>(surface); + if (!platformWindow) + return; - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (eglResult != EGL_TRUE) - qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); - - // Post EGL surface to window - eglResult = eglSwapBuffers(ms_eglDisplay, m_eglSurface); - if (eglResult != EGL_TRUE) - qFatal("QQNX: failed to swap EGL buffers, err=%d", eglGetError()); + platformWindow->swapEGLBuffers(); } QFunctionPointer QQnxGLContext::getProcAddress(const QByteArray &procName) @@ -275,6 +263,10 @@ QFunctionPointer QQnxGLContext::getProcAddress(const QByteArray &procName) return static_cast<QFunctionPointer>(eglGetProcAddress(procName.constData())); } +EGLDisplay QQnxGLContext::getEglDisplay() { + return ms_eglDisplay; +} + EGLint *QQnxGLContext::contextAttrs() { qGLContextDebug() << Q_FUNC_INFO; @@ -288,66 +280,4 @@ EGLint *QQnxGLContext::contextAttrs() #endif } -bool QQnxGLContext::isCurrent() const -{ - qGLContextDebug() << Q_FUNC_INFO; - return (eglGetCurrentContext() == m_eglContext); -} - -void QQnxGLContext::createSurface(QPlatformSurface *surface) -{ - qGLContextDebug() << Q_FUNC_INFO; - - // Get a pointer to the corresponding platform window - QQnxWindow *platformWindow = dynamic_cast<QQnxWindow*>(surface); - if (!platformWindow) - qFatal("QQNX: unable to create EGLSurface without a QQnxWindow"); - - // Link the window and context - platformWindow->setPlatformOpenGLContext(this); - - // Fetch the surface size from the window and update - // the window's buffers before we create the EGL surface - const QSize surfaceSize = platformWindow->requestedBufferSize(); - if (!surfaceSize.isValid()) { - qFatal("QQNX: Trying to create 0 size EGL surface. " - "Please set a valid window size before calling QOpenGLContext::makeCurrent()"); - } - platformWindow->setBufferSize(surfaceSize); - - // Post root window, in case it hasn't been posted yet, to make it appear. - platformWindow->screen()->onWindowPost(platformWindow); - - // Obtain the native handle for our window - screen_window_t handle = platformWindow->nativeHandle(); - - const EGLint eglSurfaceAttrs[] = - { - EGL_RENDER_BUFFER, EGL_BACK_BUFFER, - EGL_NONE - }; - - // Create EGL surface - m_eglSurface = eglCreateWindowSurface(ms_eglDisplay, m_eglConfig, (EGLNativeWindowType) handle, eglSurfaceAttrs); - if (m_eglSurface == EGL_NO_SURFACE) { - checkEGLError("eglCreateWindowSurface"); - qFatal("QQNX: failed to create EGL surface, err=%d", eglGetError()); - } -} - -void QQnxGLContext::destroySurface() -{ - qGLContextDebug() << Q_FUNC_INFO; - - // Destroy EGL surface if it exists - if (m_eglSurface != EGL_NO_SURFACE) { - EGLBoolean eglResult = eglDestroySurface(ms_eglDisplay, m_eglSurface); - if (eglResult != EGL_TRUE) { - qFatal("QQNX: failed to destroy EGL surface, err=%d", eglGetError()); - } - } - - m_eglSurface = EGL_NO_SURFACE; -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxglcontext.h b/src/plugins/platforms/qnx/qqnxglcontext.h index 6a7fca7df2..ff57861498 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.h +++ b/src/plugins/platforms/qnx/qqnxglcontext.h @@ -59,6 +59,8 @@ public: QQnxGLContext(QOpenGLContext *glContext); virtual ~QQnxGLContext(); + static EGLenum checkEGLError(const char *msg); + static void initialize(); static void shutdown(); @@ -71,13 +73,10 @@ public: virtual QSurfaceFormat format() const { return m_windowFormat; } - bool isCurrent() const; - - void createSurface(QPlatformSurface *surface); - void destroySurface(); - + static EGLDisplay getEglDisplay(); + EGLConfig getEglConfig() const { return m_eglConfig;} private: - /** \todo Should this be non-static so we can use additional displays? */ + //Can be static because different displays returne the same handle static EGLDisplay ms_eglDisplay; QSurfaceFormat m_windowFormat; @@ -85,9 +84,7 @@ private: EGLConfig m_eglConfig; EGLContext m_eglContext; - EGLSurface m_eglSurface; - - QAtomicInt m_newSurfaceRequested; + EGLSurface m_currentEglSurface; static EGLint *contextAttrs(); }; diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index feb05e3093..fa9961ccce 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -40,7 +40,9 @@ ****************************************************************************/ #include "qqnxintegration.h" +#if defined(QQNX_SCREENEVENTTHREAD) #include "qqnxscreeneventthread.h" +#endif #include "qqnxnativeinterface.h" #include "qqnxrasterbackingstore.h" #include "qqnxscreen.h" @@ -84,6 +86,8 @@ #include <qpa/qplatformwindow.h> #include <qpa/qwindowsysteminterface.h> +#include <QtGui/private/qguiapplication_p.h> + #if !defined(QT_NO_OPENGL) #include "qqnxglcontext.h" #include <QtGui/QOpenGLContext> @@ -107,9 +111,20 @@ QT_BEGIN_NAMESPACE QQnxWindowMapper QQnxIntegration::ms_windowMapper; QMutex QQnxIntegration::ms_windowMapperMutex; -QQnxIntegration::QQnxIntegration() +static inline QQnxIntegration::Options parseOptions(const QStringList ¶mList) +{ + QQnxIntegration::Options options = QQnxIntegration::NoOptions; + if (!paramList.contains(QLatin1String("no-fullscreen"))) { + options |= QQnxIntegration::FullScreenApplication; + } + return options; +} + +QQnxIntegration::QQnxIntegration(const QStringList ¶mList) : QPlatformIntegration() +#if defined(QQNX_SCREENEVENTTHREAD) , m_screenEventThread(0) +#endif , m_navigatorEventHandler(new QQnxNavigatorEventHandler()) , m_virtualKeyboard(0) #if defined(QQNX_PPS) @@ -134,6 +149,7 @@ QQnxIntegration::QQnxIntegration() #if !defined(QT_NO_DRAGANDDROP) , m_drag(new QSimpleDrag()) #endif + , m_options(parseOptions(paramList)) { qIntegrationDebug() << Q_FUNC_INFO; // Open connection to QNX composition manager @@ -185,8 +201,13 @@ QQnxIntegration::QQnxIntegration() #if defined(Q_OS_BLACKBERRY) QQnxVirtualKeyboardBps* virtualKeyboardBps = new QQnxVirtualKeyboardBps; - m_bpsEventFilter = new QQnxBpsEventFilter(m_navigatorEventHandler, - (m_screenEventThread ? 0 : m_screenEventHandler), virtualKeyboardBps); + +#if defined(QQNX_SCREENEVENTTHREAD) + m_bpsEventFilter = new QQnxBpsEventFilter(m_navigatorEventHandler, 0, virtualKeyboardBps); +#else + m_bpsEventFilter = new QQnxBpsEventFilter(m_navigatorEventHandler, m_screenEventHandler, virtualKeyboardBps); +#endif + m_bpsEventFilter->installOnEventDispatcher(m_eventDispatcher); m_virtualKeyboard = virtualKeyboardBps; @@ -383,7 +404,7 @@ QPlatformDrag *QQnxIntegration::drag() const QVariant QQnxIntegration::styleHint(QPlatformIntegration::StyleHint hint) const { qIntegrationDebug() << Q_FUNC_INFO; - if (hint == ShowIsFullScreen) + if ((hint == ShowIsFullScreen) && (m_options & FullScreenApplication)) return true; return QPlatformIntegration::styleHint(hint); @@ -526,6 +547,11 @@ QQnxScreen *QQnxIntegration::primaryDisplay() const return m_screens.first(); } +QQnxIntegration::Options QQnxIntegration::options() const +{ + return m_options; +} + bool QQnxIntegration::supportsNavigatorEvents() const { // If QQNX_PPS or Q_OS_BLACKBERRY is defined then we have navigator diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h index e3eb9e06ba..dd8973b767 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.h +++ b/src/plugins/platforms/qnx/qqnxintegration.h @@ -51,7 +51,9 @@ QT_BEGIN_NAMESPACE class QQnxBpsEventFilter; +#if defined(QQNX_SCREENEVENTTHREAD) class QQnxScreenEventThread; +#endif class QQnxFileDialogHelper; class QQnxNativeInterface; class QQnxWindow; @@ -80,7 +82,12 @@ typedef QHash<screen_window_t, QWindow *> QQnxWindowMapper; class QQnxIntegration : public QPlatformIntegration { public: - QQnxIntegration(); + enum Option { // Options to be passed on command line. + NoOptions = 0x0, + FullScreenApplication = 0x1 + }; + Q_DECLARE_FLAGS(Options, Option) + explicit QQnxIntegration(const QStringList ¶mList); ~QQnxIntegration(); bool hasCapability(QPlatformIntegration::Capability cap) const; @@ -129,6 +136,8 @@ public: void createDisplay(screen_display_t display, bool isPrimary); void removeDisplay(QQnxScreen *screen); QQnxScreen *primaryDisplay() const; + Options options() const; + private: void createDisplays(); void destroyDisplays(); @@ -137,7 +146,9 @@ private: static void removeWindow(screen_window_t qnxWindow); screen_context_t m_screenContext; +#if defined(QQNX_SCREENEVENTTHREAD) QQnxScreenEventThread *m_screenEventThread; +#endif QQnxNavigatorEventHandler *m_navigatorEventHandler; QQnxAbstractVirtualKeyboard *m_virtualKeyboard; #if defined(QQNX_PPS) @@ -164,6 +175,8 @@ private: static QQnxWindowMapper ms_windowMapper; static QMutex ms_windowMapperMutex; + const Options m_options; + friend class QQnxWindow; }; diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp index 6a7a4d0944..1da3cd5446 100644 --- a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp +++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp @@ -91,6 +91,11 @@ void QQnxRasterBackingStore::flush(QWindow *window, const QRegion ®ion, const if (window) targetWindow = static_cast<QQnxWindow *>(window->handle()); + // we only need to flush the platformWindow backing store, since this is + // the buffer where all drawing operations of all windows, including the + // child windows, are performed; conceptually ,child windows have no buffers + // (actually they do have a 1x1 placeholder buffer due to libscreen limitations), + // since Qt will only draw to the backing store of the top-level window. QQnxWindow *platformWindow = this->platformWindow(); if (!targetWindow || targetWindow == platformWindow) { @@ -108,28 +113,6 @@ void QQnxRasterBackingStore::flush(QWindow *window, const QRegion ®ion, const // update the display with newly rendered content platformWindow->post(region); - } else if (targetWindow) { - - // The contents of the backing store should be flushed to a different window than the - // window which owns the buffer. - // This typically happens for child windows, since child windows share a backing store with - // their top-level window (TLW). - // Simply copy the buffer over to the child window, to emulate a painting operation, and - // then post the window. - // - // ### Note that because of the design in the QNX QPA plugin, each window has its own buffers, - // even though they might share a backing store. This is unneeded overhead, but I don't think - // libscreen allows to have windows without buffers, or does it? - - // We assume that the TLW has been flushed previously and that no changes were made to the - // backing store inbetween (### does Qt guarantee this?) - - targetWindow->adjustBufferSize(); - targetWindow->blitFrom(platformWindow, offset, region); - targetWindow->post(region); - - } else { - qWarning() << Q_FUNC_INFO << "flush() called without a valid window!"; } m_hasUnflushedPaintOperations = false; diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp index 84721c9c2a..7959617443 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.cpp +++ b/src/plugins/platforms/qnx/qqnxscreen.cpp @@ -85,7 +85,9 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) { if (val[0] > 0 && val[1] > 0) return QSize(val[0], val[1]); - qWarning("QQnxScreen: screen_get_display_property_iv() reported an invalid physical screen size (%dx%d). Falling back to QQNX_PHYSICAL_SCREEN_SIZE environment variable.", val[0], val[1]); + qScreenDebug("QQnxScreen: screen_get_display_property_iv() reported an invalid " + "physical screen size (%dx%d). Falling back to QQNX_PHYSICAL_SCREEN_SIZE " + "environment variable.", val[0], val[1]); const QString envPhySizeStr = qgetenv("QQNX_PHYSICAL_SCREEN_SIZE"); if (!envPhySizeStr.isEmpty()) { @@ -94,7 +96,9 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) { const int envHeight = envPhySizeStrList.size() == 2 ? envPhySizeStrList[1].toInt() : -1; if (envWidth <= 0 || envHeight <= 0) { - qFatal("QQnxScreen: The value of QQNX_PHYSICAL_SCREEN_SIZE must be in the format \"width,height\" in mm, with width, height > 0. Example: QQNX_PHYSICAL_SCREEN_SIZE=150,90"); + qFatal("QQnxScreen: The value of QQNX_PHYSICAL_SCREEN_SIZE must be in the format " + "\"width,height\" in mm, with width, height > 0. " + "Example: QQNX_PHYSICAL_SCREEN_SIZE=150,90"); return QSize(150, 90); } @@ -103,11 +107,14 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) { #if defined(QQNX_PHYSICAL_SCREEN_SIZE_DEFINED) const QSize defSize(QQNX_PHYSICAL_SCREEN_WIDTH, QQNX_PHYSICAL_SCREEN_HEIGHT); - qWarning("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. Falling back to defines QQNX_PHYSICAL_SCREEN_WIDTH/QQNX_PHYSICAL_SCREEN_HEIGHT (%dx%d)", defSize.width(), defSize.height()); + qWarning("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. Falling back to defines " + "QQNX_PHYSICAL_SCREEN_WIDTH/QQNX_PHYSICAL_SCREEN_HEIGHT (%dx%d)", + defSize.width(), defSize.height()); return defSize; #else if (primaryScreen) - qFatal("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. Could not determine physical screen size."); + qFatal("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. " + "Could not determine physical screen size."); return QSize(150, 90); #endif } @@ -119,7 +126,6 @@ QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display, m_posted(false), m_keyboardHeight(0), m_nativeOrientation(Qt::PrimaryOrientation), - m_platformContext(0), m_cursor(new QQnxCursor()) { qScreenDebug() << Q_FUNC_INFO; @@ -475,9 +481,14 @@ void QQnxScreen::updateHierarchy() int topZorder; errno = 0; - result = screen_get_window_property_iv(rootWindow()->nativeHandle(), SCREEN_PROPERTY_ZORDER, &topZorder); - if (result != 0) - qFatal("QQnxScreen: failed to query root window z-order, errno=%d", errno); + if (isPrimaryScreen()) { + result = screen_get_window_property_iv(rootWindow()->nativeHandle(), SCREEN_PROPERTY_ZORDER, &topZorder); + if (result != 0) + qFatal("QQnxScreen: failed to query root window z-order, errno=%d", errno); + } else { + topZorder = 0; //We do not need z ordering on the secondary screen, because only one window + //is supported there + } topZorder++; // root window has the lowest z-order in the windowgroup diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h index 6e8c2c6a60..e498d27c14 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.h +++ b/src/plugins/platforms/qnx/qqnxscreen.h @@ -133,7 +133,6 @@ private: Qt::ScreenOrientation m_nativeOrientation; QRect m_initialGeometry; QRect m_currentGeometry; - QPlatformOpenGLContext *m_platformContext; QList<QQnxWindow *> m_childWindows; QList<screen_window_t> m_overlays; diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp index c2d0e3e41c..c869d29c99 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp +++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp @@ -469,8 +469,14 @@ void QQnxScreenEventHandler::handleDisplayEvent(screen_event_t event) qScreenEventDebug() << Q_FUNC_INFO << "display attachment is now:" << isAttached; QQnxScreen *screen = m_qnxIntegration->screenForNative(nativeDisplay); + if (!screen) { if (isAttached) { + int val[2]; + screen_get_display_property_iv(nativeDisplay, SCREEN_PROPERTY_SIZE, val); + if (val[0] == 0 && val[1] == 0) //If screen size is invalid, wait for the next event + return; + qScreenEventDebug() << "creating new QQnxScreen for newly attached display"; m_qnxIntegration->createDisplay(nativeDisplay, false /* not primary, we assume */); } diff --git a/src/plugins/platforms/qnx/qqnxtheme.cpp b/src/plugins/platforms/qnx/qqnxtheme.cpp index 733b7223b6..37c1079441 100644 --- a/src/plugins/platforms/qnx/qqnxtheme.cpp +++ b/src/plugins/platforms/qnx/qqnxtheme.cpp @@ -58,10 +58,8 @@ QQnxTheme::~QQnxTheme() bool QQnxTheme::usePlatformNativeDialog(DialogType type) const { -#if defined(Q_OS_BLACKBERRY_TABLET) if (type == QPlatformTheme::FileDialog) return true; -#endif #if !defined(QT_NO_COLORDIALOG) if (type == QPlatformTheme::ColorDialog) return false; @@ -76,10 +74,8 @@ bool QQnxTheme::usePlatformNativeDialog(DialogType type) const QPlatformDialogHelper *QQnxTheme::createPlatformDialogHelper(DialogType type) const { switch (type) { -#if defined(Q_OS_BLACKBERRY_TABLET) case QPlatformTheme::FileDialog: return new QQnxFileDialogHelper(m_integration); -#endif #if !defined(QT_NO_COLORDIALOG) case QPlatformTheme::ColorDialog: #endif diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index fb8e8075ad..9b9576c88b 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -72,13 +72,15 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context) m_window(0), m_currentBufferIndex(-1), m_previousBufferIndex(-1), -#if !defined(QT_NO_OPENGL) - m_platformOpenGLContext(0), -#endif m_screen(0), m_parentWindow(0), m_visible(false), m_windowState(Qt::WindowNoState), +#if !defined(QT_NO_OPENGL) + m_platformOpenGLContext(0), + m_newSurfaceRequested(true), + m_eglSurface(EGL_NO_SURFACE), +#endif m_requestedBufferSize(window->geometry().size()) { qWindowDebug() << Q_FUNC_INFO << "window =" << window << ", size =" << window->size(); @@ -86,7 +88,11 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context) // Create child QNX window errno = 0; - result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW); + if (static_cast<QQnxScreen *>(window->screen()->handle())->isPrimaryScreen()) { + result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW); + } else { + result = screen_create_window(&m_window, m_screenContext); + } if (result != 0) qFatal("QQnxWindow: failed to create window, errno=%d", errno); @@ -172,6 +178,11 @@ QQnxWindow::~QQnxWindow() // Cleanup QNX window and its buffers screen_destroy_window(m_window); + +#if !defined(QT_NO_OPENGL) + // Cleanup EGL surface if it exists + destroyEGLSurface(); +#endif } void QQnxWindow::setGeometry(const QRect &rect) @@ -180,16 +191,16 @@ void QQnxWindow::setGeometry(const QRect &rect) #if !defined(QT_NO_OPENGL) // If this is an OpenGL window we need to request that the GL context updates - // the EGLsurface on which it is rendering. The surface will be recreated the - // next time QQnxGLContext::makeCurrent() is called. + // the EGLsurface on which it is rendering. { // We want the setting of the atomic bool in the GL context to be atomic with // setting m_requestedBufferSize and therefore extended the scope to include // that test. const QMutexLocker locker(&m_mutex); m_requestedBufferSize = rect.size(); - if (m_platformOpenGLContext != 0 && bufferSize() != rect.size()) - m_platformOpenGLContext->requestSurfaceChange(); + if (m_platformOpenGLContext != 0 && bufferSize() != rect.size()) { + m_newSurfaceRequested.testAndSetRelease(false, true); + } } #endif @@ -336,6 +347,9 @@ QSize QQnxWindow::requestedBufferSize() const void QQnxWindow::adjustBufferSize() { + if (m_parentWindow) + return; + const QSize windowSize = window()->size(); if (windowSize != bufferSize()) setBufferSize(windowSize); @@ -526,8 +540,12 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen) if (m_screen == platformScreen) return; - if (m_screen) + if (m_screen) { + qWindowDebug() << Q_FUNC_INFO << "Moving window to different screen"; m_screen->removeWindow(this); + screen_leave_window_group(m_window); + } + platformScreen->addWindow(this); m_screen = platformScreen; @@ -538,17 +556,20 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen) if (result != 0) qFatal("QQnxWindow: failed to set window display, errno=%d", errno); - // Add window to display's window group - errno = 0; - result = screen_join_window_group(m_window, platformScreen->windowGroupName()); - if (result != 0) - qFatal("QQnxWindow: failed to join window group, errno=%d", errno); - Q_FOREACH (QQnxWindow *childWindow, m_childWindows) { - // Only subwindows and tooltips need necessarily be moved to another display with the window. - if ((window()->type() & Qt::WindowType_Mask) == Qt::SubWindow || - (window()->type() & Qt::WindowType_Mask) == Qt::ToolTip) - childWindow->setScreen(platformScreen); + if (m_screen->isPrimaryScreen()) { + // Add window to display's window group + errno = 0; + result = screen_join_window_group(m_window, platformScreen->windowGroupName()); + if (result != 0) + qFatal("QQnxWindow: failed to join window group, errno=%d", errno); + + Q_FOREACH (QQnxWindow *childWindow, m_childWindows) { + // Only subwindows and tooltips need necessarily be moved to another display with the window. + if ((window()->type() & Qt::WindowType_Mask) == Qt::SubWindow || + (window()->type() & Qt::WindowType_Mask) == Qt::ToolTip) + childWindow->setScreen(platformScreen); + } } m_screen->updateHierarchy(); @@ -586,8 +607,18 @@ void QQnxWindow::setParent(const QPlatformWindow *window) setScreen(m_parentWindow->m_screen); m_parentWindow->m_childWindows.push_back(this); + + // we don't need any buffers, since + // Qt will draw to the parent TLW + // backing store. + setBufferSize(QSize(1, 1)); } else { m_screen->addWindow(this); + + // recreate buffers, in case the + // window has been reparented and + // becomes a TLW + adjustBufferSize(); } m_screen->updateHierarchy(); @@ -646,6 +677,12 @@ void QQnxWindow::setWindowState(Qt::WindowState state) applyWindowState(); } +void QQnxWindow::propagateSizeHints() +{ + // nothing to do; silence base class warning + qWindowDebug() << Q_FUNC_INFO << ": ignored"; +} + void QQnxWindow::gainedFocus() { qWindowDebug() << Q_FUNC_INFO << "window =" << window(); @@ -711,6 +748,79 @@ void QQnxWindow::minimize() #endif } +#if !defined(QT_NO_OPENGL) +void QQnxWindow::createEGLSurface() +{ + // Fetch the surface size from the window and update + // the window's buffers before we create the EGL surface + const QSize surfaceSize = requestedBufferSize(); + if (!surfaceSize.isValid()) { + qFatal("QQNX: Trying to create 0 size EGL surface. " + "Please set a valid window size before calling QOpenGLContext::makeCurrent()"); + } + setBufferSize(surfaceSize); + + // Post root window, in case it hasn't been posted yet, to make it appear. + screen()->onWindowPost(0); + + const EGLint eglSurfaceAttrs[] = + { + EGL_RENDER_BUFFER, EGL_BACK_BUFFER, + EGL_NONE + }; + + qWindowDebug() << "Creating EGL surface" << platformOpenGLContext()->getEglDisplay() + << platformOpenGLContext()->getEglConfig(); + // Create EGL surface + m_eglSurface = eglCreateWindowSurface(platformOpenGLContext()->getEglDisplay() + , platformOpenGLContext()->getEglConfig(), + (EGLNativeWindowType) m_window, eglSurfaceAttrs); + if (m_eglSurface == EGL_NO_SURFACE) { + QQnxGLContext::checkEGLError("eglCreateWindowSurface"); + qFatal("QQNX: failed to create EGL surface, err=%d", eglGetError()); + } +} + +void QQnxWindow::destroyEGLSurface() +{ + // Destroy EGL surface if it exists + if (m_eglSurface != EGL_NO_SURFACE) { + EGLBoolean eglResult = eglDestroySurface(platformOpenGLContext()->getEglDisplay(), m_eglSurface); + if (eglResult != EGL_TRUE) + qFatal("QQNX: failed to destroy EGL surface, err=%d", eglGetError()); + } + + m_eglSurface = EGL_NO_SURFACE; +} + +void QQnxWindow::swapEGLBuffers() +{ + qWindowDebug() << Q_FUNC_INFO; + // Set current rendering API + EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); + if (eglResult != EGL_TRUE) + qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); + + // Post EGL surface to window + eglResult = eglSwapBuffers(m_platformOpenGLContext->getEglDisplay(), m_eglSurface); + if (eglResult != EGL_TRUE) + qFatal("QQNX: failed to swap EGL buffers, err=%d", eglGetError()); +} + +EGLSurface QQnxWindow::getSurface() +{ + if (m_newSurfaceRequested.testAndSetOrdered(true, false)) { + if (m_eglSurface != EGL_NO_SURFACE) { + platformOpenGLContext()->doneCurrent(); + destroyEGLSurface(); + } + createEGLSurface(); + } + + return m_eglSurface; +} +#endif + void QQnxWindow::updateZorder(int &topZorder) { errno = 0; diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index 63d5dc0979..4fabccf4cb 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -103,6 +103,8 @@ public: void requestActivateWindow(); void setWindowState(Qt::WindowState state); + void propagateSizeHints(); + void gainedFocus(); QQnxScreen *screen() const { return m_screen; } @@ -118,6 +120,13 @@ public: void blitFrom(QQnxWindow *sourceWindow, const QPoint &sourceOffset, const QRegion &targetRegion); void minimize(); +#if !defined(QT_NO_OPENGL) + void createEGLSurface(); + void destroyEGLSurface(); + void swapEGLBuffers(); + EGLSurface getSurface(); +#endif + private: QRect setGeometryHelper(const QRect &rect); void removeFromParent(); @@ -145,9 +154,6 @@ private: QRegion m_previousDirty; QRegion m_scrolled; -#if !defined(QT_NO_OPENGL) - QQnxGLContext *m_platformOpenGLContext; -#endif QQnxScreen *m_screen; QList<QQnxWindow*> m_childWindows; QQnxWindow *m_parentWindow; @@ -162,6 +168,13 @@ private: // EGL surface. All of this has to be done from the thread that is calling // QQnxGLContext::makeCurrent() mutable QMutex m_mutex; + +#if !defined(QT_NO_OPENGL) + QQnxGLContext *m_platformOpenGLContext; + QAtomicInt m_newSurfaceRequested; + EGLSurface m_eglSurface; +#endif + QSize m_requestedBufferSize; }; diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp index 7a28fd9074..a0f2c1812f 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp +++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp @@ -1207,10 +1207,14 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowColumnExtents(long *row, { QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - if (!accessible) + if (!accessible || !tableCellInterface()) return E_FAIL; - tableCellInterface()->rowColumnExtents((int*)row, (int*)column, (int*)rowExtents, (int*)columnExtents, (bool*)isSelected); + *row = (long)tableCellInterface()->rowIndex(); + *column = (long)tableCellInterface()->columnIndex(); + *rowExtents = (long)tableCellInterface()->rowExtent(); + *columnExtents = (long)tableCellInterface()->columnExtent(); + *isSelected = tableCellInterface()->isSelected(); return S_OK; } diff --git a/src/plugins/platforms/windows/main.cpp b/src/plugins/platforms/windows/main.cpp index e5c3269a6c..ffd87af193 100644 --- a/src/plugins/platforms/windows/main.cpp +++ b/src/plugins/platforms/windows/main.cpp @@ -105,12 +105,12 @@ QT_BEGIN_NAMESPACE class QWindowsIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "windows.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "windows.json") public: - QPlatformIntegration *create(const QString&, const QStringList&); + QPlatformIntegration *create(const QString&, const QStringList&, int &, char **); }; -QPlatformIntegration *QWindowsIntegrationPlugin::create(const QString& system, const QStringList& paramList) +QPlatformIntegration *QWindowsIntegrationPlugin::create(const QString& system, const QStringList& paramList, int &, char **) { if (system.compare(system, QStringLiteral("windows"), Qt::CaseInsensitive) == 0) return new QWindowsIntegration(paramList); diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h index 49ddf3106b..4c08a664d8 100644 --- a/src/plugins/platforms/windows/qtwindows_additional.h +++ b/src/plugins/platforms/windows/qtwindows_additional.h @@ -49,6 +49,10 @@ # define WM_THEMECHANGED 0x031A #endif +#ifndef WM_DWMCOMPOSITIONCHANGED +# define WM_DWMCOMPOSITIONCHANGED 0x31E +#endif + #ifndef GWL_HWNDPARENT # define GWL_HWNDPARENT (-8) #endif diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index 238817e85c..e9eb50799e 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -83,6 +83,7 @@ enum WindowsEventType // Simplify event types CalculateSize = WindowEventFlag + 16, FocusInEvent = WindowEventFlag + 17, FocusOutEvent = WindowEventFlag + 18, + WhatsThisEvent = WindowEventFlag + 19, MouseEvent = MouseEventFlag + 1, MouseWheelEvent = MouseEventFlag + 2, CursorEvent = MouseEventFlag + 3, @@ -104,6 +105,7 @@ enum WindowsEventType // Simplify event types InputMethodCloseCandidateWindowEvent = InputMethodEventFlag + 5, InputMethodRequest = InputMethodEventFlag + 6, ThemeChanged = ThemingEventFlag + 1, + CompositionSettingsChanged = ThemingEventFlag + 2, DisplayChangedEvent = 437, SettingChangedEvent = DisplayChangedEvent + 1, ContextMenu = 123, @@ -200,10 +202,18 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI return QtWindows::DisplayChangedEvent; case WM_THEMECHANGED: return QtWindows::ThemeChanged; + case WM_DWMCOMPOSITIONCHANGED: + return QtWindows::CompositionSettingsChanged; #ifndef QT_NO_CONTEXTMENU case WM_CONTEXTMENU: return QtWindows::ContextMenu; #endif + case WM_SYSCOMMAND: +#ifndef Q_OS_WINCE + if ((wParamIn & 0xfff0) == SC_CONTEXTHELP) + return QtWindows::WhatsThisEvent; +#endif + break; default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 5114e9d524..8dab1e2b1c 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -47,6 +47,7 @@ #include "qtwindowsglobal.h" #include "qwindowsmime.h" #include "qwindowsinputcontext.h" +#include "qwindowstabletsupport.h" #ifndef QT_NO_ACCESSIBILITY #include "accessible/qwindowsaccessibility.h" #endif @@ -83,6 +84,7 @@ int QWindowsContext::verboseOLE = 0; int QWindowsContext::verboseInputMethods = 0; int QWindowsContext::verboseDialogs = 0; int QWindowsContext::verboseTheming = 0; +int QWindowsContext::verboseTablet = 0; // Get verbosity of components from "foo:2,bar:3" static inline int componentVerbose(const char *v, const char *keyWord) @@ -216,6 +218,7 @@ bool QWindowsUser32DLL::initTouch() QWindowsShell32DLL::QWindowsShell32DLL() : sHCreateItemFromParsingName(0) , sHGetStockIconInfo(0) + , sHGetImageList(0) { } @@ -224,6 +227,7 @@ void QWindowsShell32DLL::init() QSystemLibrary library(QStringLiteral("shell32")); sHCreateItemFromParsingName = (SHCreateItemFromParsingName)(library.resolve("SHCreateItemFromParsingName")); sHGetStockIconInfo = (SHGetStockIconInfo)library.resolve("SHGetStockIconInfo"); + sHGetImageList = (SHGetImageList)library.resolve("SHGetImageList"); } QWindowsUser32DLL QWindowsContext::user32dll; @@ -259,17 +263,20 @@ struct QWindowsContextPrivate { QWindowsMimeConverter m_mimeConverter; QWindowsScreenManager m_screenManager; QSharedPointer<QWindowCreationContext> m_creationContext; +#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) + QScopedPointer<QWindowsTabletSupport> m_tabletSupport; +#endif const HRESULT m_oleInitializeResult; const QByteArray m_eventType; QWindow *m_lastActiveWindow; bool m_asyncExpose; }; -QWindowsContextPrivate::QWindowsContextPrivate() : - m_systemInfo(0), - m_oleInitializeResult(OleInitialize(NULL)), - m_eventType(QByteArrayLiteral("windows_generic_MSG")), - m_lastActiveWindow(0), m_asyncExpose(0) +QWindowsContextPrivate::QWindowsContextPrivate() + : m_systemInfo(0) + , m_oleInitializeResult(OleInitialize(NULL)) + , m_eventType(QByteArrayLiteral("windows_generic_MSG")) + , m_lastActiveWindow(0), m_asyncExpose(0) { const QSysInfo::WinVersion ver = QSysInfo::windowsVersion(); #ifndef Q_OS_WINCE @@ -310,7 +317,13 @@ QWindowsContext::QWindowsContext() : QWindowsContext::verboseInputMethods = componentVerbose(v, "im"); QWindowsContext::verboseDialogs = componentVerbose(v, "dialogs"); QWindowsContext::verboseTheming = componentVerbose(v, "theming"); + QWindowsContext::verboseTablet = componentVerbose(v, "tablet"); } +#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) + d->m_tabletSupport.reset(QWindowsTabletSupport::create()); + if (QWindowsContext::verboseTablet) + qDebug() << "Tablet support: " << (d->m_tabletSupport.isNull() ? QStringLiteral("None") : d->m_tabletSupport->description()); +#endif } QWindowsContext::~QWindowsContext() @@ -631,6 +644,15 @@ QWindowsScreenManager &QWindowsContext::screenManager() return d->m_screenManager; } +QWindowsTabletSupport *QWindowsContext::tabletSupport() const +{ +#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) + return d->m_tabletSupport.data(); +#else + return 0; +#endif +} + /*! \brief Convenience to create a non-visible, message-only dummy window for example used as clipboard watcher or for GL. @@ -864,8 +886,15 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, theme->windowsThemeChanged(platformWindow->window()); return true; } + case QtWindows::CompositionSettingsChanged: + platformWindow->handleCompositionSettingsChanged(); + return true; #ifndef Q_OS_WINCE case QtWindows::ActivateWindowEvent: +#ifndef QT_NO_TABLETEVENT + if (!d->m_tabletSupport.isNull()) + d->m_tabletSupport->notifyActivate(); +#endif // !QT_NO_TABLETEVENT if (platformWindow->testFlag(QWindowsWindow::BlockedByModal)) if (const QWindow *modalWindow = QGuiApplication::modalWindow()) QWindowsWindow::baseWindowOf(modalWindow)->alertWindow(); @@ -875,6 +904,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::ContextMenu: return handleContextMenuEvent(platformWindow->window(), msg); #endif + case QtWindows::WhatsThisEvent: { +#ifndef QT_NO_WHATSTHIS + QWindowSystemInterface::handleEnterWhatsThisEvent(); + return true; +#endif + } break; default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 6b80075379..173df58570 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE class QWindow; class QPlatformScreen; class QWindowsScreenManager; +class QWindowsTabletSupport; class QWindowsWindow; class QWindowsMimeConverter; struct QWindowCreationContext; @@ -107,9 +108,11 @@ struct QWindowsShell32DLL typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **); typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *); + typedef HRESULT (WINAPI *SHGetImageList)(int, REFIID , void **); SHCreateItemFromParsingName sHCreateItemFromParsingName; SHGetStockIconInfo sHGetStockIconInfo; + SHGetImageList sHGetImageList; }; #endif // Q_OS_WINCE @@ -135,6 +138,7 @@ public: static int verboseInputMethods; static int verboseDialogs; static int verboseTheming; + static int verboseTablet; explicit QWindowsContext(); ~QWindowsContext(); @@ -185,6 +189,7 @@ public: QWindowsMimeConverter &mimeConverter() const; QWindowsScreenManager &screenManager(); + QWindowsTabletSupport *tabletSupport() const; #ifndef Q_OS_WINCE static QWindowsUser32DLL user32dll; static QWindowsShell32DLL shell32dll; diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 9a7d03c0c2..0e6c49aedb 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#define QT_NO_URL_CAST_FROM_STRING 1 + #include "qwindowsdialoghelpers.h" #include "qwindowscontext.h" @@ -64,6 +66,8 @@ #include <QtCore/QMutexLocker> #include <QtCore/private/qsystemlibrary_p.h> +#include <algorithm> + #include "qtwindows_additional.h" #define STRICT_TYPED_ITEMIDS @@ -613,24 +617,6 @@ void QWindowsDialogHelperBase<BaseClass>::exec() } } -static inline bool snapToDefaultButtonHint() -{ - BOOL snapToDefault = false; - if (SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0, &snapToDefault, 0)) - return snapToDefault; - return false; -} - -template <class BaseClass> -QVariant QWindowsDialogHelperBase<BaseClass>::styleHint(QPlatformDialogHelper::StyleHint hint) const -{ - switch (hint) { - case QPlatformDialogHelper::SnapToDefaultButton: - return QVariant(snapToDefaultButtonHint()); - } - return BaseClass::styleHint(hint); -} - /*! \class QWindowsFileDialogSharedData \brief Explicitly shared file dialog parameters that are not in QFileDialogOptions. @@ -651,34 +637,34 @@ public: QWindowsFileDialogSharedData() : m_data(new Data) {} void fromOptions(const QSharedPointer<QFileDialogOptions> &o); - QString directory() const; - void setDirectory(const QString &); + QUrl directory() const; + void setDirectory(const QUrl &); QString selectedNameFilter() const; void setSelectedNameFilter(const QString &); - QStringList selectedFiles() const; - void setSelectedFiles(const QStringList &); + QList<QUrl> selectedFiles() const; + void setSelectedFiles(const QList<QUrl> &); QString selectedFile() const; private: class Data : public QSharedData { public: - QString directory; + QUrl directory; QString selectedNameFilter; - QStringList selectedFiles; + QList<QUrl> selectedFiles; QMutex mutex; }; QExplicitlySharedDataPointer<Data> m_data; }; -inline QString QWindowsFileDialogSharedData::directory() const +inline QUrl QWindowsFileDialogSharedData::directory() const { m_data->mutex.lock(); - const QString result = m_data->directory; + const QUrl result = m_data->directory; m_data->mutex.unlock(); return result; } -inline void QWindowsFileDialogSharedData::setDirectory(const QString &d) +inline void QWindowsFileDialogSharedData::setDirectory(const QUrl &d) { QMutexLocker (&m_data->mutex); m_data->directory = d; @@ -698,24 +684,24 @@ inline void QWindowsFileDialogSharedData::setSelectedNameFilter(const QString &f m_data->selectedNameFilter = f; } -inline QStringList QWindowsFileDialogSharedData::selectedFiles() const +inline QList<QUrl> QWindowsFileDialogSharedData::selectedFiles() const { m_data->mutex.lock(); - const QStringList result = m_data->selectedFiles; + const QList<QUrl> result = m_data->selectedFiles; m_data->mutex.unlock(); return result; } inline QString QWindowsFileDialogSharedData::selectedFile() const { - const QStringList files = selectedFiles(); - return files.isEmpty() ? QString() : files.front(); + const QList<QUrl> files = selectedFiles(); + return files.isEmpty() ? QString() : files.front().toLocalFile(); } -inline void QWindowsFileDialogSharedData::setSelectedFiles(const QStringList &f) +inline void QWindowsFileDialogSharedData::setSelectedFiles(const QList<QUrl> &urls) { QMutexLocker (&m_data->mutex); - m_data->selectedFiles = f; + m_data->selectedFiles = urls; } inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer<QFileDialogOptions> &o) @@ -779,7 +765,7 @@ public: QWindowsNativeFileDialogEventHandler(QWindowsNativeFileDialogBase *nativeFileDialog) : m_ref(1), m_nativeFileDialog(nativeFileDialog) {} - ~QWindowsNativeFileDialogEventHandler() {} + virtual ~QWindowsNativeFileDialogEventHandler() {} private: long m_ref; @@ -822,7 +808,7 @@ public: virtual void setWindowTitle(const QString &title); inline void setMode(QFileDialogOptions::FileMode mode, QFileDialogOptions::FileDialogOptions options); inline void setDirectory(const QString &directory); - inline void updateDirectory() { setDirectory(m_data.directory()); } + inline void updateDirectory() { setDirectory(m_data.directory().toLocalFile()); } inline QString directory() const; virtual void exec(HWND owner = 0); virtual void setNameFilters(const QStringList &f); @@ -837,10 +823,10 @@ public: inline void setLabelText(QFileDialogOptions::DialogLabel l, const QString &text); // Return the selected files for tracking in OnSelectionChanged(). - virtual QStringList selectedFiles() const = 0; + virtual QList<QUrl> selectedFiles() const = 0; // Return the result for tracking in OnFileOk(). Differs from selection for // example by appended default suffixes, etc. - virtual QStringList dialogResult() const = 0; + virtual QList<QUrl> dialogResult() const = 0; inline void onFolderChange(IShellItem *); inline void onSelectionChange(); @@ -848,8 +834,8 @@ public: inline bool onFileOk(); signals: - void directoryEntered(const QString& directory); - void currentChanged(const QString& file); + void directoryEntered(const QUrl &directory); + void currentChanged(const QUrl &file); void filterSelected(const QString & filter); public slots: @@ -861,9 +847,9 @@ protected: void setDefaultSuffixSys(const QString &s); inline IFileDialog * fileDialog() const { return m_fileDialog; } static QString itemPath(IShellItem *item); - static QStringList libraryItemFolders(IShellItem *item); + static QList<QUrl> libraryItemFolders(IShellItem *item); static QString libraryItemDefaultSaveFolder(IShellItem *item); - static int itemPaths(IShellItemArray *items, QStringList *fileResult = 0); + static int itemPaths(IShellItemArray *items, QList<QUrl> *fileResult = 0); static IShellItem *shellItem(const QString &path); const QWindowsFileDialogSharedData &data() const { return m_data; } @@ -1031,9 +1017,9 @@ static IShellLibrary *sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode) } // Return all folders of a library-type item. -QStringList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *item) +QList<QUrl> QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *item) { - QStringList result; + QList<QUrl> result; if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) { IShellItemArray *itemArray = 0; if (SUCCEEDED(library->GetFolders(LFF_FORCEFILESYSTEM, IID_IShellItemArray, reinterpret_cast<void **>(&itemArray)))) { @@ -1062,9 +1048,9 @@ QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *i #else // !Q_OS_WINCE && __IShellLibrary_INTERFACE_DEFINED__ -QStringList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *) +QList<QUrl> QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *) { - return QStringList(); + return QList<QUrl>(); } QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *) @@ -1096,7 +1082,7 @@ QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item) } int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items, - QStringList *result /* = 0 */) + QList<QUrl> *result /* = 0 */) { DWORD itemCount = 0; if (result) @@ -1108,7 +1094,7 @@ int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items, for (DWORD i = 0; i < itemCount; ++i) { IShellItem *item = 0; if (SUCCEEDED(items->GetItemAt(i, &item))) - result->push_back(QWindowsNativeFileDialogBase::itemPath(item)); + result->push_back(QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item))); } } return itemCount; @@ -1270,7 +1256,7 @@ QString QWindowsNativeFileDialogBase::selectedNameFilter() const void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item) { if (item) { - const QString directory = QWindowsNativeFileDialogBase::itemPath(item); + const QUrl directory = QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item)); m_data.setDirectory(directory); emit directoryEntered(directory); } @@ -1278,7 +1264,7 @@ void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item) void QWindowsNativeFileDialogBase::onSelectionChange() { - const QStringList current = selectedFiles(); + const QList<QUrl> current = selectedFiles(); m_data.setSelectedFiles(current); if (current.size() == 1) emit currentChanged(current.front()); @@ -1338,8 +1324,8 @@ public: explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) : QWindowsNativeFileDialogBase(data) {} virtual void setNameFilters(const QStringList &f); - virtual QStringList selectedFiles() const; - virtual QStringList dialogResult() const; + virtual QList<QUrl> selectedFiles() const; + virtual QList<QUrl> dialogResult() const; }; // Return the first suffix from the name filter "Foo files (*.foo;*.bar)" -> "foo". @@ -1374,22 +1360,22 @@ void QWindowsNativeSaveFileDialog::setNameFilters(const QStringList &f) } // m_hasDefaultSuffix } -QStringList QWindowsNativeSaveFileDialog::dialogResult() const +QList<QUrl> QWindowsNativeSaveFileDialog::dialogResult() const { - QStringList result; + QList<QUrl> result; IShellItem *item = 0; if (SUCCEEDED(fileDialog()->GetResult(&item)) && item) - result.push_back(QWindowsNativeFileDialogBase::itemPath(item)); + result.push_back(QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item))); return result; } -QStringList QWindowsNativeSaveFileDialog::selectedFiles() const +QList<QUrl> QWindowsNativeSaveFileDialog::selectedFiles() const { - QStringList result; + QList<QUrl> result; IShellItem *item = 0; const HRESULT hr = fileDialog()->GetCurrentSelection(&item); if (SUCCEEDED(hr) && item) - result.push_back(QWindowsNativeSaveFileDialog::itemPath(item)); + result.push_back(QUrl::fromLocalFile(QWindowsNativeSaveFileDialog::itemPath(item))); return result; } @@ -1408,26 +1394,26 @@ class QWindowsNativeOpenFileDialog : public QWindowsNativeFileDialogBase public: explicit QWindowsNativeOpenFileDialog(const QWindowsFileDialogSharedData &data) : QWindowsNativeFileDialogBase(data) {} - virtual QStringList selectedFiles() const; - virtual QStringList dialogResult() const; + virtual QList<QUrl> selectedFiles() const; + virtual QList<QUrl> dialogResult() const; private: inline IFileOpenDialog *openFileDialog() const { return static_cast<IFileOpenDialog *>(fileDialog()); } }; -QStringList QWindowsNativeOpenFileDialog::dialogResult() const +QList<QUrl> QWindowsNativeOpenFileDialog::dialogResult() const { - QStringList result; + QList<QUrl> result; IShellItemArray *items = 0; if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) QWindowsNativeFileDialogBase::itemPaths(items, &result); return result; } -QStringList QWindowsNativeOpenFileDialog::selectedFiles() const +QList<QUrl> QWindowsNativeOpenFileDialog::selectedFiles() const { - QStringList result; + QList<QUrl> result; IShellItemArray *items = 0; const HRESULT hr = openFileDialog()->GetSelectedItems(&items); if (SUCCEEDED(hr) && items) @@ -1484,14 +1470,13 @@ public: virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return false; } virtual bool defaultNameFilterDisables() const { return true; } - virtual void setDirectory(const QString &directory); - virtual QString directory() const; - virtual void selectFile(const QString &filename); - virtual QStringList selectedFiles() const; - virtual void setFilter(); - virtual void setNameFilters(const QStringList &filters); - virtual void selectNameFilter(const QString &filter); - virtual QString selectedNameFilter() const; + virtual void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + virtual QUrl directory() const Q_DECL_OVERRIDE; + virtual void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; + virtual QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; + virtual void setFilter() Q_DECL_OVERRIDE; + virtual void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE; + virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; private: virtual QWindowsNativeDialogBase *createNativeDialog(); @@ -1509,10 +1494,10 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() return 0; QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept())); QObject::connect(result, SIGNAL(rejected()), this, SIGNAL(reject())); - QObject::connect(result, SIGNAL(directoryEntered(QString)), - this, SIGNAL(directoryEntered(QString))); - QObject::connect(result, SIGNAL(currentChanged(QString)), - this, SIGNAL(currentChanged(QString))); + QObject::connect(result, SIGNAL(directoryEntered(QUrl)), + this, SIGNAL(directoryEntered(QUrl))); + QObject::connect(result, SIGNAL(currentChanged(QUrl)), + this, SIGNAL(currentChanged(QUrl))); QObject::connect(result, SIGNAL(filterSelected(QString)), this, SIGNAL(filterSelected(QString))); @@ -1532,11 +1517,16 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() result->setLabelText(QFileDialogOptions::Accept, opts->labelText(QFileDialogOptions::Accept)); result->updateDirectory(); result->updateSelectedNameFilter(); - const QStringList initialSelection = opts->initiallySelectedFiles(); + const QList<QUrl> initialSelection = opts->initiallySelectedFiles(); if (initialSelection.size() > 0) { - QFileInfo info(initialSelection.front()); - if (!info.isDir()) - result->selectFile(info.fileName()); + const QUrl url = initialSelection.front(); + if (url.isLocalFile()) { + QFileInfo info(url.toLocalFile()); + if (!info.isDir()) + result->selectFile(info.fileName()); + } else { + result->selectFile(url.path()); // TODO url.fileName() once it exists + } } // No need to select initialNameFilter if mode is Dir if (mode != QFileDialogOptions::Directory && mode != QFileDialogOptions::DirectoryOnly) { @@ -1550,31 +1540,31 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() return result; } -void QWindowsFileDialogHelper::setDirectory(const QString &directory) +void QWindowsFileDialogHelper::setDirectory(const QUrl &directory) { if (QWindowsContext::verboseDialogs) - qDebug("%s %s" , __FUNCTION__, qPrintable(directory)); + qDebug("%s %s" , __FUNCTION__, qPrintable(directory.toString())); m_data.setDirectory(directory); if (hasNativeDialog()) nativeFileDialog()->updateDirectory(); } -QString QWindowsFileDialogHelper::directory() const +QUrl QWindowsFileDialogHelper::directory() const { return m_data.directory(); } -void QWindowsFileDialogHelper::selectFile(const QString &fileName) +void QWindowsFileDialogHelper::selectFile(const QUrl &fileName) { if (QWindowsContext::verboseDialogs) - qDebug("%s %s" , __FUNCTION__, qPrintable(fileName)); + qDebug("%s %s" , __FUNCTION__, qPrintable(fileName.toString())); if (QWindowsNativeFileDialogBase *nfd = nativeFileDialog()) - nfd->selectFile(fileName); + nfd->selectFile(fileName.toLocalFile()); // ## should use QUrl::fileName() once it exists } -QStringList QWindowsFileDialogHelper::selectedFiles() const +QList<QUrl> QWindowsFileDialogHelper::selectedFiles() const { return m_data.selectedFiles(); } @@ -1585,14 +1575,6 @@ void QWindowsFileDialogHelper::setFilter() qDebug("%s" , __FUNCTION__); } -void QWindowsFileDialogHelper::setNameFilters(const QStringList &filters) -{ - if (QWindowsContext::verboseDialogs) - qDebug("%s" , __FUNCTION__); - if (QWindowsNativeFileDialogBase *nfd = nativeFileDialog()) - nfd->setNameFilters(filters); -} - void QWindowsFileDialogHelper::selectNameFilter(const QString &filter) { m_data.setSelectedNameFilter(filter); @@ -1643,8 +1625,8 @@ private: explicit QWindowsXpNativeFileDialog(const OptionsPtr &options, const QWindowsFileDialogSharedData &data); void populateOpenFileName(OPENFILENAME *ofn, HWND owner) const; - QStringList execExistingDir(HWND owner); - QStringList execFileNames(HWND owner, int *selectedFilterIndex) const; + QList<QUrl> execExistingDir(HWND owner); + QList<QUrl> execFileNames(HWND owner, int *selectedFilterIndex) const; const OptionsPtr m_options; QString m_title; @@ -1683,7 +1665,7 @@ QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options void QWindowsXpNativeFileDialog::exec(HWND owner) { int selectedFilterIndex = -1; - const QStringList selectedFiles = + const QList<QUrl> selectedFiles = m_options->fileMode() == QFileDialogOptions::DirectoryOnly ? execExistingDir(owner) : execFileNames(owner, &selectedFilterIndex); m_data.setSelectedFiles(selectedFiles); @@ -1695,7 +1677,8 @@ void QWindowsXpNativeFileDialog::exec(HWND owner) const QStringList nameFilters = m_options->nameFilters(); if (selectedFilterIndex >= 0 && selectedFilterIndex < nameFilters.size()) m_data.setSelectedNameFilter(nameFilters.at(selectedFilterIndex)); - m_data.setDirectory(QFileInfo(selectedFiles.front()).absolutePath()); + QUrl firstFile = selectedFiles.front(); + m_data.setDirectory(firstFile.adjusted(QUrl::RemoveFilename)); m_result = QPlatformDialogHelper::Accepted; emit accepted(); } @@ -1722,7 +1705,7 @@ int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM case BFFM_INITIALIZED: { if (!m_title.isEmpty()) SetWindowText(hwnd, (wchar_t *)m_title.utf16()); - const QString initialFile = QDir::toNativeSeparators(m_data.directory()); + const QString initialFile = QDir::toNativeSeparators(m_data.directory().toLocalFile()); if (!initialFile.isEmpty()) SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initialFile.utf16())); } @@ -1738,7 +1721,7 @@ int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM return 0; } -QStringList QWindowsXpNativeFileDialog::execExistingDir(HWND owner) +QList<QUrl> QWindowsXpNativeFileDialog::execExistingDir(HWND owner) { BROWSEINFO bi; wchar_t initPath[MAX_PATH]; @@ -1750,12 +1733,12 @@ QStringList QWindowsXpNativeFileDialog::execExistingDir(HWND owner) bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE; bi.lpfn = xpFileDialogGetExistingDirCallbackProc; bi.lParam = LPARAM(this); - QStringList selectedFiles; + QList<QUrl> selectedFiles; if (qt_LpItemIdList pItemIDList = SHBrowseForFolder(&bi)) { wchar_t path[MAX_PATH]; path[0] = 0; if (SHGetPathFromIDList(pItemIDList, path) && path[0]) - selectedFiles.push_back(QDir::cleanPath(QString::fromWCharArray(path))); + selectedFiles.push_back(QUrl::fromLocalFile(QDir::cleanPath(QString::fromWCharArray(path)))); IMalloc *pMalloc; if (SHGetMalloc(&pMalloc) == NOERROR) { pMalloc->Free(pItemIDList); @@ -1807,7 +1790,7 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow QDir::toNativeSeparators(m_data.selectedFile()).remove(QLatin1Char('<')). remove(QLatin1Char('>')).remove(QLatin1Char('"')).remove(QLatin1Char('|')); ofn->lpstrFile = qStringToWCharArray(initiallySelectedFile, ofn->nMaxFile); - ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_data.directory())); + ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_data.directory().toLocalFile())); ofn->lpstrTitle = (wchar_t*)m_title.utf16(); // Determine lpstrDefExt. Note that the current MSDN docs document this // member wrong. It should rather be documented as "the default extension @@ -1832,25 +1815,27 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow ofn->Flags |= OFN_OVERWRITEPROMPT; } -QStringList QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedFilterIndex) const +QList<QUrl> QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedFilterIndex) const { *selectedFilterIndex = -1; OPENFILENAME ofn; populateOpenFileName(&ofn, owner); - QStringList result; + QList<QUrl> result; const bool isSave = m_options->acceptMode() == QFileDialogOptions::AcceptSave; if (isSave ? m_getSaveFileNameW(&ofn) : m_getOpenFileNameW(&ofn)) { *selectedFilterIndex = ofn.nFilterIndex - 1; - result.push_back(QDir::cleanPath(QString::fromWCharArray(ofn.lpstrFile))); + const QString dir = QDir::cleanPath(QString::fromWCharArray(ofn.lpstrFile)); + result.push_back(QUrl::fromLocalFile(dir)); // For multiselection, the first item is the path followed // by "\0<file1>\0<file2>\0\0". if (ofn.Flags & (OFN_ALLOWMULTISELECT)) { - wchar_t *ptr = ofn.lpstrFile + result.front().size() + 1; + wchar_t *ptr = ofn.lpstrFile + dir.size() + 1; if (*ptr) { - const QString path = result.takeAt(0) + QLatin1Char('/'); + result.pop_front(); + const QString path = dir + QLatin1Char('/'); while (*ptr) { const QString fileName = QString::fromWCharArray(ptr); - result.push_back(path + fileName); + result.push_back(QUrl::fromLocalFile(path + fileName)); ptr += fileName.size() + 1; } // extract multiple files } // has multiple files @@ -1879,14 +1864,13 @@ public: virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return false; } virtual bool defaultNameFilterDisables() const { return true; } - virtual void setDirectory(const QString &directory); - virtual QString directory() const; - virtual void selectFile(const QString &filename); - virtual QStringList selectedFiles() const; - virtual void setFilter() {} - virtual void setNameFilters(const QStringList &); - virtual void selectNameFilter(const QString &); - virtual QString selectedNameFilter() const; + virtual void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + virtual QUrl directory() const Q_DECL_OVERRIDE; + virtual void selectFile(const QUrl &url) Q_DECL_OVERRIDE; + virtual QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; + virtual void setFilter() Q_DECL_OVERRIDE {} + virtual void selectNameFilter(const QString &) Q_DECL_OVERRIDE; + virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; private: virtual QWindowsNativeDialogBase *createNativeDialog(); @@ -1907,31 +1891,26 @@ QWindowsNativeDialogBase *QWindowsXpFileDialogHelper::createNativeDialog() return 0; } -void QWindowsXpFileDialogHelper::setDirectory(const QString &directory) +void QWindowsXpFileDialogHelper::setDirectory(const QUrl &directory) { m_data.setDirectory(directory); // Dialog cannot be updated at run-time. } -QString QWindowsXpFileDialogHelper::directory() const +QUrl QWindowsXpFileDialogHelper::directory() const { return m_data.directory(); } -void QWindowsXpFileDialogHelper::selectFile(const QString &filename) +void QWindowsXpFileDialogHelper::selectFile(const QUrl &url) { - m_data.setSelectedFiles(QStringList(filename)); // Dialog cannot be updated at run-time. + m_data.setSelectedFiles(QList<QUrl>() << url); // Dialog cannot be updated at run-time. } -QStringList QWindowsXpFileDialogHelper::selectedFiles() const +QList<QUrl> QWindowsXpFileDialogHelper::selectedFiles() const { return m_data.selectedFiles(); } -void QWindowsXpFileDialogHelper::setNameFilters(const QStringList &) -{ - // Dialog cannot be updated at run-time. -} - void QWindowsXpFileDialogHelper::selectNameFilter(const QString &f) { m_data.setSelectedNameFilter(f); // Dialog cannot be updated at run-time. @@ -1984,7 +1963,7 @@ private: QWindowsNativeColorDialog::QWindowsNativeColorDialog(const SharedPointerColor &color) : m_code(QPlatformDialogHelper::Rejected), m_color(color) { - qFill(m_customColors, m_customColors + 16, COLORREF(0)); + std::fill(m_customColors, m_customColors + 16, COLORREF(0)); } void QWindowsNativeColorDialog::exec(HWND owner) diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h index 7884f398f3..c0ee60cc1e 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h @@ -72,7 +72,6 @@ public: Qt::WindowModality windowModality, QWindow *parent); virtual void hide(); - virtual QVariant styleHint(QPlatformDialogHelper::StyleHint) const; virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index b7ccb5767e..a6bce6502b 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -838,8 +838,6 @@ error: return i18n_name; } -Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); - static bool addFontToDatabase(const QString &familyName, uchar charSet, const TEXTMETRIC *textmetric, const FONTSIGNATURE *signature, @@ -932,7 +930,7 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet, QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, 0); if (!englishName.isEmpty()) - qt_registerAliasToFontFamily(familyName, englishName); + QPlatformFontDatabase::registerAliasToFontFamily(familyName, englishName); return true; } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 7f97d58be4..6037c201ac 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -122,8 +122,6 @@ static FontFile * createFontFile(const QString &fileName, int index) extern bool localizedName(const QString &name); extern QString getEnglishName(const QString &familyName); -Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias); - static bool addFontToDatabase(const QString &familyName, uchar charSet, const TEXTMETRIC *textmetric, const FONTSIGNATURE *signature, @@ -304,7 +302,7 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet, antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); if (!englishName.isEmpty()) - qt_registerAliasToFontFamily(faceName, englishName); + QPlatformFontDatabase::registerAliasToFontFamily(faceName, englishName); return true; } diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index 33ddcaffc5..64457f4b67 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -1133,8 +1133,10 @@ QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, << "If you need them anyway, start your application with -platform windows:fontengine=freetype."; } #endif // wince - QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin + 4, - ih + 2 * margin + 4, + + // The padding here needs to be kept in sync with the values in alphaMapBoundingBox. + QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin, + ih + 2 * margin, QWindowsNativeImage::systemFormat()); /*If cleartype is enabled we use the standard system format even on Windows CE @@ -1167,6 +1169,17 @@ QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, return ni; } +glyph_metrics_t QWindowsFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat format) +{ + int margin = 0; + if (format == QFontEngine::Format_A32 || format == QFontEngine::Format_ARGB) + margin = glyphMargin(QFontEngineGlyphCache::Raster_RGBMask); + glyph_metrics_t gm = boundingBox(glyph, matrix); + gm.width += margin * 2; + gm.height += margin * 2; + return gm; +} + QImage QWindowsFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &xform) { HFONT font = hfont; diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h index 9e92a8fbff..60ff61fcb9 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.h +++ b/src/plugins/platforms/windows/qwindowsfontengine.h @@ -121,6 +121,7 @@ public: virtual QImage alphaMapForGlyph(glyph_t t) { return alphaMapForGlyph(t, QTransform()); } virtual QImage alphaMapForGlyph(glyph_t, const QTransform &xform); virtual QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform); + virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat); virtual QFontEngine *cloneWithSize(qreal pixelSize) const; virtual bool supportsTransformation(const QTransform &transform) const; diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp index c0f1b3a000..7407d88f8b 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -215,7 +215,9 @@ QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *di if (QWindowsContext::verboseFonts) qDebug("%s %g", __FUNCTION__, pixelSize); - d->directWriteFactory->AddRef(); + Q_ASSERT(m_directWriteFontFace); + + m_fontEngineData->directWriteFactory->AddRef(); m_directWriteFontFace->AddRef(); fontDef.pixelSize = pixelSize; @@ -237,19 +239,17 @@ QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite() void QWindowsFontEngineDirectWrite::collectMetrics() { - if (m_directWriteFontFace != 0) { - DWRITE_FONT_METRICS metrics; - - m_directWriteFontFace->GetMetrics(&metrics); - m_unitsPerEm = metrics.designUnitsPerEm; - - m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); - m_ascent = DESIGN_TO_LOGICAL(metrics.ascent); - m_descent = DESIGN_TO_LOGICAL(metrics.descent); - m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight); - m_lineGap = DESIGN_TO_LOGICAL(metrics.lineGap); - m_underlinePosition = DESIGN_TO_LOGICAL(metrics.underlinePosition); - } + DWRITE_FONT_METRICS metrics; + + m_directWriteFontFace->GetMetrics(&metrics); + m_unitsPerEm = metrics.designUnitsPerEm; + + m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); + m_ascent = DESIGN_TO_LOGICAL(metrics.ascent); + m_descent = DESIGN_TO_LOGICAL(metrics.descent); + m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight); + m_lineGap = DESIGN_TO_LOGICAL(metrics.lineGap); + m_underlinePosition = DESIGN_TO_LOGICAL(metrics.underlinePosition); } QFixed QWindowsFontEngineDirectWrite::underlinePosition() const @@ -272,31 +272,24 @@ bool QWindowsFontEngineDirectWrite::getSfntTableData(uint tag, uchar *buffer, ui { bool ret = false; - if (m_directWriteFontFace) { - DWORD t = qbswap<quint32>(tag); - - const void *tableData = 0; - void *tableContext = 0; - UINT32 tableSize; - BOOL exists; - HRESULT hr = m_directWriteFontFace->TryGetFontTable( - t, &tableData, &tableSize, &tableContext, &exists - ); - - if (SUCCEEDED(hr)) { - if (exists) { - if (!buffer) { - *length = tableSize; - ret = true; - } else if (*length >= tableSize) { - memcpy(buffer, tableData, tableSize); - ret = true; - } - } - m_directWriteFontFace->ReleaseFontTable(tableContext); - } else { - qErrnoWarning("%s: TryGetFontTable failed", __FUNCTION__); + const void *tableData = 0; + UINT32 tableSize; + void *tableContext = 0; + BOOL exists; + HRESULT hr = m_directWriteFontFace->TryGetFontTable(qbswap<quint32>(tag) + &tableData, &tableSize, + &tableContext, &exists); + if (SUCCEEDED(hr)) { + if (exists) { + ret = true; + if (buffer && *length >= tableSize) + memcpy(buffer, tableData, tableSize); + else + *length = tableSize; } + m_directWriteFontFace->ReleaseFontTable(tableContext); + } else { + qErrnoWarning("%s: TryGetFontTable failed", __FUNCTION__); } return ret; @@ -327,43 +320,43 @@ inline unsigned int getChar(const QChar *str, int &i, const int len) bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const { - if (m_directWriteFontFace != 0) { - QVarLengthArray<UINT32> codePoints(len); - for (int i=0; i<len; ++i) { - codePoints[i] = getChar(str, i, len); - if (flags & QFontEngine::RightToLeft) - codePoints[i] = QChar::mirroredChar(codePoints[i]); - } + if (*nglyphs < len) { + *nglyphs = len; + return false; + } - QVarLengthArray<UINT16> glyphIndices(len); - HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(), - len, - glyphIndices.data()); + QVarLengthArray<UINT32> codePoints(len); + int actualLength = 0; + if (flags & QFontEngine::RightToLeft) { + for (int i = 0; i < len; ++i) + codePoints[actualLength++] = QChar::mirroredChar(getChar(str, i, len)); + } else { + for (int i = 0; i < len; ++i) + codePoints[actualLength++] = getChar(str, i, len); + } - if (SUCCEEDED(hr)) { - for (int i=0; i<len; ++i) - glyphs->glyphs[i] = glyphIndices[i]; + QVarLengthArray<UINT16> glyphIndices(actualLength); + HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(), actualLength, + glyphIndices.data()); + if (FAILED(hr)) { + qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__); + return false; + } - *nglyphs = len; - glyphs->numGlyphs = len; + for (int i = 0; i < actualLength; ++i) + glyphs->glyphs[i] = glyphIndices.at(i); - if (!(flags & GlyphIndicesOnly)) - recalcAdvances(glyphs, 0); + *nglyphs = actualLength; + glyphs->numGlyphs = actualLength; - return true; - } else { - qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__); - } - } + if (!(flags & GlyphIndicesOnly)) + recalcAdvances(glyphs, 0); - return false; + return true; } void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const { - if (m_directWriteFontFace == 0) - return; - QVarLengthArray<UINT16> glyphIndices(glyphs->numGlyphs); // ### Caching? @@ -391,9 +384,6 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn void QWindowsFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags) { - if (m_directWriteFontFace == 0) - return; - QVarLengthArray<UINT16> glyphIndices(nglyphs); QVarLengthArray<DWRITE_GLYPH_OFFSET> glyphOffsets(nglyphs); QVarLengthArray<FLOAT> glyphAdvances(nglyphs); @@ -439,9 +429,6 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(const QGlyphLayout &g glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(glyph_t g) { - if (m_directWriteFontFace == 0) - return glyph_metrics_t(); - UINT16 glyphIndex = g; DWRITE_GLYPH_METRICS glyphMetrics; @@ -668,14 +655,14 @@ bool QWindowsFontEngineDirectWrite::canRender(const QChar *string, int len) if (FAILED(hr)) { qErrnoWarning("%s: GetGlyphIndices failed", __FUNCTION__); return false; - } else { - for (int i=0; i<glyphIndices.size(); ++i) { - if (glyphIndices.at(i) == 0) - return false; - } + } - return true; + for (int i = 0; i < actualLength; ++i) { + if (glyphIndices.at(i) == 0) + return false; } + + return true; } QFontEngine::Type QWindowsFontEngineDirectWrite::type() const diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index 106087f757..ab14cb49eb 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -107,8 +107,6 @@ public: static QString fontNameSubstitute(const QString &familyName); private: - friend class QRawFontPrivate; - QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform); void collectMetrics(); diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index f6dda04c13..d1ede39549 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -49,6 +49,8 @@ #include <QtGui/QGuiApplication> #include <qpa/qplatformnativeinterface.h> +#include <algorithm> + #include <wingdi.h> #include <GL/gl.h> @@ -377,7 +379,7 @@ static int choosePixelFormat(HDC hdc, return 0; int iAttributes[attribSize]; - qFill(iAttributes, iAttributes + attribSize, int(0)); + std::fill(iAttributes, iAttributes + attribSize, int(0)); int i = 0; iAttributes[i++] = WGL_ACCELERATION_ARB; iAttributes[i++] = testFlag(additional.formatFlags, QWindowsGLDirectRendering) ? @@ -505,8 +507,8 @@ static QSurfaceFormat return result; int iAttributes[attribSize]; int iValues[attribSize]; - qFill(iAttributes, iAttributes + attribSize, int(0)); - qFill(iValues, iValues + attribSize, int(0)); + std::fill(iAttributes, iAttributes + attribSize, int(0)); + std::fill(iValues, iValues + attribSize, int(0)); int i = 0; const bool hasSampleBuffers = testFlag(staticContext.extensions, QOpenGLStaticContext::SampleBuffers); @@ -567,7 +569,7 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, return 0; int attributes[attribSize]; int attribIndex = 0; - qFill(attributes, attributes + attribSize, int(0)); + std::fill(attributes, attributes + attribSize, int(0)); // We limit the requested version by the version of the static context as // wglCreateContextAttribsARB fails and returns NULL if the requested context diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp new file mode 100644 index 0000000000..4a5d7b5a78 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -0,0 +1,473 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowstabletsupport.h" + +#ifndef QT_NO_TABLETEVENT + +#include "qwindowscontext.h" +#include "qwindowskeymapper.h" +#include "qwindowswindow.h" + +#include <qpa/qwindowsysteminterface.h> + +#include <QtGui/QTabletEvent> +#include <QtGui/QScreen> +#include <QtGui/QGuiApplication> +#include <QtGui/QWindow> +#include <QtCore/QDebug> +#include <QtCore/QScopedArrayPointer> +#include <QtCore/QtMath> + +#include <private/qguiapplication_p.h> +#include <QtCore/private/qsystemlibrary_p.h> + +// Note: The definition of the PACKET structure in pktdef.h depends on this define. +#define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_Z) +#include <pktdef.h> + +QT_BEGIN_NAMESPACE + +enum { + PacketMode = 0, + TabletPacketQSize = 128, + DeviceIdMask = 0xFF6, // device type mask && device color mask + CursorTypeBitMask = 0x0F06 // bitmask to find the specific cursor type (see Wacom FAQ) +}; + +extern "C" LRESULT QT_WIN_CALLBACK qWindowsTabletSupportWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WT_PROXIMITY: + if (QWindowsContext::instance()->tabletSupport()->translateTabletProximityEvent(wParam, lParam)) + return 0; + break; + case WT_PACKET: + if (QWindowsContext::instance()->tabletSupport()->translateTabletPacketEvent()) + return 0; + break; + } + return DefWindowProc(hwnd, message, wParam, lParam); +} + + +// Scale tablet coordinates to screen coordinates. + +static inline int sign(int x) +{ + return x >= 0 ? 1 : -1; +} + +inline QPointF QWindowsTabletDeviceData::scaleCoordinates(int coordX, int coordY, const QRect &targetArea) const +{ + const int targetX = targetArea.x(); + const int targetY = targetArea.y(); + const int targetWidth = targetArea.width(); + const int targetHeight = targetArea.height(); + + const qreal x = sign(targetWidth) == sign(maxX) ? + ((coordX - minX) * qAbs(targetWidth) / qAbs(qreal(maxX - minX))) + targetX : + ((qAbs(maxX) - (coordX - minX)) * qAbs(targetWidth) / qAbs(qreal(maxX - minX))) + targetX; + + const qreal y = sign(targetHeight) == sign(maxY) ? + ((coordY - minY) * qAbs(targetHeight) / qAbs(qreal(maxY - minY))) + targetY : + ((qAbs(maxY) - (coordY - minY)) * qAbs(targetHeight) / qAbs(qreal(maxY - minY))) + targetY; + + return QPointF(x, y); +} + +QWindowsWinTab32DLL QWindowsTabletSupport::m_winTab32DLL; + +/*! + \class QWindowsWinTab32DLL QWindowsTabletSupport + \brief Functions from wintabl32.dll shipped with WACOM tablets used by QWindowsTabletSupport. + + \internal + \ingroup qt-lighthouse-win +*/ + +bool QWindowsWinTab32DLL::init() +{ + if (wTInfo) + return true; + QSystemLibrary library(QStringLiteral("wintab32")); + if (!library.load()) + return false; + wTOpen = (PtrWTOpen)library.resolve("WTOpenW"); + wTClose = (PtrWTClose)library.resolve("WTClose"); + wTInfo = (PtrWTInfo)library.resolve("WTInfoW"); + wTEnable = (PtrWTEnable)library.resolve("WTEnable"); + wTOverlap = (PtrWTEnable)library.resolve("WTOverlap"); + wTPacketsGet = (PtrWTPacketsGet)library.resolve("WTPacketsGet"); + wTGet = (PtrWTGet)library.resolve("WTGetW"); + wTQueueSizeGet = (PtrWTQueueSizeGet)library.resolve("WTQueueSizeGet"); + wTQueueSizeSet = (PtrWTQueueSizeSet)library.resolve("WTQueueSizeSet"); + return wTOpen && wTClose && wTInfo && wTEnable && wTOverlap && wTPacketsGet && wTQueueSizeGet && wTQueueSizeSet; +} + +/*! + \class QWindowsTabletSupport + \brief Tablet support for Windows. + + Support for WACOM tablets. + + \sa http://www.wacomeng.com/windows/docs/Wintab_v140.htm + + \internal + \since 5.2 + \ingroup qt-lighthouse-win +*/ + +QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context) + : m_window(window) + , m_context(context) + , m_tiltSupport(false) + , m_currentDevice(-1) +{ + AXIS orientation[3]; + // Some tablets don't support tilt, check if it is possible, + if (QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES, DVC_ORIENTATION, &orientation)) + m_tiltSupport = orientation[0].axResolution && orientation[1].axResolution; +} + +QWindowsTabletSupport::~QWindowsTabletSupport() +{ + QWindowsTabletSupport::m_winTab32DLL.wTClose(m_context); + DestroyWindow(m_window); +} + +QWindowsTabletSupport *QWindowsTabletSupport::create() +{ + if (!m_winTab32DLL.init()) + return 0; + const HWND window = QWindowsContext::instance()->createDummyWindow(QStringLiteral("TabletDummyWindow"), + L"TabletDummyWindow", + qWindowsTabletSupportWndProc); + if (!window) { + if (QWindowsContext::verboseTablet) + qWarning() << __FUNCTION__ << "Unable to create window for tablet."; + return 0; + } + LOGCONTEXT lcMine; + // build our context from the default context + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEFSYSCTX, 0, &lcMine); + // Go for the raw coordinates, the tablet event will return good stuff + lcMine.lcOptions |= CXO_MESSAGES | CXO_CSRMESSAGES; + lcMine.lcPktData = lcMine.lcMoveMask = PACKETDATA; + lcMine.lcPktMode = PacketMode; + lcMine.lcOutOrgX = 0; + lcMine.lcOutExtX = lcMine.lcInExtX; + lcMine.lcOutOrgY = 0; + lcMine.lcOutExtY = -lcMine.lcInExtY; + const HCTX context = QWindowsTabletSupport::m_winTab32DLL.wTOpen(window, &lcMine, true); + if (!context) { + if (QWindowsContext::verboseTablet) + qWarning() << __FUNCTION__ << "Unable to open tablet."; + DestroyWindow(window); + return 0; + + } + // Set the size of the Packet Queue to the correct size + const int currentQueueSize = QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeGet(context); + if (currentQueueSize != TabletPacketQSize) { + if (!QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeSet(context, TabletPacketQSize)) { + if (!QWindowsTabletSupport::m_winTab32DLL.wTQueueSizeSet(context, currentQueueSize)) { + qWarning() << "Unable to set queue size on tablet. The tablet will not work."; + QWindowsTabletSupport::m_winTab32DLL.wTClose(context); + DestroyWindow(window); + return 0; + } // cannot restore old size + } // cannot set + } // mismatch + if (QWindowsContext::verboseTablet) + qDebug("Opened tablet context %p on window %p, changed packet queue size %d -> %d", + context, window, currentQueueSize, TabletPacketQSize); + return new QWindowsTabletSupport(window, context); +} + +unsigned QWindowsTabletSupport::options() const +{ + UINT result = 0; + m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_CTXOPTIONS, &result); + return result; +} + +QString QWindowsTabletSupport::description() const +{ + const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, 0); + if (!size) + return QString(); + QScopedPointer<TCHAR> winTabId(new TCHAR[size + 1]); + m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, winTabId.data()); + WORD implementationVersion = 0; + m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_IMPLVERSION, &implementationVersion); + WORD specificationVersion = 0; + m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_SPECVERSION, &specificationVersion); + const unsigned opts = options(); + QString result = QString::fromLatin1("%1 specification: v%2.%3 implementation: v%4.%5 options: 0x%6") + .arg(QString::fromWCharArray(winTabId.data())) + .arg(specificationVersion >> 8).arg(specificationVersion & 0xFF) + .arg(implementationVersion >> 8).arg(implementationVersion & 0xFF) + .arg(opts, 0, 16); + if (opts & CXO_MESSAGES) + result += QStringLiteral(" CXO_MESSAGES"); + if (opts & CXO_CSRMESSAGES) + result += QStringLiteral(" CXO_CSRMESSAGES"); + if (m_tiltSupport) + result += QStringLiteral(" tilt"); + return result; +} + +void QWindowsTabletSupport::notifyActivate() +{ + // Cooperate with other tablet applications, but when we get focus, I want to use the tablet. + const bool result = QWindowsTabletSupport::m_winTab32DLL.wTEnable(m_context, true) + && QWindowsTabletSupport::m_winTab32DLL.wTOverlap(m_context, true); + if (QWindowsContext::verboseTablet) + qDebug() << __FUNCTION__ << result; +} + +static inline int indexOfDevice(const QVector<QWindowsTabletDeviceData> &devices, qint64 uniqueId) +{ + for (int i = 0; i < devices.size(); ++i) + if (devices.at(i).uniqueId == uniqueId) + return i; + return -1; +} + +static inline QTabletEvent::TabletDevice deviceType(const UINT cursorType) +{ + if (((cursorType & 0x0006) == 0x0002) && ((cursorType & CursorTypeBitMask) != 0x0902)) + return QTabletEvent::Stylus; + switch (cursorType & CursorTypeBitMask) { + case 0x0802: + return QTabletEvent::Stylus; + case 0x0902: + return QTabletEvent::Airbrush; + case 0x0004: + return QTabletEvent::FourDMouse; + case 0x0006: + return QTabletEvent::Puck; + case 0x0804: + return QTabletEvent::RotationStylus; + default: + break; + } + return QTabletEvent::NoDevice; +} + +static inline QTabletEvent::PointerType pointerType(unsigned currentCursor) +{ + switch (currentCursor % 3) { // %3 for dual track + case 0: + return QTabletEvent::Cursor; + case 1: + return QTabletEvent::Pen; + case 2: + return QTabletEvent::Eraser; + default: + break; + } + return QTabletEvent::UnknownPointer; +} + +QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t) +{ + d << "TabletDevice id:" << t.uniqueId << " pressure: " << t.minPressure + << ".." << t.maxPressure << " tan pressure: " << t.minTanPressure << ".." + << t.maxTanPressure << " area:" << t.minX << t.minY <<t.minZ + << ".." << t.maxX << t.maxY << t.maxZ << " device " << t.currentDevice + << " pointer " << t.currentPointerType; + return d; +} + +QWindowsTabletDeviceData QWindowsTabletSupport::tabletInit(const quint64 uniqueId, const UINT cursorType) const +{ + QWindowsTabletDeviceData result; + result.uniqueId = uniqueId; + /* browse WinTab's many info items to discover pressure handling. */ + AXIS axis; + LOGCONTEXT lc; + /* get the current context for its device variable. */ + QWindowsTabletSupport::m_winTab32DLL.wTGet(m_context, &lc); + /* get the size of the pressure axis. */ + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES + lc.lcDevice, DVC_NPRESSURE, &axis); + result.minPressure = int(axis.axMin); + result.maxPressure = int(axis.axMax); + + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEVICES + lc.lcDevice, DVC_TPRESSURE, &axis); + result.minTanPressure = int(axis.axMin); + result.maxTanPressure = int(axis.axMax); + + LOGCONTEXT defaultLc; + /* get default region */ + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_DEFCONTEXT, 0, &defaultLc); + result.maxX = int(defaultLc.lcInExtX) - int(defaultLc.lcInOrgX); + result.maxY = int(defaultLc.lcInExtY) - int(defaultLc.lcInOrgY); + result.maxZ = int(defaultLc.lcInExtZ) - int(defaultLc.lcInOrgZ); + result.currentDevice = deviceType(cursorType); + return result; +} + +bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, LPARAM lParam) +{ + const bool enteredProximity = LOWORD(lParam) != 0; + PACKET proximityBuffer[1]; // we are only interested in the first packet in this case + const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, 1, proximityBuffer); + if (!totalPacks) + return false; + const UINT currentCursor = proximityBuffer[0].pkCursor; + UINT physicalCursorId; + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId); + UINT cursorType; + QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_TYPE, &cursorType); + const qint64 uniqueId = (qint64(cursorType & DeviceIdMask) << 32L) | qint64(physicalCursorId); + // initializing and updating the cursor should be done in response to + // WT_CSRCHANGE. We do it in WT_PROXIMITY because some wintab never send + // the event WT_CSRCHANGE even if asked with CXO_CSRMESSAGES + m_currentDevice = indexOfDevice(m_devices, uniqueId); + if (m_currentDevice < 0) { + m_currentDevice = m_devices.size(); + m_devices.push_back(tabletInit(uniqueId, cursorType)); + } + m_devices[m_currentDevice].currentPointerType = pointerType(currentCursor); + if (QWindowsContext::verboseTablet) + qDebug() << __FUNCTION__ << (enteredProximity ? "enter" : "leave") + << " proximity for device #" + << m_currentDevice << m_devices.at(m_currentDevice); + if (enteredProximity) { + QWindowSystemInterface::handleTabletEnterProximityEvent(m_devices.at(m_currentDevice).currentDevice, + m_devices.at(m_currentDevice).currentPointerType, + m_devices.at(m_currentDevice).uniqueId); + } else { + QWindowSystemInterface::handleTabletLeaveProximityEvent(m_devices.at(m_currentDevice).currentDevice, + m_devices.at(m_currentDevice).currentPointerType, + m_devices.at(m_currentDevice).uniqueId); + } + return true; +} + +bool QWindowsTabletSupport::translateTabletPacketEvent() +{ + static PACKET localPacketBuf[TabletPacketQSize]; // our own tablet packet queue. + const int packetCount = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, TabletPacketQSize, &localPacketBuf); + if (!packetCount || m_currentDevice < 0) + return false; + + const int currentDevice = m_devices.at(m_currentDevice).currentDevice; + const int currentPointer = m_devices.at(m_currentDevice).currentPointerType; + + // When entering proximity, the tablet driver snaps the mouse pointer to the + // tablet position scaled to the virtual desktop and keeps it in sync. + const QRect virtualDesktopArea = QGuiApplication::primaryScreen()->virtualGeometry(); + + if (QWindowsContext::verboseTablet) + qDebug() << __FUNCTION__ << "processing " << packetCount + << "target:" << QGuiApplicationPrivate::tabletPressTarget; + + const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); + + for (int i = 0; i < packetCount ; ++i) { + const PACKET &packet = localPacketBuf[i]; + + const int z = currentDevice == QTabletEvent::FourDMouse ? int(packet.pkZ) : 0; + const QPointF globalPosF = m_devices.at(m_currentDevice).scaleCoordinates(packet.pkX, packet.pkY, virtualDesktopArea); + + QWindow *target = QGuiApplicationPrivate::tabletPressTarget; // Pass to window that grabbed it. + const QPoint globalPos = globalPosF.toPoint(); + if (!target) + if (QPlatformWindow *pw = QWindowsContext::instance()->findPlatformWindowAt(GetDesktopWindow(), globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT)) + target = pw->window(); + if (!target) + continue; + + const QPoint localPos = target->mapFromGlobal(globalPos); + + const qreal pressureNew = packet.pkButtons && (currentPointer == QTabletEvent::Pen || currentPointer == QTabletEvent::Eraser) ? + m_devices.at(m_currentDevice).scalePressure(packet.pkNormalPressure) : + qreal(0); + const qreal tangentialPressure = currentDevice == QTabletEvent::Airbrush ? + m_devices.at(m_currentDevice).scaleTangentialPressure(packet.pkTangentPressure) : + qreal(0); + + int tiltX = 0; + int tiltY = 0; + qreal rotation = 0; + if (m_tiltSupport) { + // Convert from azimuth and altitude to x tilt and y tilt. What + // follows is the optimized version. Here are the equations used: + // X = sin(azimuth) * cos(altitude) + // Y = cos(azimuth) * cos(altitude) + // Z = sin(altitude) + // X Tilt = arctan(X / Z) + // Y Tilt = arctan(Y / Z) + const double radAzim = (packet.pkOrientation.orAzimuth / 10) * (M_PI / 180); + const double tanAlt = tan((abs(packet.pkOrientation.orAltitude / 10)) * (M_PI / 180)); + + const double degX = atan(sin(radAzim) / tanAlt); + const double degY = atan(cos(radAzim) / tanAlt); + tiltX = int(degX * (180 / M_PI)); + tiltY = int(-degY * (180 / M_PI)); + rotation = packet.pkOrientation.orTwist; + } + + if (QWindowsContext::verboseTablet > 1) { + qDebug() + << "Packet #" << i << '/' << packetCount << "button:" << packet.pkButtons + << globalPosF << z << "to:" << target << localPos << "(packet" << packet.pkX + << packet.pkY << ") dev:" << currentDevice << "pointer:" + << currentPointer << "P:" << pressureNew << "tilt:" << tiltX << ',' + << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; + } + + QWindowSystemInterface::handleTabletEvent(target, packet.pkButtons, localPos, globalPosF, + currentDevice, currentPointer, + pressureNew, tiltX, tiltY, + tangentialPressure, rotation, z, + m_devices.at(m_currentDevice).uniqueId, + keyboardModifiers); + } + return true; +} + +QT_END_NAMESPACE + +#endif // QT_NO_TABLETEVENT diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h new file mode 100644 index 0000000000..12f96b618d --- /dev/null +++ b/src/plugins/platforms/windows/qwindowstabletsupport.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSTABLETSUPPORT_H +#define QWINDOWSTABLETSUPPORT_H + +#include "qtwindowsglobal.h" + +#if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) + +#include <QtCore/QVector> +#include <QtCore/QPointF> + +#include <wintab.h> + +QT_BEGIN_NAMESPACE + +class QDebug; +class QWindow; +class QRect; + +struct QWindowsWinTab32DLL +{ + QWindowsWinTab32DLL() : wTOpen(0), wTClose(0), wTInfo(0), wTEnable(0), wTOverlap(0), wTPacketsGet(0), wTGet(0), + wTQueueSizeGet(0), wTQueueSizeSet(0) {} + + bool init(); + + typedef HCTX (API *PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL); + typedef BOOL (API *PtrWTClose)(HCTX); + typedef UINT (API *PtrWTInfo)(UINT, UINT, LPVOID); + typedef BOOL (API *PtrWTEnable)(HCTX, BOOL); + typedef BOOL (API *PtrWTOverlap)(HCTX, BOOL); + typedef int (API *PtrWTPacketsGet)(HCTX, int, LPVOID); + typedef BOOL (API *PtrWTGet)(HCTX, LPLOGCONTEXT); + typedef int (API *PtrWTQueueSizeGet)(HCTX); + typedef BOOL (API *PtrWTQueueSizeSet)(HCTX, int); + + PtrWTOpen wTOpen; + PtrWTClose wTClose; + PtrWTInfo wTInfo; + PtrWTEnable wTEnable; + PtrWTOverlap wTOverlap; + PtrWTPacketsGet wTPacketsGet; + PtrWTGet wTGet; + PtrWTQueueSizeGet wTQueueSizeGet; + PtrWTQueueSizeSet wTQueueSizeSet; +}; + +struct QWindowsTabletDeviceData +{ + QWindowsTabletDeviceData() : minPressure(0), maxPressure(0), minTanPressure(0), + maxTanPressure(0), minX(0), maxX(0), minY(0), maxY(0), minZ(0), maxZ(0), + uniqueId(0), currentDevice(0), currentPointerType(0) {} + + QPointF scaleCoordinates(int coordX, int coordY,const QRect &targetArea) const; + qreal scalePressure(qreal p) const { return p / qreal(maxPressure - minPressure); } + qreal scaleTangentialPressure(qreal p) const { return p / qreal(maxTanPressure - minTanPressure); } + + int minPressure; + int maxPressure; + int minTanPressure; + int maxTanPressure; + int minX, maxX, minY, maxY, minZ, maxZ; + qint64 uniqueId; + int currentDevice; + int currentPointerType; +}; + +QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t); + +class QWindowsTabletSupport +{ + Q_DISABLE_COPY(QWindowsTabletSupport) + + explicit QWindowsTabletSupport(HWND window, HCTX context); + +public: + ~QWindowsTabletSupport(); + + static QWindowsTabletSupport *create(); + + void notifyActivate(); + QString description() const; + + bool translateTabletProximityEvent(WPARAM wParam, LPARAM lParam); + bool translateTabletPacketEvent(); + +private: + unsigned options() const; + QWindowsTabletDeviceData tabletInit(const quint64 uniqueId, const UINT cursorType) const; + + static QWindowsWinTab32DLL m_winTab32DLL; + const HWND m_window; + const HCTX m_context; + bool m_tiltSupport; + QVector<QWindowsTabletDeviceData> m_devices; + int m_currentDevice; +}; + +QT_END_NAMESPACE + +#endif // !QT_NO_TABLETEVENT && !Q_OS_WINCE +#endif // QWINDOWSTABLETSUPPORT_H diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 9f6e6b18e7..49fdfc15b8 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -54,6 +54,11 @@ #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" # include "winuser.h" +#else +# include <commctrl.h> +# include <objbase.h> +# include <commoncontrols.h> +# include <shellapi.h> #endif #include <QtCore/QVariant> @@ -69,6 +74,12 @@ #include <qpa/qwindowsysteminterface.h> #include <private/qsystemlibrary_p.h> +#include <algorithm> + +#if defined(__IImageList_INTERFACE_DEFINED__) && defined(__IID_DEFINED__) +# define USE_IIMAGELIST +#endif + QT_BEGIN_NAMESPACE static inline QTextStream& operator<<(QTextStream &str, const QColor &c) @@ -290,8 +301,8 @@ QWindowsTheme *QWindowsTheme::m_instance = 0; QWindowsTheme::QWindowsTheme() { m_instance = this; - qFill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); - qFill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); + std::fill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); + std::fill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); refresh(); } @@ -361,8 +372,15 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const case IconPixmapSizes: { QList<int> sizes; sizes << 16 << 32; +#ifdef USE_IIMAGELIST + sizes << 48; // sHIL_EXTRALARGE + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA) + sizes << 256; // SHIL_JUMBO +#endif // USE_IIMAGELIST return QVariant::fromValue(sizes); } + case DialogSnapToDefaultButton: + return QVariant(booleanSystemParametersInfo(SPI_GETSNAPTODEFBUTTON, false)); default: break; } @@ -372,7 +390,7 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const void QWindowsTheme::clearPalettes() { qDeleteAll(m_palettes, m_palettes + NPalettes); - qFill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); + std::fill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); } void QWindowsTheme::refreshPalettes() @@ -393,7 +411,7 @@ void QWindowsTheme::refreshPalettes() void QWindowsTheme::clearFonts() { qDeleteAll(m_fonts, m_fonts + NFonts); - qFill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); + std::fill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0)); } void QWindowsTheme::refreshFonts() @@ -410,6 +428,8 @@ void QWindowsTheme::refreshFonts() const QFont messageBoxFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont); const QFont statusFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfStatusFont); const QFont titleFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfCaptionFont); + QFont fixedFont(QStringLiteral("Courier New"), messageBoxFont.pointSize()); + fixedFont.setStyleHint(QFont::TypeWriter); LOGFONT lfIconTitleFont; SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); @@ -424,6 +444,7 @@ void QWindowsTheme::refreshFonts() m_fonts[MdiSubWindowTitleFont] = new QFont(titleFont); m_fonts[DockWidgetTitleFont] = new QFont(titleFont); m_fonts[ItemViewFont] = new QFont(iconTitleFont); + m_fonts[FixedFont] = new QFont(fixedFont); if (QWindowsContext::verboseTheming) qDebug() << __FUNCTION__ << '\n' @@ -573,11 +594,24 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) con return QPlatformTheme::standardPixmap(sp, size); } -static QString dirIconPixmapCacheKey(int iIcon, int iconSize) +enum { // Shell image list ids + sHIL_EXTRALARGE = 0x2, // 48x48 or user-defined + sHIL_JUMBO = 0x4 // 256x256 (Vista or later) +}; + +static QString dirIconPixmapCacheKey(int iIcon, int iconSize, int imageListSize) { QString key = QLatin1String("qt_dir_") + QString::number(iIcon); if (iconSize == SHGFI_LARGEICON) key += QLatin1Char('l'); + switch (imageListSize) { + case sHIL_EXTRALARGE: + key += QLatin1Char('e'); + break; + case sHIL_JUMBO: + key += QLatin1Char('j'); + break; + } return key; } @@ -601,7 +635,40 @@ public: void operator delete (void *) {} }; -QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +// Shell image list helper functions. + +static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info) +{ + QPixmap result; +#ifdef USE_IIMAGELIST + // For MinGW: + static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}}; + + if (!QWindowsContext::shell32dll.sHGetImageList) + return result; + if (iImageList == sHIL_JUMBO && QSysInfo::WindowsVersion < QSysInfo::WV_VISTA) + return result; + + IImageList *imageList = 0; + HRESULT hr = QWindowsContext::shell32dll.sHGetImageList(iImageList, iID_IImageList, (void **)&imageList); + if (hr != S_OK) + return result; + HICON hIcon; + hr = imageList->GetIcon(info.iIcon, ILD_TRANSPARENT, &hIcon); + if (hr == S_OK) { + result = qt_pixmapFromWinHICON(hIcon); + DestroyIcon(hIcon); + } + imageList->Release(); +#else + Q_UNUSED(iImageList) + Q_UNUSED(info) +#endif // USE_IIMAGELIST + return result; +} + +QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions) const { /* We don't use the variable, but by storing it statically, we * ensure CoInitialize is only called once. */ @@ -610,17 +677,26 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s static QCache<QString, FakePointer<int> > dirIconEntryCache(1000); static QMutex mx; + static int defaultFolderIIcon = 0; + const bool useDefaultFolderIcon = iconOptions & QPlatformTheme::DontUseCustomDirectoryIcons; QPixmap pixmap; const QString filePath = QDir::toNativeSeparators(fileInfo.filePath()); - int iconSize = size.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON; - + const int width = size.width(); + const int iconSize = width > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON; + const int requestedImageListSize = +#ifdef USE_IIMAGELIST + width > 48 ? sHIL_JUMBO : (width > 32 ? sHIL_EXTRALARGE : 0); +#else + 0; +#endif // !USE_IIMAGELIST bool cacheableDirIcon = fileInfo.isDir() && !fileInfo.isRoot(); if (cacheableDirIcon) { QMutexLocker locker(&mx); - int iIcon = **dirIconEntryCache.object(filePath); + int iIcon = (useDefaultFolderIcon && defaultFolderIIcon) ? defaultFolderIIcon + : **dirIconEntryCache.object(filePath); if (iIcon) { - QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize), pixmap); + QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize, requestedImageListSize), pixmap); if (pixmap.isNull()) // Let's keep both caches in sync dirIconEntryCache.remove(filePath); else @@ -635,15 +711,26 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s #else iconSize|SHGFI_SYSICONINDEX; #endif // Q_OS_WINCE - unsigned long val = SHGetFileInfo((const wchar_t *)filePath.utf16(), 0, - &info, sizeof(SHFILEINFO), flags); + unsigned long val = 0; + if (cacheableDirIcon && useDefaultFolderIcon) { + flags |= SHGFI_USEFILEATTRIBUTES; + val = SHGetFileInfo(L"dummy", + FILE_ATTRIBUTE_DIRECTORY, + &info, sizeof(SHFILEINFO), flags); + } else { + val = SHGetFileInfo(reinterpret_cast<const wchar_t *>(filePath.utf16()), 0, + &info, sizeof(SHFILEINFO), flags); + } // Even if GetFileInfo returns a valid result, hIcon can be empty in some cases if (val && info.hIcon) { QString key; if (cacheableDirIcon) { + if (useDefaultFolderIcon && !defaultFolderIIcon) + defaultFolderIIcon = info.iIcon; + //using the unique icon index provided by windows save us from duplicate keys - key = dirIconPixmapCacheKey(info.iIcon, iconSize); + key = dirIconPixmapCacheKey(info.iIcon, iconSize, requestedImageListSize); QPixmapCache::find(key, pixmap); if (!pixmap.isNull()) { QMutexLocker locker(&mx); @@ -652,7 +739,13 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s } if (pixmap.isNull()) { - pixmap = qt_pixmapFromWinHICON(info.hIcon); + if (requestedImageListSize) { + pixmap = pixmapFromShellImageList(requestedImageListSize, info); + if (pixmap.isNull() && requestedImageListSize == sHIL_JUMBO) + pixmap = pixmapFromShellImageList(sHIL_EXTRALARGE, info); + } + if (pixmap.isNull()) + pixmap = qt_pixmapFromWinHICON(info.hIcon); if (!pixmap.isNull()) { if (cacheableDirIcon) { QMutexLocker locker(&mx); diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index bbd7f4623f..9346621d59 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -68,7 +68,8 @@ public: { return m_fonts[type]; } virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; - virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; + virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions = 0) const; void windowsThemeChanged(QWindow *window); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index ace18ddf5b..f3faccbc14 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -56,6 +56,7 @@ #include <QtGui/QScreen> #include <QtGui/QWindow> #include <QtGui/QRegion> +#include <private/qsystemlibrary_p.h> #include <private/qwindow_p.h> #include <private/qguiapplication_p.h> #include <qpa/qwindowsysteminterface.h> @@ -203,6 +204,69 @@ static inline QSize clientSize(HWND hwnd) return qSizeOfRect(rect); } +static bool applyBlurBehindWindow(HWND hwnd) +{ +#ifdef Q_OS_WINCE + Q_UNUSED(hwnd); + return false; +#else + enum { dwmBbEnable = 0x1, dwmBbBlurRegion = 0x2 }; + + struct DwmBlurBehind { + DWORD dwFlags; + BOOL fEnable; + HRGN hRgnBlur; + BOOL fTransitionOnMaximized; + }; + + typedef HRESULT (WINAPI *PtrDwmEnableBlurBehindWindow)(HWND, const DwmBlurBehind*); + typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL *); + + // DWM API is available only from Windows Vista + if (QSysInfo::windowsVersion() < QSysInfo::WV_VISTA) + return false; + + static bool functionPointersResolved = false; + static PtrDwmEnableBlurBehindWindow dwmBlurBehind = 0; + static PtrDwmIsCompositionEnabled dwmIsCompositionEnabled = 0; + + if (Q_UNLIKELY(!functionPointersResolved)) { + QSystemLibrary library(QStringLiteral("dwmapi")); + if (library.load()) { + dwmBlurBehind = (PtrDwmEnableBlurBehindWindow)(library.resolve("DwmEnableBlurBehindWindow")); + dwmIsCompositionEnabled = (PtrDwmIsCompositionEnabled)(library.resolve("DwmIsCompositionEnabled")); + } + + functionPointersResolved = true; + } + + if (Q_UNLIKELY(!dwmBlurBehind || !dwmIsCompositionEnabled)) + return false; + + BOOL compositionEnabled; + if (dwmIsCompositionEnabled(&compositionEnabled) != S_OK) + return false; + + DwmBlurBehind blurBehind = {0, 0, 0, 0}; + + if (compositionEnabled) { + blurBehind.dwFlags = dwmBbEnable | dwmBbBlurRegion; + blurBehind.fEnable = TRUE; + blurBehind.hRgnBlur = CreateRectRgn(0, 0, -1, -1); + } else { + blurBehind.dwFlags = dwmBbEnable; + blurBehind.fEnable = FALSE; + } + + const bool result = dwmBlurBehind(hwnd, &blurBehind) == S_OK; + + if (blurBehind.hRgnBlur) + DeleteObject(blurBehind.hRgnBlur); + + return result; +#endif // Q_OS_WINCE +} + // from qwidget_win.cpp, pass flags separately in case they have been "autofixed". static bool shouldShowMaximizeButton(const QWindow *w, Qt::WindowFlags flags) { @@ -543,6 +607,10 @@ QWindowsWindow::WindowData result.frame = context->margins; result.embedded = embedded; result.customMargins = context->customMargins; + + if (isGL && hasAlpha) + applyBlurBehindWindow(result.hwnd); + return result; } @@ -1167,6 +1235,13 @@ void QWindowsWindow::handleHidden() fireExpose(QRegion()); } +void QWindowsWindow::handleCompositionSettingsChanged() +{ + const QWindow *w = window(); + if (w->surfaceType() == QWindow::OpenGLSurface && w->format().hasAlpha()) + applyBlurBehindWindow(handle()); +} + void QWindowsWindow::setGeometry(const QRect &rectIn) { QRect rect = rectIn; diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index afcfa8b821..f055864482 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -221,6 +221,7 @@ public: void handleMoved(); void handleResized(int wParam); void handleHidden(); + void handleCompositionSettingsChanged(); static inline HWND handleOf(const QWindow *w); static inline QWindowsWindow *baseWindowOf(const QWindow *w); diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index 3aa9caaa0f..d4e6e558ed 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -102,6 +102,12 @@ contains(QT_CONFIG, opengles2) { } } +!wince*:!contains( DEFINES, QT_NO_TABLETEVENT ) { + INCLUDEPATH += ../../../3rdparty/wintab + HEADERS += qwindowstabletsupport.h + SOURCES += qwindowstabletsupport.cpp +} + contains(QT_CONFIG, freetype) { DEFINES *= QT_NO_FONTCONFIG QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype diff --git a/src/plugins/platforms/xcb/main.cpp b/src/plugins/platforms/xcb/main.cpp index be5a0e3501..e114827703 100644 --- a/src/plugins/platforms/xcb/main.cpp +++ b/src/plugins/platforms/xcb/main.cpp @@ -47,15 +47,15 @@ QT_BEGIN_NAMESPACE class QXcbIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "xcb.json") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "xcb.json") public: - QPlatformIntegration *create(const QString&, const QStringList&); + QPlatformIntegration *create(const QString&, const QStringList&, int &, char **); }; -QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& parameters) +QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& parameters, int &argc, char **argv) { if (system.toLower() == "xcb") - return new QXcbIntegration(parameters); + return new QXcbIntegration(parameters, argc, argv); return 0; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 2ce34ea8f2..ff5b36c448 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -51,13 +51,15 @@ #include "qxcbwmsupport.h" #include "qxcbnativeinterface.h" #include "qxcbintegration.h" +#include "qxcbsystemtraytracker.h" -#include <QtAlgorithms> #include <QSocketNotifier> #include <QAbstractEventDispatcher> #include <QTimer> #include <QByteArray> +#include <algorithm> + #include <dlfcn.h> #include <stdio.h> #include <errno.h> @@ -262,6 +264,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra , has_xkb(false) , m_buttons(0) , m_focusWindow(0) + , m_systemTrayTracker(0) { #ifdef XCB_USE_XLIB Display *dpy = XOpenDisplay(m_displayName.constData()); @@ -656,6 +659,11 @@ void QXcbConnection::log(const char *file, int line, int sequence) void QXcbConnection::handleXcbError(xcb_generic_error_t *error) { + long result = 0; + QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); + if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), error, &result)) + return; + uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1); uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1); @@ -813,6 +821,8 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent); case XCB_UNMAP_NOTIFY: HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent); + case XCB_DESTROY_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_destroy_notify_event_t, event, handleDestroyNotifyEvent); case XCB_CLIENT_MESSAGE: handleClientMessageEvent((xcb_client_message_event_t *)event); break; @@ -1196,6 +1206,8 @@ void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t * drag()->handleFinished(event); } #endif + if (m_systemTrayTracker && event->type == atom(QXcbAtom::MANAGER)) + m_systemTrayTracker->notifyManagerClientMessageEvent(event); QXcbWindow *window = platformWindowFromId(event->window); if (!window) @@ -1231,6 +1243,8 @@ static const char * xcb_atomnames = { "_NET_WM_CONTEXT_HELP\0" "_NET_WM_SYNC_REQUEST\0" "_NET_WM_SYNC_REQUEST_COUNTER\0" + "MANAGER\0" + "_NET_SYSTEM_TRAY_OPCODE\0" // ICCCM window state "WM_STATE\0" @@ -1388,6 +1402,8 @@ static const char * xcb_atomnames = { "Abs MT Pressure\0" "Abs MT Tracking ID\0" "Max Contacts\0" + "Rel X\0" + "Rel Y\0" // XInput2 tablet "Abs X\0" "Abs Y\0" @@ -1404,9 +1420,9 @@ static const char * xcb_atomnames = { "_XSETTINGS_SETTINGS\0" // \0\0 terminates loop. }; -xcb_atom_t QXcbConnection::atom(QXcbAtom::Atom atom) +QXcbAtom::Atom QXcbConnection::qatom(xcb_atom_t xatom) const { - return m_allAtoms[atom]; + return static_cast<QXcbAtom::Atom>(std::find(m_allAtoms, m_allAtoms + QXcbAtom::NAtoms, xatom) - m_allAtoms); } void QXcbConnection::initializeAllAtoms() { @@ -1724,6 +1740,17 @@ bool QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int o } #endif // defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO) +QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() +{ + if (!m_systemTrayTracker) { + if ( (m_systemTrayTracker = QXcbSystemTrayTracker::create(this)) ) { + connect(m_systemTrayTracker, SIGNAL(systemTrayWindowChanged(QScreen*)), + QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*))); + } + } + return m_systemTrayTracker; +} + QXcbConnectionGrabber::QXcbConnectionGrabber(QXcbConnection *connection) :m_connection(connection) { diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 2a5ff0b1cb..7cabe67a68 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -87,6 +87,7 @@ class QXcbKeyboard; class QXcbClipboard; class QXcbWMSupport; class QXcbNativeInterface; +class QXcbSystemTrayTracker; namespace QXcbAtom { enum Atom { @@ -98,6 +99,8 @@ namespace QXcbAtom { _NET_WM_CONTEXT_HELP, _NET_WM_SYNC_REQUEST, _NET_WM_SYNC_REQUEST_COUNTER, + MANAGER, // System tray notification + _NET_SYSTEM_TRAY_OPCODE, // System tray operation // ICCCM window state WM_STATE, @@ -256,6 +259,8 @@ namespace QXcbAtom { AbsMTPressure, AbsMTTrackingID, MaxContacts, + RelX, + RelY, // XInput2 tablet AbsX, AbsY, @@ -319,6 +324,7 @@ public: virtual void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *) {} virtual void handleMapNotifyEvent(const xcb_map_notify_event_t *) {} virtual void handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *) {} + virtual void handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *) {} virtual void handleButtonPressEvent(const xcb_button_press_event_t *) {} virtual void handleButtonReleaseEvent(const xcb_button_release_event_t *) {} virtual void handleMotionNotifyEvent(const xcb_motion_notify_event_t *) {} @@ -346,7 +352,8 @@ public: const QList<QXcbScreen *> &screens() const { return m_screens; } int primaryScreen() const { return m_primaryScreen; } - xcb_atom_t atom(QXcbAtom::Atom atom); + inline xcb_atom_t atom(QXcbAtom::Atom atom) const { return m_allAtoms[atom]; } + QXcbAtom::Atom qatom(xcb_atom_t atom) const; xcb_atom_t internAtom(const char *name); QByteArray atomName(xcb_atom_t atom); @@ -430,6 +437,9 @@ public: void ungrabServer(); QXcbNativeInterface *nativeInterface() const { return m_nativeInterface; } + + QXcbSystemTrayTracker *systemTrayTracker(); + private slots: void processXcbEvents(); @@ -478,8 +488,6 @@ private: }; QHash<int, ValuatorClassInfo> valuatorInfo; }; - void xi2QueryTabletData(void *dev, TabletData *tabletData); // use no XI stuff in headers - void xi2SetupTabletDevices(); bool xi2HandleTabletEvent(void *event, TabletData *tabletData); void xi2ReportTabletEvent(const TabletData &tabletData, void *event); QVector<TabletData> m_tabletData; @@ -565,6 +573,7 @@ private: QXcbWindow *m_focusWindow; QByteArray m_startupId; + QXcbSystemTrayTracker *m_systemTrayTracker; }; #define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 799bb387e1..b144d953a7 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -44,8 +44,8 @@ #include "qxcbwindow.h" #include "qtouchdevice.h" #include <qpa/qwindowsysteminterface.h> -//#define XI2_TOUCH_DEBUG -#ifdef XI2_TOUCH_DEBUG +//#define XI2_DEBUG +#ifdef XI2_DEBUG #include <QDebug> #endif @@ -63,20 +63,19 @@ struct XInput2DeviceData { } XIDeviceInfo *xiDeviceInfo; QTouchDevice *qtTouchDevice; -}; -#ifndef QT_NO_TABLETEVENT -static inline bool q_xi2_is_tablet(XIDeviceInfo *dev) -{ - QByteArray name(dev->name); - name = name.toLower(); - // Cannot just check for "wacom" because that would also pick up the touch and tablet-button devices. - return name.contains("stylus") || name.contains("eraser"); -} -#endif // QT_NO_TABLETEVENT + // Stuff that is relevant only for touchpads + QHash<int, QPointF> pointPressedPosition; // in screen coordinates where each point was pressed + QPointF firstPressedPosition; // in screen coordinates where the first point was pressed + QPointF firstPressedNormalPosition; // device coordinates (0 to 1, 0 to 1) where the first point was pressed + QSizeF size; // device size in mm +}; void QXcbConnection::initializeXInput2() { +#ifndef QT_NO_TABLETEVENT + m_tabletData.clear(); +#endif Display *xDisplay = static_cast<Display *>(m_xlib_display); if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) { int xiMajor = 2; @@ -88,13 +87,78 @@ void QXcbConnection::initializeXInput2() m_xi2Enabled = true; } if (m_xi2Enabled) { +#ifdef XI2_DEBUG + qDebug("XInput version %d.%d is supported", xiMajor, m_xi2Minor); +#endif + int deviceCount = 0; + XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount); + for (int i = 0; i < deviceCount; ++i) { + // Only non-master pointing devices are relevant here. + if (devices[i].use != XISlavePointer) + continue; +#ifdef XI2_DEBUG + qDebug() << "input device "<< devices[i].name; +#endif #ifndef QT_NO_TABLETEVENT - // Tablet support: Find the stylus-related devices. - xi2SetupTabletDevices(); + TabletData tabletData; +#endif + for (int c = 0; c < devices[i].num_classes; ++c) { + switch (devices[i].classes[c]->type) { + case XIValuatorClass: { + XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(devices[i].classes[c]); + const int valuatorAtom = qatom(vci->label); +#ifdef XI2_DEBUG + qDebug() << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms); +#endif +#ifndef QT_NO_TABLETEVENT + if (valuatorAtom < QXcbAtom::NAtoms) { + TabletData::ValuatorClassInfo info; + info.minVal = vci->min; + info.maxVal = vci->max; + info.number = vci->number; + tabletData.valuatorInfo[valuatorAtom] = info; + } #endif // QT_NO_TABLETEVENT -#ifdef XI2_TOUCH_DEBUG - qDebug("XInput version %d.%d is supported", xiMajor, m_xi2Minor); + } break; + default: + break; + } + } + bool isTablet = false; +#ifndef QT_NO_TABLETEVENT + // If we have found the valuators which we expect a tablet to have, assume it's a tablet. + if (tabletData.valuatorInfo.contains(QXcbAtom::AbsX) && + tabletData.valuatorInfo.contains(QXcbAtom::AbsY) && + tabletData.valuatorInfo.contains(QXcbAtom::AbsPressure)) { + tabletData.deviceId = devices[i].deviceid; + tabletData.pointerType = QTabletEvent::Pen; + if (QByteArray(devices[i].name).toLower().contains("eraser")) + tabletData.pointerType = QTabletEvent::Eraser; + m_tabletData.append(tabletData); + isTablet = true; +#ifdef XI2_DEBUG + qDebug() << " it's a tablet with pointer type" << tabletData.pointerType; #endif + } +#endif // QT_NO_TABLETEVENT + if (!isTablet) { + XInput2DeviceData *dev = deviceForId(devices[i].deviceid); +#ifdef XI2_DEBUG + if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchScreen) + qDebug(" it's a touchscreen with type %d capabilities 0x%X max touch points %d", + dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), + dev->qtTouchDevice->maximumTouchPoints()); + else if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchPad) + qDebug(" it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f", + dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), + dev->qtTouchDevice->maximumTouchPoints(), + dev->size.width(), dev->size.height()); +#else + Q_UNUSED(dev); +#endif // XI2_DEBUG + } + } + XIFreeDeviceInfo(devices); } } } @@ -113,25 +177,24 @@ void QXcbConnection::xi2Select(xcb_window_t window) unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask); #ifdef XCB_USE_XINPUT22 - // Select touch events on all master devices indiscriminately. bitMask |= XI_TouchBeginMask; bitMask |= XI_TouchUpdateMask; bitMask |= XI_TouchEndMask; XIEventMask mask; - mask.deviceid = XIAllMasterDevices; mask.mask_len = sizeof(bitMask); mask.mask = xiBitMask; - Status result = XISelectEvents(xDisplay, window, &mask, 1); - // If we have XInput 2.2 and successfully enable touch on the master - // devices, then evdev touchscreens will provide touch only. In most other - // cases, there will be emulated mouse events, because true X11 touch - // support is so new that for the older drivers, mouse emulation was the - // only way; and it's still the fallback even with the modern evdev driver. - // But if neither Qt nor X11 does mouse emulation, it will not be possible - // to interact with mouse-oriented QWidgets; so we have to let Qt do it. - if (m_xi2Minor >= 2 && result == Success) - has_touch_without_mouse_emulation = true; -#endif + // Enable each touchscreen + foreach (XInput2DeviceData *dev, m_touchDevices.values()) { + mask.deviceid = dev->xiDeviceInfo->deviceid; + Status result = XISelectEvents(xDisplay, window, &mask, 1); + // If we have XInput >= 2.2 and successfully enable a touchscreen, then + // it will provide touch only. In most other cases, there will be + // emulated mouse events from the driver. If not, then Qt must do its + // own mouse emulation to enable interaction with mouse-oriented QWidgets. + if (m_xi2Minor >= 2 && result == Success) + has_touch_without_mouse_emulation = true; + } +#endif // XCB_USE_XINPUT22 #ifndef QT_NO_TABLETEVENT // For each tablet, select some additional event types. @@ -163,23 +226,29 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id) QTouchDevice::Capabilities caps = 0; dev = new XInput2DeviceData; dev->xiDeviceInfo = XIQueryDevice(static_cast<Display *>(m_xlib_display), id, &unused); - dev->qtTouchDevice = new QTouchDevice; + int type = -1; + int maxTouchPoints = 1; + bool hasRelativeCoords = false; for (int i = 0; i < dev->xiDeviceInfo->num_classes; ++i) { XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i]; switch (classinfo->type) { #ifdef XCB_USE_XINPUT22 case XITouchClass: { XITouchClassInfo *tci = reinterpret_cast<XITouchClassInfo *>(classinfo); + maxTouchPoints = tci->num_touches; +#ifdef XI2_DEBUG + qDebug(" has touch class with mode %d", tci->mode); +#endif switch (tci->mode) { case XIModeRelative: - dev->qtTouchDevice->setType(QTouchDevice::TouchPad); + type = QTouchDevice::TouchPad; break; case XIModeAbsolute: - dev->qtTouchDevice->setType(QTouchDevice::TouchScreen); + type = QTouchDevice::TouchScreen; break; } } break; -#endif +#endif // XCB_USE_XINPUT22 case XIValuatorClass: { XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo); if (vci->label == atom(QXcbAtom::AbsMTPositionX)) @@ -188,18 +257,36 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id) caps |= QTouchDevice::Area; else if (vci->label == atom(QXcbAtom::AbsMTPressure) || vci->label == atom(QXcbAtom::AbsPressure)) caps |= QTouchDevice::Pressure; + else if (vci->label == atom(QXcbAtom::RelX)) { + hasRelativeCoords = true; + dev->size.setWidth((vci->max - vci->min) * 1000.0 / vci->resolution); + } else if (vci->label == atom(QXcbAtom::RelY)) { + hasRelativeCoords = true; + dev->size.setHeight((vci->max - vci->min) * 1000.0 / vci->resolution); + } } break; } } - dev->qtTouchDevice->setCapabilities(caps); - dev->qtTouchDevice->setName(dev->xiDeviceInfo->name); - if (caps != 0) - QWindowSystemInterface::registerTouchDevice(dev->qtTouchDevice); -#ifdef XI2_TOUCH_DEBUG - qDebug("registered new device %s with %d classes and %d max touch points", - dev->xiDeviceInfo->name, dev->xiDeviceInfo->num_classes, dev->qtTouchDevice->maxTouchPoints()); -#endif - m_touchDevices[id] = dev; + if (type < 0 && caps && hasRelativeCoords) { + type = QTouchDevice::TouchPad; + if (dev->size.width() < 10 || dev->size.height() < 10 || + dev->size.width() > 10000 || dev->size.height() > 10000) + dev->size = QSizeF(130, 110); + } + if (type >= QTouchDevice::TouchScreen && type <= QTouchDevice::TouchPad) { + dev->qtTouchDevice = new QTouchDevice; + dev->qtTouchDevice->setName(dev->xiDeviceInfo->name); + dev->qtTouchDevice->setType((QTouchDevice::DeviceType)type); + dev->qtTouchDevice->setCapabilities(caps); + dev->qtTouchDevice->setMaximumTouchPoints(maxTouchPoints); + if (caps != 0) + QWindowSystemInterface::registerTouchDevice(dev->qtTouchDevice); + m_touchDevices[id] = dev; + } else { + m_touchDevices.remove(id); + delete dev; + dev = 0; + } } return dev; } @@ -218,7 +305,7 @@ static qreal valuatorNormalized(double value, XIValuatorClassInfo *vci) value = vci->min; return (value - vci->min) / (vci->max - vci->min); } -#endif +#endif // XCB_USE_XINPUT22 void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) { @@ -237,7 +324,7 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) #ifdef XCB_USE_XINPUT22 if (xiEvent->evtype == XI_TouchBegin || xiEvent->evtype == XI_TouchUpdate || xiEvent->evtype == XI_TouchEnd) { xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); -#ifdef XI2_TOUCH_DEBUG +#ifdef XI2_DEBUG qDebug("XI2 event type %d seq %d detail %d pos 0x%X,0x%X %f,%f root pos %f,%f", event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail, xiDeviceEvent->event_x, xiDeviceEvent->event_y, @@ -247,6 +334,8 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { XInput2DeviceData *dev = deviceForId(xiEvent->deviceid); + Q_ASSERT(dev); + const bool firstTouch = m_touchPoints.isEmpty(); if (xiEvent->evtype == XI_TouchBegin) { QWindowSystemInterface::TouchPoint tp; tp.id = xiDeviceEvent->detail % INT_MAX; @@ -267,11 +356,15 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) double value; if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value)) continue; -#ifdef XI2_TOUCH_DEBUG - qDebug(" valuator class label %d value %lf from range %lf -> %lf name %s", - vci->label, value, vci->min, vci->max, XGetAtomName(static_cast<Display *>(m_xlib_display), vci->label) ); +#ifdef XI2_DEBUG + qDebug(" valuator %20s value %lf from range %lf -> %lf", + atomName(vci->label).constData(), value, vci->min, vci->max ); #endif - if (vci->label == atom(QXcbAtom::AbsMTPositionX)) { + if (vci->label == atom(QXcbAtom::RelX)) { + nx = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::RelY)) { + ny = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::AbsMTPositionX)) { nx = valuatorNormalized(value, vci); } else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) { ny = valuatorNormalized(value, vci); @@ -306,17 +399,43 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) } switch (xiEvent->evtype) { + case XI_TouchBegin: + if (firstTouch) { + dev->firstPressedPosition = QPointF(x, y); + dev->firstPressedNormalPosition = QPointF(nx, ny); + } + dev->pointPressedPosition.insert(touchPoint.id, QPointF(x, y)); + break; case XI_TouchUpdate: - if (touchPoint.area.center() != QPoint(x, y)) + if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) { + qreal dx = (nx - dev->firstPressedNormalPosition.x()) * + dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); + qreal dy = (ny - dev->firstPressedNormalPosition.y()) * + dev->size.height() * screen->geometry().height() / screen->physicalSize().height(); + x = dev->firstPressedPosition.x() + dx; + y = dev->firstPressedPosition.y() + dy; + touchPoint.state = Qt::TouchPointMoved; + } else if (touchPoint.area.center() != QPoint(x, y)) { touchPoint.state = Qt::TouchPointMoved; + dev->pointPressedPosition[touchPoint.id] = QPointF(x, y); + } break; case XI_TouchEnd: touchPoint.state = Qt::TouchPointReleased; + if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) { + qreal dx = (nx - dev->firstPressedNormalPosition.x()) * + dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); + qreal dy = (ny - dev->firstPressedNormalPosition.y()) * + dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); + x = dev->firstPressedPosition.x() + dx; + y = dev->firstPressedPosition.y() + dy; + } + dev->pointPressedPosition.remove(touchPoint.id); } touchPoint.area = QRectF(x - w/2, y - h/2, w, h); touchPoint.normalPosition = QPointF(nx, ny); -#ifdef XI2_TOUCH_DEBUG +#ifdef XI2_DEBUG qDebug() << " tp " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition << " area " << touchPoint.area << " pressure " << touchPoint.pressure; #endif @@ -330,80 +449,11 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) touchPoint.state = Qt::TouchPointStationary; } } -#endif +#endif // XCB_USE_XINPUT22 } } #ifndef QT_NO_TABLETEVENT -void QXcbConnection::xi2QueryTabletData(void *dev, TabletData *tabletData) -{ - XIDeviceInfo *device = static_cast<XIDeviceInfo *>(dev); - tabletData->deviceId = device->deviceid; - - tabletData->pointerType = QTabletEvent::Pen; - if (QByteArray(device->name).toLower().contains("eraser")) - tabletData->pointerType = QTabletEvent::Eraser; - - for (int i = 0; i < device->num_classes; ++i) { - switch (device->classes[i]->type) { - case XIValuatorClass: { - XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(device->classes[i]); - int val = 0; - if (vci->label == atom(QXcbAtom::AbsX)) - val = QXcbAtom::AbsX; - else if (vci->label == atom(QXcbAtom::AbsY)) - val = QXcbAtom::AbsY; - else if (vci->label == atom(QXcbAtom::AbsPressure)) - val = QXcbAtom::AbsPressure; - else if (vci->label == atom(QXcbAtom::AbsTiltX)) - val = QXcbAtom::AbsTiltX; - else if (vci->label == atom(QXcbAtom::AbsTiltY)) - val = QXcbAtom::AbsTiltY; - else if (vci->label == atom(QXcbAtom::AbsWheel)) - val = QXcbAtom::AbsWheel; - else if (vci->label == atom(QXcbAtom::AbsDistance)) - val = QXcbAtom::AbsDistance; - if (val) { - TabletData::ValuatorClassInfo info; - info.minVal = vci->min; - info.maxVal = vci->max; - info.number = vci->number; - tabletData->valuatorInfo[val] = info; - } - } - break; - default: - break; - } - } -} - -void QXcbConnection::xi2SetupTabletDevices() -{ - Display *xDisplay = static_cast<Display *>(m_xlib_display); - m_tabletData.clear(); - int deviceCount = 0; - XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount); - if (devices) { - for (int i = 0; i < deviceCount; ++i) { - int unused = 0; - XIDeviceInfo *dev = XIQueryDevice(xDisplay, devices[i].deviceid, &unused); - if (dev) { - if (q_xi2_is_tablet(dev)) { - TabletData tabletData; - xi2QueryTabletData(dev, &tabletData); -#ifdef XI2_TOUCH_DEBUG - qDebug() << "found tablet" << dev->name; -#endif - m_tabletData.append(tabletData); - } - XIFreeDeviceInfo(dev); - } - } - XIFreeDeviceInfo(devices); - } -} - bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData) { bool handled = true; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index cf7e99023a..68ad93143b 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -119,9 +119,10 @@ static bool runningUnderDebugger() } #endif -QXcbIntegration::QXcbIntegration(const QStringList ¶meters) +QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char **argv) : m_eventDispatcher(createUnixEventDispatcher()) , m_services(new QGenericUnixServices) + , m_instanceName(0) { QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher); @@ -138,7 +139,28 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters) if (canNotGrabEnv) canGrab = false; - m_connections << new QXcbConnection(m_nativeInterface.data(), canGrab); + // Parse arguments + const char *displayName = 0; + if (argc) { + int j = 1; + for (int i = 1; i < argc; i++) { + char *arg = argv[i]; + if (arg) { + if (!strcmp(arg, "-display") && i < argc - 1) { + displayName = argv[++i]; + arg = 0; + } else if (!strcmp(arg, "-name") && i < argc - 1) { + m_instanceName = argv[++i]; + arg = 0; + } + } + if (arg) + argv[j++] = arg; + } + argc = j; + } // argc + + m_connections << new QXcbConnection(m_nativeInterface.data(), canGrab, displayName); for (int i = 0; i < parameters.size() - 1; i += 2) { #ifdef Q_XCB_DEBUG @@ -365,6 +387,8 @@ QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const case QPlatformIntegration::SynthesizeMouseFromTouchEvents: // We do not want Qt to synthesize mouse events if X11 already does it. return m_connections.at(0)->hasTouchWithoutMouseEmulation(); + default: + break; } return QPlatformIntegration::styleHint(hint); } @@ -389,6 +413,8 @@ QByteArray QXcbIntegration::wmClass() const if (m_wmClass.isEmpty()) { // Instance name according to ICCCM 4.1.2.5 QString name; + if (m_instanceName) + name = QString::fromLocal8Bit(m_instanceName); if (name.isEmpty() && qEnvironmentVariableIsSet(resourceNameVar)) name = QString::fromLocal8Bit(qgetenv(resourceNameVar)); if (name.isEmpty()) diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 07b6b8d678..09fc0d32b5 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -55,7 +55,7 @@ class QXcbScreen; class QXcbIntegration : public QPlatformIntegration { public: - QXcbIntegration(const QStringList ¶meters); + QXcbIntegration(const QStringList ¶meters, int &argc, char **argv); ~QXcbIntegration(); QPlatformWindow *createPlatformWindow(QWindow *window) const; @@ -119,6 +119,7 @@ private: friend class QXcbConnection; // access QPlatformIntegration::screenAdded() mutable QByteArray m_wmClass; + const char *m_instanceName; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index d1729ed168..2529fb8a83 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -243,6 +243,10 @@ #define XF86XK_Select 0x1008FFA0 #define XF86XK_View 0x1008FFA1 #define XF86XK_TopMenu 0x1008FFA2 +#define XF86XK_Red 0x1008FFA3 +#define XF86XK_Green 0x1008FFA4 +#define XF86XK_Yellow 0x1008FFA5 +#define XF86XK_Blue 0x1008FFA6 #define XF86XK_Suspend 0x1008FFA7 #define XF86XK_Hibernate 0x1008FFA8 #define XF86XK_TouchpadToggle 0x1008FFA9 @@ -538,6 +542,10 @@ static const unsigned int KeyTbl[] = { XF86XK_Select, Qt::Key_Select, XF86XK_View, Qt::Key_View, XF86XK_TopMenu, Qt::Key_TopMenu, + XF86XK_Red, Qt::Key_Red, + XF86XK_Green, Qt::Key_Green, + XF86XK_Yellow, Qt::Key_Yellow, + XF86XK_Blue, Qt::Key_Blue, XF86XK_Bluetooth, Qt::Key_Bluetooth, XF86XK_Suspend, Qt::Key_Suspend, XF86XK_Hibernate, Qt::Key_Hibernate, diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 9e9fd2914f..99e9932847 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -42,7 +42,9 @@ #include "qxcbnativeinterface.h" #include "qxcbscreen.h" +#include "qxcbwindow.h" #include "qxcbintegration.h" +#include "qxcbsystemtraytracker.h" #include <private/qguiapplication_p.h> #include <QtCore/QMap> @@ -82,6 +84,8 @@ public: insert("appusertime",QXcbNativeInterface::AppUserTime); insert("hintstyle", QXcbNativeInterface::ScreenHintStyle); insert("startupid", QXcbNativeInterface::StartupId); + insert(QByteArrayLiteral("traywindow"), QXcbNativeInterface::TrayWindow); + insert(QByteArrayLiteral("gettimestamp"), QXcbNativeInterface::GetTimestamp); } }; @@ -100,6 +104,36 @@ void QXcbNativeInterface::beep() // For QApplication::beep() xcb_bell(connection, 0); } +static inline QXcbSystemTrayTracker *systemTrayTracker(const QScreen *s) +{ + return static_cast<const QXcbScreen *>(s->handle())->connection()->systemTrayTracker(); +} + +bool QXcbNativeInterface::systemTrayAvailable(const QScreen *screen) const +{ + return systemTrayTracker(screen); +} + +bool QXcbNativeInterface::requestSystemTrayWindowDock(const QWindow *window) +{ + const QPlatformWindow *platformWindow = window->handle(); + if (!platformWindow) + return false; + QXcbSystemTrayTracker *trayTracker = systemTrayTracker(window->screen()); + if (!trayTracker) + return false; + trayTracker->requestSystemTrayWindowDock(static_cast<const QXcbWindow *>(platformWindow)->xcb_window()); + return true; +} + +QRect QXcbNativeInterface::systemTrayWindowGlobalGeometry(const QWindow *window) +{ + if (const QPlatformWindow *platformWindow = window->handle()) + if (const QXcbSystemTrayTracker *trayTracker = systemTrayTracker(window->screen())) + return trayTracker->systemTrayWindowGlobalGeometry(static_cast<const QXcbWindow *>(platformWindow)->xcb_window()); + return QRect(); +} + void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString) { QByteArray lowerCaseResource = resourceString.toLower(); @@ -162,6 +196,14 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resource, Q break; case ScreenHintStyle: result = reinterpret_cast<void *>(xcbScreen->hintStyle() + 1); + break; + case TrayWindow: + if (QXcbSystemTrayTracker *s = systemTrayTracker(screen)) + result = (void *)quintptr(s->trayWindow()); + break; + case GetTimestamp: + result = getTimestamp(xcbScreen); + break; default: break; } @@ -216,6 +258,11 @@ void *QXcbNativeInterface::appUserTime(const QXcbScreen *screen) return reinterpret_cast<void *>(quintptr(screen->connection()->netWmUserTime())); } +void *QXcbNativeInterface::getTimestamp(const QXcbScreen *screen) +{ + return reinterpret_cast<void *>(quintptr(screen->connection()->getTimestamp())); +} + void *QXcbNativeInterface::startupId() { QXcbIntegration* integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration()); diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index e27bfa5a46..86b94e62e4 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -45,6 +45,8 @@ #include <qpa/qplatformnativeinterface.h> #include <xcb/xcb.h> +#include <QtCore/QRect> + QT_BEGIN_NAMESPACE class QWidget; @@ -66,7 +68,9 @@ public: AppTime, AppUserTime, ScreenHintStyle, - StartupId + StartupId, + TrayWindow, + GetTimestamp }; QXcbNativeInterface(); @@ -88,6 +92,7 @@ public: void *graphicsDeviceForWindow(QWindow *window); void *appTime(const QXcbScreen *screen); void *appUserTime(const QXcbScreen *screen); + void *getTimestamp(const QXcbScreen *screen); void *startupId(); static void setAppTime(QScreen *screen, xcb_timestamp_t time); static void setAppUserTime(QScreen *screen, xcb_timestamp_t time); @@ -95,6 +100,12 @@ public: static void *glxContextForContext(QOpenGLContext *context); Q_INVOKABLE void beep(); + Q_INVOKABLE bool systemTrayAvailable(const QScreen *screen) const; + Q_INVOKABLE bool requestSystemTrayWindowDock(const QWindow *window); + Q_INVOKABLE QRect systemTrayWindowGlobalGeometry(const QWindow *window); + +signals: + void systemTrayWindowChanged(QScreen *screen); private: const QByteArray m_genericEventFilterType; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 37c6c97bc4..6961a2fd79 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -112,6 +112,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_PROPERTY_CHANGE + | XCB_EVENT_MASK_STRUCTURE_NOTIFY // for the "MANAGER" atom (system tray notification). }; xcb_change_window_attributes(xcb_connection(), screen()->root, mask, values); @@ -148,7 +149,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, if (!sync_reply || !sync_reply->present) m_syncRequestSupported = false; else - m_syncRequestSupported = m_windowManagerName != QLatin1String("KWin"); + m_syncRequestSupported = true; m_clientLeader = xcb_generate_id(xcb_connection()); Q_XCB_CALL2(xcb_create_window(xcb_connection(), diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp new file mode 100644 index 0000000000..24d2feb106 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbsystemtraytracker.h" +#include "qxcbconnection.h" +#include "qxcbscreen.h" + +#include <QtCore/QDebug> +#include <QtCore/QRect> +#include <QtGui/QScreen> + +#include <qpa/qplatformnativeinterface.h> + +QT_BEGIN_NAMESPACE + +enum { + SystemTrayRequestDock = 0, + SystemTrayBeginMessage = 1, + SystemTrayCancelMessage = 2 +}; + +// QXcbSystemTrayTracker provides API for accessing the tray window and tracks +// its lifecyle by listening for its destruction and recreation. +// See http://standards.freedesktop.org/systemtray-spec/systemtray-spec-latest.html + +QXcbSystemTrayTracker *QXcbSystemTrayTracker::create(QXcbConnection *connection) +{ + // Selection, tray atoms for GNOME, NET WM Specification + const xcb_atom_t trayAtom = connection->atom(QXcbAtom::_NET_SYSTEM_TRAY_OPCODE); + if (!trayAtom) + return 0; + const QByteArray netSysTray = QByteArrayLiteral("_NET_SYSTEM_TRAY_S") + QByteArray::number(connection->primaryScreen()); + const xcb_atom_t selection = connection->internAtom(netSysTray.constData()); + if (!selection) + return 0; + return new QXcbSystemTrayTracker(connection, trayAtom, selection, connection); +} + +QXcbSystemTrayTracker::QXcbSystemTrayTracker(QXcbConnection *connection, + xcb_atom_t trayAtom, + xcb_atom_t selection, + QObject *parent) + : QObject(parent) + , m_selection(selection) + , m_trayAtom(trayAtom) + , m_connection(connection) + , m_trayWindow(0) +{ +} + +xcb_window_t QXcbSystemTrayTracker::locateTrayWindow(const QXcbConnection *connection, xcb_atom_t selection) +{ + xcb_get_selection_owner_cookie_t cookie = xcb_get_selection_owner(connection->xcb_connection(), selection); + xcb_get_selection_owner_reply_t *reply = xcb_get_selection_owner_reply(connection->xcb_connection(), cookie, 0); + if (!reply) + return 0; + const xcb_window_t result = reply->owner; + free(reply); + return result; +} + +// API for QPlatformNativeInterface/QPlatformSystemTrayIcon: Request a window +// to be docked on the tray. +void QXcbSystemTrayTracker::requestSystemTrayWindowDock(xcb_window_t window) const +{ + xcb_client_message_event_t trayRequest; + memset(&trayRequest, 0, sizeof(trayRequest)); + trayRequest.response_type = XCB_CLIENT_MESSAGE; + trayRequest.format = 32; + trayRequest.window = m_trayWindow; + trayRequest.type = m_trayAtom; + trayRequest.data.data32[0] = XCB_CURRENT_TIME; + trayRequest.data.data32[1] = SystemTrayRequestDock; + trayRequest.data.data32[2] = window; + xcb_send_event(m_connection->xcb_connection(), 0, m_trayWindow, XCB_EVENT_MASK_NO_EVENT, (const char *)&trayRequest); +} + +// API for QPlatformNativeInterface/QPlatformSystemTrayIcon: Return tray window. +xcb_window_t QXcbSystemTrayTracker::trayWindow() +{ + if (!m_trayWindow) { + m_trayWindow = QXcbSystemTrayTracker::locateTrayWindow(m_connection, m_selection); + if (m_trayWindow) { // Listen for DestroyNotify on tray. + m_connection->addWindowEventListener(m_trayWindow, this); + const quint32 mask = XCB_CW_EVENT_MASK; + const quint32 value = XCB_EVENT_MASK_STRUCTURE_NOTIFY; + Q_XCB_CALL(xcb_change_window_attributes(m_connection->xcb_connection(), m_trayWindow, mask, &value)); + } + } + return m_trayWindow; +} + +// API for QPlatformNativeInterface/QPlatformSystemTrayIcon: Return the geometry of a +// a window parented on the tray. Determines the global geometry via XCB since mapToGlobal +// does not work for the QWindow parented on the tray. +QRect QXcbSystemTrayTracker::systemTrayWindowGlobalGeometry(xcb_window_t window) const +{ + xcb_connection_t *conn = m_connection->xcb_connection(); + xcb_get_geometry_reply_t *geomReply = + xcb_get_geometry_reply(conn, xcb_get_geometry(conn, window), 0); + if (!geomReply) + return QRect(); + + xcb_translate_coordinates_reply_t *translateReply = + xcb_translate_coordinates_reply(conn, xcb_translate_coordinates(conn, window, m_connection->rootWindow(), 0, 0), 0); + if (!translateReply) { + free(geomReply); + return QRect(); + } + + const QRect result(QPoint(translateReply->dst_x, translateReply->dst_y), QSize(geomReply->width, geomReply->height)); + free(translateReply); + return result; +} + +inline void QXcbSystemTrayTracker::emitSystemTrayWindowChanged() +{ + const int screen = m_connection->primaryScreen(); + if (screen >= 0 && screen < m_connection->screens().size()) { + const QPlatformScreen *ps = m_connection->screens().at(screen); + emit systemTrayWindowChanged(ps->screen()); + } +} + +// Client messages with the "MANAGER" atom on the root window indicate creation of a new tray. +void QXcbSystemTrayTracker::notifyManagerClientMessageEvent(const xcb_client_message_event_t *t) +{ + if (t->data.data32[1] == m_selection) + emitSystemTrayWindowChanged(); +} + +// Listen for destruction of the tray. +void QXcbSystemTrayTracker::handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *event) +{ + if (event->window == m_trayWindow) { + m_connection->removeWindowEventListener(m_trayWindow); + m_trayWindow = 0; + emitSystemTrayWindowChanged(); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsudevlistener.h b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h index 7534f0bcd3..c6b0a0659e 100644 --- a/src/plugins/platforms/kms/qkmsudevlistener.h +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h @@ -39,40 +39,49 @@ ** ****************************************************************************/ -#ifndef QKMSUDEVLISTENER_H -#define QKMSUDEVLISTENER_H +#ifndef QXCBSYSTEMTRAYTRACKER_H +#define QXCBSYSTEMTRAYTRACKER_H -#include <QObject> -#include <QMap> -#include <QList> -#include <QPointer> -#include <QString> +#include "qxcbconnection.h" -#include <qkmsudevhandler.h> - -#include <libudev.h> +#include <xcb/xcb.h> QT_BEGIN_NAMESPACE -class QKmsUdevListener : public QObject +class QXcbConnection; +class QScreen; + +class QXcbSystemTrayTracker : public QObject, public QXcbWindowEventListener { Q_OBJECT - public: - QKmsUdevListener(QObject *parent = 0); - ~QKmsUdevListener(); + static QXcbSystemTrayTracker *create(QXcbConnection *connection); + + xcb_window_t trayWindow(); + void requestSystemTrayWindowDock(xcb_window_t window) const; + QRect systemTrayWindowGlobalGeometry(xcb_window_t window) const; + + void notifyManagerClientMessageEvent(const xcb_client_message_event_t *); + + void handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *); - void addHandler(QKmsUdevHandler *); +signals: + void systemTrayWindowChanged(QScreen *screen); private: - QList<QPointer<QKmsUdevHandler> > m_handlers; - QMap<QString, QPointer<QObject> > m_devices; - struct udev *m_udev; + explicit QXcbSystemTrayTracker(QXcbConnection *connection, + xcb_atom_t trayAtom, + xcb_atom_t selection, + QObject *parent = 0); + static xcb_window_t locateTrayWindow(const QXcbConnection *connection, xcb_atom_t selection); + void emitSystemTrayWindowChanged(); - void scan(); - bool create(struct udev_device *); + const xcb_atom_t m_selection; + const xcb_atom_t m_trayAtom; + QXcbConnection *m_connection; + xcb_window_t m_trayWindow; }; QT_END_NAMESPACE -#endif // QKMSUDEVLISTENER_H +#endif // QXCBSYSTEMTRAYTRACKER_H diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 028cd9ab72..46c3fdce5c 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -57,6 +57,8 @@ #include <qpa/qplatformintegration.h> +#include <algorithm> + // FIXME This workaround can be removed for xcb-icccm > 3.8 #define class class_name #include <xcb/xcb_icccm.h> @@ -152,7 +154,7 @@ enum QX11EmbedMessageType { XEMBED_ACTIVATE_ACCELERATOR = 14 }; -static unsigned int XEMBED_VERSION = 0; +const long XEMBED_VERSION = 0; // Returns true if we should set WM_TRANSIENT_FOR on \a w static inline bool isTransient(const QWindow *w) @@ -779,21 +781,21 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates() if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) { const xcb_atom_t *states = static_cast<const xcb_atom_t *>(xcb_get_property_value(reply)); const xcb_atom_t *statesEnd = states + reply->length; - if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_ABOVE))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_ABOVE))) result |= NetWmStateAbove; - if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_BELOW))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_BELOW))) result |= NetWmStateBelow; - if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN))) result |= NetWmStateFullScreen; - if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ))) result |= NetWmStateMaximizedHorz; - if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT))) result |= NetWmStateMaximizedVert; - if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MODAL))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MODAL))) result |= NetWmStateModal; - if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP))) result |= NetWmStateStaysOnTop; - if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION))) + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION))) result |= NetWmStateDemandsAttention; free(reply); } else { @@ -1502,6 +1504,9 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even } else if (event->data.data32[0] == atom(QXcbAtom::WM_TAKE_FOCUS)) { connection()->setTime(event->data.data32[1]); } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) { + if (event->window == m_screen->root()) + return; + xcb_client_message_event_t reply = *event; reply.response_type = XCB_CLIENT_MESSAGE; @@ -1515,8 +1520,7 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even m_syncValue.hi = event->data.data32[3]; #ifndef QT_NO_WHATSTHIS } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_CONTEXT_HELP)) { - QEvent *e = new QEvent(QEvent::EnterWhatsThisMode); - QGuiApplication::postEvent(QGuiApplication::instance(), e); + QWindowSystemInterface::handleEnterWhatsThisEvent(); #endif } else { qWarning() << "QXcbWindow: Unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]); @@ -1533,6 +1537,11 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even #endif } else if (event->type == atom(QXcbAtom::_XEMBED)) { handleXEmbedMessage(event); + } else if (event->type == atom(QXcbAtom::MANAGER) || event->type == atom(QXcbAtom::_NET_ACTIVE_WINDOW) + || event->type == atom(QXcbAtom::_NET_WM_STATE) || event->type == atom(QXcbAtom::MANAGER) + || event->type == atom(QXcbAtom::WM_CHANGE_STATE)) { + // Ignore _NET_ACTIVE_WINDOW, _NET_WM_STATE, MANAGER which are relate to tray icons + // and other messages. } else { qWarning() << "QXcbWindow: Unhandled client message:" << connection()->atomName(event->type); } diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro index 82995286c4..b198ab1717 100644 --- a/src/plugins/platforms/xcb/xcb-plugin.pro +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -21,7 +21,8 @@ SOURCES = \ qxcbnativeinterface.cpp \ qxcbcursor.cpp \ qxcbimage.cpp \ - qxcbxsettings.cpp + qxcbxsettings.cpp \ + qxcbsystemtraytracker.cpp HEADERS = \ qxcbclipboard.h \ @@ -38,7 +39,8 @@ HEADERS = \ qxcbnativeinterface.h \ qxcbcursor.h \ qxcbimage.h \ - qxcbxsettings.h + qxcbxsettings.h \ + qxcbsystemtraytracker.h LIBS += -ldl diff --git a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp index 91a23afac5..e8758da1c7 100644 --- a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp +++ b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp @@ -282,13 +282,13 @@ bool QGtk2FileDialogHelper::defaultNameFilterDisables() const return false; } -void QGtk2FileDialogHelper::setDirectory(const QString &directory) +void QGtk2FileDialogHelper::setDirectory(const QUrl &directory) { GtkDialog *gtkDialog = d->gtkDialog(); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), directory.toUtf8()); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), directory.toLocalFile().toUtf8()); } -QString QGtk2FileDialogHelper::directory() const +QUrl QGtk2FileDialogHelper::directory() const { // While GtkFileChooserDialog is hidden, gtk_file_chooser_get_current_folder() // returns a bogus value -> return the cached value before hiding @@ -302,27 +302,27 @@ QString QGtk2FileDialogHelper::directory() const ret = QString::fromUtf8(folder); g_free(folder); } - return ret; + return QUrl::fromLocalFile(ret); } -void QGtk2FileDialogHelper::selectFile(const QString &filename) +void QGtk2FileDialogHelper::selectFile(const QUrl &filename) { GtkDialog *gtkDialog = d->gtkDialog(); - gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(gtkDialog), filename.toUtf8()); + gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(gtkDialog), filename.toLocalFile().toUtf8()); } -QStringList QGtk2FileDialogHelper::selectedFiles() const +QList<QUrl> QGtk2FileDialogHelper::selectedFiles() const { // While GtkFileChooserDialog is hidden, gtk_file_chooser_get_filenames() // returns a bogus value -> return the cached value before hiding if (!_selection.isEmpty()) return _selection; - QStringList selection; + QList<QUrl> selection; GtkDialog *gtkDialog = d->gtkDialog(); GSList *filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(gtkDialog)); for (GSList *it = filenames; it; it = it->next) - selection += QString::fromUtf8((const char*)it->data); + selection += QUrl::fromLocalFile(QString::fromUtf8((const char*)it->data)); g_slist_free(filenames); return selection; } @@ -356,7 +356,7 @@ void QGtk2FileDialogHelper::onAccepted() if (filter.isEmpty()) emit filterSelected(filter); - QStringList files = selectedFiles(); + QList<QUrl> files = selectedFiles(); emit filesSelected(files); if (files.count() == 1) emit fileSelected(files.first()); @@ -370,7 +370,7 @@ void QGtk2FileDialogHelper::onSelectionChanged(GtkDialog *gtkDialog, QGtk2FileDi selection = QString::fromUtf8(filename); g_free(filename); } - emit helper->currentChanged(selection); + emit helper->currentChanged(QUrl::fromLocalFile(selection)); } void QGtk2FileDialogHelper::onCurrentFolderChanged(QGtk2FileDialogHelper *dialog) @@ -419,12 +419,12 @@ void QGtk2FileDialogHelper::applyOptions() if (!nameFilters.isEmpty()) setNameFilters(nameFilters); - const QString initialDirectory = opts->initialDirectory(); + const QString initialDirectory = opts->initialDirectory().toLocalFile(); if (!initialDirectory.isEmpty()) setDirectory(initialDirectory); - foreach (const QString &filename, opts->initiallySelectedFiles()) - selectFile(filename); + foreach (const QUrl &filename, opts->initiallySelectedFiles()) + selectFile(filename.toLocalFile()); const QString initialNameFilter = opts->initiallySelectedNameFilter(); if (!initialNameFilter.isEmpty()) diff --git a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.h b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.h index c2d12625f5..47a6153fbc 100644 --- a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.h +++ b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.h @@ -90,10 +90,10 @@ public: void hide(); bool defaultNameFilterDisables() const; - void setDirectory(const QString &directory); - QString directory() const; - void selectFile(const QString &filename); - QStringList selectedFiles() const; + void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + QUrl directory() const Q_DECL_OVERRIDE; + void selectFile(const QUrl &filename) Q_DECL_OVERRIDE; + QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; void setFilter(); void selectNameFilter(const QString &filter); QString selectedNameFilter() const; @@ -107,8 +107,8 @@ private: void applyOptions(); void setNameFilters(const QStringList &filters); - QString _dir; - QStringList _selection; + QUrl _dir; + QList<QUrl> _selection; QHash<QString, GtkFileFilter*> _filters; QHash<GtkFileFilter*, QString> _filterNames; QScopedPointer<QGtk2Dialog> d; |