diff options
Diffstat (limited to 'src/plugins')
220 files changed, 8146 insertions, 8307 deletions
diff --git a/src/plugins/accessible/accessible.pro b/src/plugins/accessible/accessible.pro deleted file mode 100644 index 26c7d3066d..0000000000 --- a/src/plugins/accessible/accessible.pro +++ /dev/null @@ -1,5 +0,0 @@ -TEMPLATE = subdirs - -contains(QT_CONFIG, accessibility) { - SUBDIRS += widgets -} diff --git a/src/plugins/accessible/widgets/complexwidgets.cpp b/src/plugins/accessible/widgets/complexwidgets.cpp deleted file mode 100644 index 5f3b6b4bd6..0000000000 --- a/src/plugins/accessible/widgets/complexwidgets.cpp +++ /dev/null @@ -1,459 +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 "complexwidgets.h" - -#include <qaccessible.h> -#include <qapplication.h> -#include <qabstractbutton.h> -#include <qevent.h> -#include <qheaderview.h> -#include <qtabbar.h> -#include <qcombobox.h> -#include <qlistview.h> -#include <qtableview.h> -#include <qlineedit.h> -#include <qstyle.h> -#include <qstyleoption.h> -#include <qtooltip.h> -#include <qwhatsthis.h> -#include <qtreeview.h> -#include <private/qtabbar_p.h> -#include <QAbstractScrollArea> -#include <QScrollArea> -#include <QScrollBar> -#include <QDebug> - -#ifndef QT_NO_ACCESSIBILITY - -QT_BEGIN_NAMESPACE - -QString Q_GUI_EXPORT qt_accStripAmp(const QString &text); - -#ifndef QT_NO_TABBAR -/*! - \class QAccessibleTabBar - \brief The QAccessibleTabBar class implements the QAccessibleInterface for tab bars. - \internal - - \ingroup accessibility -*/ - -class QAccessibleTabButton: public QAccessibleInterface, public QAccessibleActionInterface -{ -public: - QAccessibleTabButton(QTabBar *parent, int index) - : m_parent(parent), m_index(index) - {} - - void *interface_cast(QAccessible::InterfaceType t) { - if (t == QAccessible::ActionInterface) { - return static_cast<QAccessibleActionInterface*>(this); - } - return 0; - } - - QObject *object() const { return 0; } - QAccessible::Role role() const { return QAccessible::PageTab; } - QAccessible::State state() const { - QAccessibleInterface *parentInterface = parent(); - QAccessible::State state = parentInterface->state(); - return state; - } - QRect rect() const { - if (!isValid()) - return QRect(); - - QPoint tp = m_parent->mapToGlobal(QPoint(0,0)); - QRect rec = m_parent->tabRect(m_index); - rec = QRect(tp.x() + rec.x(), tp.y() + rec.y(), rec.width(), rec.height()); - return rec; - } - - bool isValid() const { return true; }// (!m_parent.isNull()) && m_parent->count() > m_index; } - - QAccessibleInterface *childAt(int, int) const { return 0; } - int childCount() const { return 0; } - int indexOfChild(const QAccessibleInterface *) const { return -1; } - - QString text(QAccessible::Text) const { return qt_accStripAmp(m_parent->tabText(m_index)); } - void setText(QAccessible::Text, const QString &) {} - - QAccessibleInterface *parent() const { - return QAccessible::queryAccessibleInterface(m_parent); - } - QAccessibleInterface *child(int) const { return 0; } - // action interface - QStringList actionNames() const - { - return QStringList(pressAction()); - } - - void doAction(const QString &actionName) - { - if (actionName == pressAction()) - m_parent->setCurrentIndex(m_index); - } - - QStringList keyBindingsForAction(const QString &) const - { - return QStringList(); - } - - int index() const { return m_index; } - -private: - QPointer<QTabBar> m_parent; - int m_index; - -}; - -/*! - Constructs a QAccessibleTabBar object for \a w. -*/ -QAccessibleTabBar::QAccessibleTabBar(QWidget *w) -: QAccessibleWidget(w, QAccessible::PageTabList) -{ - Q_ASSERT(tabBar()); -} - -QAccessibleTabBar::~QAccessibleTabBar() -{ - foreach (QAccessible::Id id, m_childInterfaces.values()) - QAccessible::deleteAccessibleInterface(id); -} - -/*! Returns the QTabBar. */ -QTabBar *QAccessibleTabBar::tabBar() const -{ - return qobject_cast<QTabBar*>(object()); -} - -QAccessibleInterface* QAccessibleTabBar::child(int index) const -{ - if (QAccessible::Id id = m_childInterfaces.value(index)) - return QAccessible::accessibleInterface(id); - - // first the tabs, then 2 buttons - if (index < tabBar()->count()) { - QAccessibleTabButton *button = new QAccessibleTabButton(tabBar(), index); - QAccessible::registerAccessibleInterface(button); - m_childInterfaces.insert(index, QAccessible::uniqueId(button)); - return button; - } else if (index >= tabBar()->count()) { - // left button - if (index - tabBar()->count() == 0) { - return QAccessible::queryAccessibleInterface(tabBar()->d_func()->leftB); - } - // right button - if (index - tabBar()->count() == 1) { - return QAccessible::queryAccessibleInterface(tabBar()->d_func()->rightB); - } - } - return 0; -} - -int QAccessibleTabBar::indexOfChild(const QAccessibleInterface *child) const -{ - if (child->object() && child->object() == tabBar()->d_func()->leftB) - return tabBar()->count(); - if (child->object() && child->object() == tabBar()->d_func()->rightB) - return tabBar()->count() + 1; - if (child->role() == QAccessible::PageTab) { - QAccessibleInterface *parent = child->parent(); - if (parent == this) { - const QAccessibleTabButton *tabButton = static_cast<const QAccessibleTabButton *>(child); - return tabButton->index(); - } - } - return -1; -} - -int QAccessibleTabBar::childCount() const -{ - // tabs + scroll buttons - return tabBar()->count() + 2; -} - -QString QAccessibleTabBar::text(QAccessible::Text t) const -{ - if (t == QAccessible::Name) { - return qt_accStripAmp(tabBar()->tabText(tabBar()->currentIndex())); - } - return QString(); -} - -#endif // QT_NO_TABBAR - -#ifndef QT_NO_COMBOBOX -/*! - \class QAccessibleComboBox - \brief The QAccessibleComboBox class implements the QAccessibleInterface for editable and read-only combo boxes. - \internal - - \ingroup accessibility -*/ - -/*! - Constructs a QAccessibleComboBox object for \a w. -*/ -QAccessibleComboBox::QAccessibleComboBox(QWidget *w) -: QAccessibleWidget(w, QAccessible::ComboBox) -{ - Q_ASSERT(comboBox()); -} - -/*! - Returns the combobox. -*/ -QComboBox *QAccessibleComboBox::comboBox() const -{ - return qobject_cast<QComboBox*>(object()); -} - -QAccessibleInterface *QAccessibleComboBox::child(int index) const -{ - if (index == 0) { - QAbstractItemView *view = comboBox()->view(); - //QWidget *parent = view ? view->parentWidget() : 0; - return QAccessible::queryAccessibleInterface(view); - } else if (index == 1 && comboBox()->isEditable()) { - return QAccessible::queryAccessibleInterface(comboBox()->lineEdit()); - } - return 0; -} - -int QAccessibleComboBox::childCount() const -{ - // list and text edit - return comboBox()->isEditable() ? 2 : 1; -} - -QAccessibleInterface *QAccessibleComboBox::childAt(int x, int y) const -{ - if (comboBox()->isEditable() && comboBox()->lineEdit()->rect().contains(x, y)) - return child(1); - return 0; -} - -int QAccessibleComboBox::indexOfChild(const QAccessibleInterface *child) const -{ - if (comboBox()->view() == child->object()) - return 0; - if (comboBox()->isEditable() && comboBox()->lineEdit() == child->object()) - return 1; - return -1; -} - -/*! \reimp */ -QString QAccessibleComboBox::text(QAccessible::Text t) const -{ - QString str; - - switch (t) { - case QAccessible::Name: -#ifndef Q_OS_UNIX // on Linux we use relations for this, name is text (fall through to Value) - str = QAccessibleWidget::text(t); - break; -#endif - case QAccessible::Value: - if (comboBox()->isEditable()) - str = comboBox()->lineEdit()->text(); - else - str = comboBox()->currentText(); - break; -#ifndef QT_NO_SHORTCUT - case QAccessible::Accelerator: - str = QKeySequence(Qt::Key_Down).toString(QKeySequence::NativeText); - break; -#endif - default: - break; - } - if (str.isEmpty()) - str = QAccessibleWidget::text(t); - return str; -} - -QStringList QAccessibleComboBox::actionNames() const -{ - return QStringList() << showMenuAction() << pressAction(); -} - -QString QAccessibleComboBox::localizedActionDescription(const QString &actionName) const -{ - if (actionName == showMenuAction() || actionName == pressAction()) - return QComboBox::tr("Open the combo box selection popup"); - return QString(); -} - -void QAccessibleComboBox::doAction(const QString &actionName) -{ - if (actionName == showMenuAction() || actionName == pressAction()) { - if (comboBox()->view()->isVisible()) { - comboBox()->hidePopup(); - } else { - comboBox()->showPopup(); - } - } -} - -QStringList QAccessibleComboBox::keyBindingsForAction(const QString &/*actionName*/) const -{ - return QStringList(); -} - -#endif // QT_NO_COMBOBOX - -#ifndef QT_NO_SCROLLAREA -// ======================= QAccessibleAbstractScrollArea ======================= -QAccessibleAbstractScrollArea::QAccessibleAbstractScrollArea(QWidget *widget) - : QAccessibleWidget(widget, QAccessible::Client) -{ - Q_ASSERT(qobject_cast<QAbstractScrollArea *>(widget)); -} - -QAccessibleInterface *QAccessibleAbstractScrollArea::child(int index) const -{ - return QAccessible::queryAccessibleInterface(accessibleChildren().at(index)); -} - -int QAccessibleAbstractScrollArea::childCount() const -{ - return accessibleChildren().count(); -} - -int QAccessibleAbstractScrollArea::indexOfChild(const QAccessibleInterface *child) const -{ - if (!child || !child->object()) - return -1; - return accessibleChildren().indexOf(qobject_cast<QWidget *>(child->object())); -} - -bool QAccessibleAbstractScrollArea::isValid() const -{ - return (QAccessibleWidget::isValid() && abstractScrollArea() && abstractScrollArea()->viewport()); -} - -QAccessibleInterface *QAccessibleAbstractScrollArea::childAt(int x, int y) const -{ - if (!abstractScrollArea()->isVisible()) - return 0; - - for (int i = 0; i < childCount(); ++i) { - QPoint wpos = accessibleChildren().at(i)->mapToGlobal(QPoint(0, 0)); - QRect rect = QRect(wpos, accessibleChildren().at(i)->size()); - if (rect.contains(x, y)) - return child(i); - } - return 0; -} - -QAbstractScrollArea *QAccessibleAbstractScrollArea::abstractScrollArea() const -{ - return static_cast<QAbstractScrollArea *>(object()); -} - -QWidgetList QAccessibleAbstractScrollArea::accessibleChildren() const -{ - QWidgetList children; - - // Viewport. - QWidget * viewport = abstractScrollArea()->viewport(); - if (viewport) - children.append(viewport); - - // Horizontal scrollBar container. - QScrollBar *horizontalScrollBar = abstractScrollArea()->horizontalScrollBar(); - if (horizontalScrollBar && horizontalScrollBar->isVisible()) { - children.append(horizontalScrollBar->parentWidget()); - } - - // Vertical scrollBar container. - QScrollBar *verticalScrollBar = abstractScrollArea()->verticalScrollBar(); - if (verticalScrollBar && verticalScrollBar->isVisible()) { - children.append(verticalScrollBar->parentWidget()); - } - - // CornerWidget. - QWidget *cornerWidget = abstractScrollArea()->cornerWidget(); - if (cornerWidget && cornerWidget->isVisible()) - children.append(cornerWidget); - - return children; -} - -QAccessibleAbstractScrollArea::AbstractScrollAreaElement -QAccessibleAbstractScrollArea::elementType(QWidget *widget) const -{ - if (!widget) - return Undefined; - - if (widget == abstractScrollArea()) - return Self; - if (widget == abstractScrollArea()->viewport()) - return Viewport; - if (widget->objectName() == QLatin1String("qt_scrollarea_hcontainer")) - return HorizontalContainer; - if (widget->objectName() == QLatin1String("qt_scrollarea_vcontainer")) - return VerticalContainer; - if (widget == abstractScrollArea()->cornerWidget()) - return CornerWidget; - - return Undefined; -} - -bool QAccessibleAbstractScrollArea::isLeftToRight() const -{ - return abstractScrollArea()->isLeftToRight(); -} - -// ======================= QAccessibleScrollArea =========================== -QAccessibleScrollArea::QAccessibleScrollArea(QWidget *widget) - : QAccessibleAbstractScrollArea(widget) -{ - Q_ASSERT(qobject_cast<QScrollArea *>(widget)); -} -#endif // QT_NO_SCROLLAREA - -QT_END_NAMESPACE - -#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/widgets/complexwidgets.h b/src/plugins/accessible/widgets/complexwidgets.h deleted file mode 100644 index 00186282f3..0000000000 --- a/src/plugins/accessible/widgets/complexwidgets.h +++ /dev/null @@ -1,145 +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 COMPLEXWIDGETS_H -#define COMPLEXWIDGETS_H - -#include <QtCore/qpointer.h> -#include <QtWidgets/qaccessiblewidget.h> -#include <QtWidgets/qabstractitemview.h> - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_ACCESSIBILITY - -class QAbstractButton; -class QHeaderView; -class QTabBar; -class QComboBox; -class QTitleBar; -class QAbstractScrollArea; -class QScrollArea; - -#ifndef QT_NO_SCROLLAREA -class QAccessibleAbstractScrollArea : public QAccessibleWidget -{ -public: - explicit QAccessibleAbstractScrollArea(QWidget *widget); - - enum AbstractScrollAreaElement { - Self = 0, - Viewport, - HorizontalContainer, - VerticalContainer, - CornerWidget, - Undefined - }; - - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - int childCount() const Q_DECL_OVERRIDE; - int indexOfChild(const QAccessibleInterface *child) const Q_DECL_OVERRIDE; - bool isValid() const Q_DECL_OVERRIDE; - QAccessibleInterface *childAt(int x, int y) const Q_DECL_OVERRIDE; - -//protected: - QAbstractScrollArea *abstractScrollArea() const; - -private: - QWidgetList accessibleChildren() const; - AbstractScrollAreaElement elementType(QWidget *widget) const; - bool isLeftToRight() const; -}; - -class QAccessibleScrollArea : public QAccessibleAbstractScrollArea -{ -public: - explicit QAccessibleScrollArea(QWidget *widget); -}; -#endif // QT_NO_SCROLLAREA - -#ifndef QT_NO_TABBAR -class QAccessibleTabBar : public QAccessibleWidget -{ -public: - explicit QAccessibleTabBar(QWidget *w); - ~QAccessibleTabBar(); - - int childCount() const Q_DECL_OVERRIDE; - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - - QAccessibleInterface* child(int index) const Q_DECL_OVERRIDE; - int indexOfChild(const QAccessibleInterface *child) const Q_DECL_OVERRIDE; - -protected: - QTabBar *tabBar() const; - mutable QHash<int, QAccessible::Id> m_childInterfaces; -}; -#endif // QT_NO_TABBAR - -#ifndef QT_NO_COMBOBOX -class QAccessibleComboBox : public QAccessibleWidget -{ -public: - explicit QAccessibleComboBox(QWidget *w); - - int childCount() const Q_DECL_OVERRIDE; - QAccessibleInterface *childAt(int x, int y) const Q_DECL_OVERRIDE; - int indexOfChild(const QAccessibleInterface *child) const Q_DECL_OVERRIDE; - QAccessibleInterface* child(int index) const Q_DECL_OVERRIDE; - - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - - // QAccessibleActionInterface - QStringList actionNames() const Q_DECL_OVERRIDE; - QString localizedActionDescription(const QString &actionName) const Q_DECL_OVERRIDE; - void doAction(const QString &actionName) Q_DECL_OVERRIDE; - QStringList keyBindingsForAction(const QString &actionName) const Q_DECL_OVERRIDE; - -protected: - QComboBox *comboBox() const; -}; -#endif // QT_NO_COMBOBOX - -#endif // QT_NO_ACCESSIBILITY - -QT_END_NAMESPACE - -#endif // COMPLEXWIDGETS_H diff --git a/src/plugins/accessible/widgets/itemviews.cpp b/src/plugins/accessible/widgets/itemviews.cpp deleted file mode 100644 index 7d3668ee5a..0000000000 --- a/src/plugins/accessible/widgets/itemviews.cpp +++ /dev/null @@ -1,1222 +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 "itemviews.h" - -#include <qheaderview.h> -#include <qtableview.h> -#include <qlistview.h> -#include <qtreeview.h> -#include <private/qtreewidget_p.h> - -#ifndef QT_NO_ACCESSIBILITY - -QT_BEGIN_NAMESPACE - -QString Q_GUI_EXPORT qt_accStripAmp(const QString &text); - -#ifndef QT_NO_ITEMVIEWS -/* -Implementation of the IAccessible2 table2 interface. Much simpler than -the other table interfaces since there is only the main table and cells: - -TABLE/LIST/TREE - |- HEADER CELL - |- CELL - |- CELL - ... -*/ - - -QAbstractItemView *QAccessibleTable::view() const -{ - return qobject_cast<QAbstractItemView*>(object()); -} - -int QAccessibleTable::logicalIndex(const QModelIndex &index) const -{ - if (!view()->model() || !index.isValid()) - return -1; - int vHeader = verticalHeader() ? 1 : 0; - int hHeader = horizontalHeader() ? 1 : 0; - return (index.row() + hHeader)*(index.model()->columnCount() + vHeader) + (index.column() + vHeader); -} - -QAccessibleTable::QAccessibleTable(QWidget *w) - : QAccessibleObject(w) -{ - Q_ASSERT(view()); - - if (qobject_cast<const QTableView*>(view())) { - m_role = QAccessible::Table; - } else if (qobject_cast<const QTreeView*>(view())) { - m_role = QAccessible::Tree; - } else if (qobject_cast<const QListView*>(view())) { - m_role = QAccessible::List; - } else { - // is this our best guess? - m_role = QAccessible::Table; - } -} - -bool QAccessibleTable::isValid() const -{ - return (view() && !qobject_cast<QWidget*>(view())->d_func()->data.in_destructor); -} - -QAccessibleTable::~QAccessibleTable() -{ - Q_FOREACH (QAccessible::Id id, childToId.values()) - QAccessible::deleteAccessibleInterface(id); -} - -QHeaderView *QAccessibleTable::horizontalHeader() const -{ - QHeaderView *header = 0; - if (false) { -#ifndef QT_NO_TABLEVIEW - } else if (const QTableView *tv = qobject_cast<const QTableView*>(view())) { - header = tv->horizontalHeader(); -#endif -#ifndef QT_NO_TREEVIEW - } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view())) { - header = tv->header(); -#endif - } - return header; -} - -QHeaderView *QAccessibleTable::verticalHeader() const -{ - QHeaderView *header = 0; - if (false) { -#ifndef QT_NO_TABLEVIEW - } else if (const QTableView *tv = qobject_cast<const QTableView*>(view())) { - header = tv->verticalHeader(); -#endif - } - return header; -} - -QAccessibleInterface *QAccessibleTable::cellAt(int row, int column) const -{ - if (!view()->model()) - return 0; - Q_ASSERT(role() != QAccessible::Tree); - QModelIndex index = view()->model()->index(row, column, view()->rootIndex()); - if (!index.isValid()) { - qWarning() << "QAccessibleTable::cellAt: invalid index: " << index << " for " << view(); - return 0; - } - return child(logicalIndex(index)); -} - -QAccessibleInterface *QAccessibleTable::caption() const -{ - return 0; -} - -QString QAccessibleTable::columnDescription(int column) const -{ - if (!view()->model()) - return QString(); - return view()->model()->headerData(column, Qt::Horizontal).toString(); -} - -int QAccessibleTable::columnCount() const -{ - if (!view()->model()) - return 0; - return view()->model()->columnCount(); -} - -int QAccessibleTable::rowCount() const -{ - if (!view()->model()) - return 0; - return view()->model()->rowCount(); -} - -int QAccessibleTable::selectedCellCount() const -{ - if (!view()->selectionModel()) - return 0; - return view()->selectionModel()->selectedIndexes().count(); -} - -int QAccessibleTable::selectedColumnCount() const -{ - if (!view()->selectionModel()) - return 0; - return view()->selectionModel()->selectedColumns().count(); -} - -int QAccessibleTable::selectedRowCount() const -{ - if (!view()->selectionModel()) - return 0; - return view()->selectionModel()->selectedRows().count(); -} - -QString QAccessibleTable::rowDescription(int row) const -{ - if (!view()->model()) - return QString(); - return view()->model()->headerData(row, Qt::Vertical).toString(); -} - -QList<QAccessibleInterface *> QAccessibleTable::selectedCells() const -{ - QList<QAccessibleInterface*> cells; - if (!view()->selectionModel()) - return cells; - Q_FOREACH (const QModelIndex &index, view()->selectionModel()->selectedIndexes()) - cells.append(child(logicalIndex(index))); - return cells; -} - -QList<int> QAccessibleTable::selectedColumns() const -{ - if (!view()->selectionModel()) - return QList<int>(); - QList<int> columns; - Q_FOREACH (const QModelIndex &index, view()->selectionModel()->selectedColumns()) { - columns.append(index.column()); - } - return columns; -} - -QList<int> QAccessibleTable::selectedRows() const -{ - if (!view()->selectionModel()) - return QList<int>(); - QList<int> rows; - Q_FOREACH (const QModelIndex &index, view()->selectionModel()->selectedRows()) { - rows.append(index.row()); - } - return rows; -} - -QAccessibleInterface *QAccessibleTable::summary() const -{ - return 0; -} - -bool QAccessibleTable::isColumnSelected(int column) const -{ - if (!view()->selectionModel()) - return false; - return view()->selectionModel()->isColumnSelected(column, QModelIndex()); -} - -bool QAccessibleTable::isRowSelected(int row) const -{ - if (!view()->selectionModel()) - return false; - return view()->selectionModel()->isRowSelected(row, QModelIndex()); -} - -bool QAccessibleTable::selectRow(int row) -{ - if (!view()->model() || !view()->selectionModel()) - return false; - QModelIndex index = view()->model()->index(row, 0, view()->rootIndex()); - - if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectColumns) - return false; - - switch (view()->selectionMode()) { - case QAbstractItemView::NoSelection: - return false; - case QAbstractItemView::SingleSelection: - if (view()->selectionBehavior() != QAbstractItemView::SelectRows && columnCount() > 1 ) - return false; - view()->clearSelection(); - break; - case QAbstractItemView::ContiguousSelection: - if ((!row || !view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex())) - && !view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex())) - view()->clearSelection(); - break; - default: - break; - } - - view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows); - return true; -} - -bool QAccessibleTable::selectColumn(int column) -{ - if (!view()->model() || !view()->selectionModel()) - return false; - QModelIndex index = view()->model()->index(0, column, view()->rootIndex()); - - if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectRows) - return false; - - switch (view()->selectionMode()) { - case QAbstractItemView::NoSelection: - return false; - case QAbstractItemView::SingleSelection: - if (view()->selectionBehavior() != QAbstractItemView::SelectColumns && rowCount() > 1) - return false; - case QAbstractItemView::ContiguousSelection: - if ((!column || !view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex())) - && !view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex())) - view()->clearSelection(); - break; - default: - break; - } - - view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Columns); - return true; -} - -bool QAccessibleTable::unselectRow(int row) -{ - if (!view()->model() || !view()->selectionModel()) - return false; - - QModelIndex index = view()->model()->index(row, 0, view()->rootIndex()); - if (!index.isValid()) - return false; - - QItemSelection selection(index, index); - - switch (view()->selectionMode()) { - case QAbstractItemView::SingleSelection: - //In SingleSelection and ContiguousSelection once an item - //is selected, there's no way for the user to unselect all items - if (selectedRowCount() == 1) - return false; - break; - case QAbstractItemView::ContiguousSelection: - if (selectedRowCount() == 1) - return false; - - if ((!row || view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex())) - && view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex())) { - //If there are rows selected both up the current row and down the current rown, - //the ones which are down the current row will be deselected - selection = QItemSelection(index, view()->model()->index(rowCount() - 1, 0, view()->rootIndex())); - } - default: - break; - } - - view()->selectionModel()->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Rows); - return true; -} - -bool QAccessibleTable::unselectColumn(int column) -{ - if (!view()->model() || !view()->selectionModel()) - return false; - - QModelIndex index = view()->model()->index(0, column, view()->rootIndex()); - if (!index.isValid()) - return false; - - QItemSelection selection(index, index); - - switch (view()->selectionMode()) { - case QAbstractItemView::SingleSelection: - //In SingleSelection and ContiguousSelection once an item - //is selected, there's no way for the user to unselect all items - if (selectedColumnCount() == 1) - return false; - break; - case QAbstractItemView::ContiguousSelection: - if (selectedColumnCount() == 1) - return false; - - if ((!column || view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex())) - && view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex())) { - //If there are columns selected both at the left of the current row and at the right - //of the current rown, the ones which are at the right will be deselected - selection = QItemSelection(index, view()->model()->index(0, columnCount() - 1, view()->rootIndex())); - } - default: - break; - } - - view()->selectionModel()->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Columns); - return true; -} - -QAccessible::Role QAccessibleTable::role() const -{ - return m_role; -} - -QAccessible::State QAccessibleTable::state() const -{ - return QAccessible::State(); -} - -QAccessibleInterface *QAccessibleTable::childAt(int x, int y) const -{ - QPoint viewportOffset = view()->viewport()->mapTo(view(), QPoint(0,0)); - QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset); - // FIXME: if indexPosition < 0 in one coordinate, return header - - QModelIndex index = view()->indexAt(indexPosition); - if (index.isValid()) { - return child(logicalIndex(index)); - } - return 0; -} - -int QAccessibleTable::childCount() const -{ - if (!view()->model()) - return 0; - int vHeader = verticalHeader() ? 1 : 0; - int hHeader = horizontalHeader() ? 1 : 0; - return (view()->model()->rowCount()+hHeader) * (view()->model()->columnCount()+vHeader); -} - -int QAccessibleTable::indexOfChild(const QAccessibleInterface *iface) const -{ - if (!view()->model()) - return -1; - QAccessibleInterface *parent = iface->parent(); - if (parent->object() != view()) - return -1; - - Q_ASSERT(iface->role() != QAccessible::TreeItem); // should be handled by tree class - if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) { - const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface); - return logicalIndex(cell->m_index); - } else if (iface->role() == QAccessible::ColumnHeader){ - const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface); - return cell->index + (verticalHeader() ? 1 : 0); - } else if (iface->role() == QAccessible::RowHeader){ - const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface); - return (cell->index + 1) * (view()->model()->columnCount() + 1); - } else if (iface->role() == QAccessible::Pane) { - return 0; // corner button - } else { - qWarning() << "WARNING QAccessibleTable::indexOfChild Fix my children..." - << iface->role() << iface->text(QAccessible::Name); - } - // FIXME: we are in denial of our children. this should stop. - return -1; -} - -QString QAccessibleTable::text(QAccessible::Text t) const -{ - if (t == QAccessible::Description) - return view()->accessibleDescription(); - return view()->accessibleName(); -} - -QRect QAccessibleTable::rect() const -{ - if (!view()->isVisible()) - return QRect(); - QPoint pos = view()->mapToGlobal(QPoint(0, 0)); - return QRect(pos.x(), pos.y(), view()->width(), view()->height()); -} - -QAccessibleInterface *QAccessibleTable::parent() const -{ - if (view() && view()->parent()) { - if (qstrcmp("QComboBoxPrivateContainer", view()->parent()->metaObject()->className()) == 0) { - return QAccessible::queryAccessibleInterface(view()->parent()->parent()); - } - return QAccessible::queryAccessibleInterface(view()->parent()); - } - return 0; -} - -QAccessibleInterface *QAccessibleTable::child(int logicalIndex) const -{ - if (!view()->model()) - return 0; - - if (childToId.contains(logicalIndex)) { - QAccessible::Id id = childToId.value(logicalIndex); - return QAccessible::accessibleInterface(id); - } - - int vHeader = verticalHeader() ? 1 : 0; - int hHeader = horizontalHeader() ? 1 : 0; - - int columns = view()->model()->columnCount() + vHeader; - - int row = logicalIndex / columns; - int column = logicalIndex % columns; - - QAccessibleInterface *iface = 0; - - if (vHeader) { - if (column == 0) { - if (hHeader && row == 0) { - iface = new QAccessibleTableCornerButton(view()); - } else { - iface = new QAccessibleTableHeaderCell(view(), row - hHeader, Qt::Vertical); - } - } - --column; - } - if (!iface && hHeader) { - if (row == 0) { - iface = new QAccessibleTableHeaderCell(view(), column, Qt::Horizontal); - } - --row; - } - - if (!iface) { - QModelIndex index = view()->model()->index(row, column, view()->rootIndex()); - if (!index.isValid()) { - qWarning() << "QAccessibleTable::child: Invalid index at: " << row << column; - return 0; - } - iface = new QAccessibleTableCell(view(), index, cellRole()); - } - - QAccessible::registerAccessibleInterface(iface); - childToId.insert(logicalIndex, QAccessible::uniqueId(iface)); - return iface; -} - -void *QAccessibleTable::interface_cast(QAccessible::InterfaceType t) -{ - if (t == QAccessible::TableInterface) - return static_cast<QAccessibleTableInterface*>(this); - return 0; -} - -void QAccessibleTable::modelChange(QAccessibleTableModelChangeEvent *event) -{ - // if there is no cache yet, we don't update anything - if (childToId.isEmpty()) - return; - - switch (event->modelChangeType()) { - case QAccessibleTableModelChangeEvent::ModelReset: - Q_FOREACH (QAccessible::Id id, childToId.values()) - QAccessible::deleteAccessibleInterface(id); - childToId.clear(); - break; - - // rows are inserted: move every row after that - case QAccessibleTableModelChangeEvent::RowsInserted: - case QAccessibleTableModelChangeEvent::ColumnsInserted: { - int newRows = event->lastRow() - event->firstRow() + 1; - int newColumns = event->lastColumn() - event->firstColumn() + 1; - - ChildCache newCache; - ChildCache::ConstIterator iter = childToId.constBegin(); - - while (iter != childToId.constEnd()) { - QAccessible::Id id = iter.value(); - QAccessibleInterface *iface = QAccessible::accessibleInterface(id); - Q_ASSERT(iface); - if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) { - Q_ASSERT(iface->tableCellInterface()); - QAccessibleTableCell *cell = static_cast<QAccessibleTableCell*>(iface->tableCellInterface()); - if (event->modelChangeType() == QAccessibleTableModelChangeEvent::RowsInserted - && cell->m_index.row() >= event->firstRow()) { - int newRow = cell->m_index.row() + newRows; - cell->m_index = cell->m_index.sibling(newRow, cell->m_index.column()); - } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::ColumnsInserted - && cell->m_index.column() >= event->firstColumn()) { - int newColumn = cell->m_index.column() + newColumns; - cell->m_index = cell->m_index.sibling(cell->m_index.row(), newColumn); - } - } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::RowsInserted - && iface->role() == QAccessible::RowHeader) { - QAccessibleTableHeaderCell *cell = static_cast<QAccessibleTableHeaderCell*>(iface); - if (cell->index >= event->firstRow()) { - cell->index += newRows; - } - } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::ColumnsInserted - && iface->role() == QAccessible::ColumnHeader) { - QAccessibleTableHeaderCell *cell = static_cast<QAccessibleTableHeaderCell*>(iface); - if (cell->index >= event->firstColumn()) { - cell->index += newColumns; - } - } - if (indexOfChild(iface) >= 0) { - newCache.insert(indexOfChild(iface), id); - } else { - // ### This should really not happen, - // but it might if the view has a root index set. - // This needs to be fixed. - QAccessible::deleteAccessibleInterface(id); - } - ++iter; - } - childToId = newCache; - break; - } - - case QAccessibleTableModelChangeEvent::ColumnsRemoved: - case QAccessibleTableModelChangeEvent::RowsRemoved: { - int deletedColumns = event->lastColumn() - event->firstColumn() + 1; - int deletedRows = event->lastRow() - event->firstRow() + 1; - ChildCache newCache; - ChildCache::ConstIterator iter = childToId.constBegin(); - while (iter != childToId.constEnd()) { - QAccessible::Id id = iter.value(); - QAccessibleInterface *iface = QAccessible::accessibleInterface(id); - Q_ASSERT(iface); - if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) { - Q_ASSERT(iface->tableCellInterface()); - QAccessibleTableCell *cell = static_cast<QAccessibleTableCell*>(iface->tableCellInterface()); - if (event->modelChangeType() == QAccessibleTableModelChangeEvent::RowsRemoved) { - if (cell->m_index.row() < event->firstRow()) { - newCache.insert(indexOfChild(cell), id); - } else if (cell->m_index.row() > event->lastRow()) { - int newRow = cell->m_index.row() - deletedRows; - cell->m_index = cell->m_index.sibling(newRow, cell->m_index.column()); - newCache.insert(indexOfChild(cell), id); - } else { - QAccessible::deleteAccessibleInterface(id); - } - } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::ColumnsRemoved) { - if (cell->m_index.column() < event->firstColumn()) { - newCache.insert(indexOfChild(cell), id); - } else if (cell->m_index.column() > event->lastColumn()) { - int newColumn = cell->m_index.column() - deletedColumns; - cell->m_index = cell->m_index.sibling(cell->m_index.row(), newColumn); - newCache.insert(indexOfChild(cell), id); - } else { - QAccessible::deleteAccessibleInterface(id); - } - } - } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::RowsRemoved - && iface->role() == QAccessible::RowHeader) { - QAccessibleTableHeaderCell *cell = static_cast<QAccessibleTableHeaderCell*>(iface); - if (cell->index < event->firstRow()) { - newCache.insert(indexOfChild(cell), id); - } else if (cell->index > event->lastRow()) { - cell->index -= deletedRows; - newCache.insert(indexOfChild(cell), id); - } else { - QAccessible::deleteAccessibleInterface(id); - } - } else if (event->modelChangeType() == QAccessibleTableModelChangeEvent::ColumnsRemoved - && iface->role() == QAccessible::ColumnHeader) { - QAccessibleTableHeaderCell *cell = static_cast<QAccessibleTableHeaderCell*>(iface); - if (cell->index < event->firstColumn()) { - newCache.insert(indexOfChild(cell), id); - } else if (cell->index > event->lastColumn()) { - cell->index -= deletedColumns; - newCache.insert(indexOfChild(cell), id); - } else { - QAccessible::deleteAccessibleInterface(id); - } - } - ++iter; - } - childToId = newCache; - break; - } - - case QAccessibleTableModelChangeEvent::DataChanged: - // nothing to do in this case - break; - } -} - -// TREE VIEW - -QModelIndex QAccessibleTree::indexFromLogical(int row, int column) const -{ - if (!isValid() || !view()->model()) - return QModelIndex(); - - const QTreeView *treeView = qobject_cast<const QTreeView*>(view()); - if ((row < 0) || (column < 0) || (treeView->d_func()->viewItems.count() <= row)) { - qWarning() << "QAccessibleTree::indexFromLogical: invalid index: " << row << column << " for " << treeView; - return QModelIndex(); - } - QModelIndex modelIndex = treeView->d_func()->viewItems.at(row).index; - - if (modelIndex.isValid() && column > 0) { - modelIndex = view()->model()->index(modelIndex.row(), column, modelIndex.parent()); - } - return modelIndex; -} - -QAccessibleInterface *QAccessibleTree::childAt(int x, int y) const -{ - if (!view()->model()) - return 0; - QPoint viewportOffset = view()->viewport()->mapTo(view(), QPoint(0,0)); - QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset); - - QModelIndex index = view()->indexAt(indexPosition); - if (!index.isValid()) - return 0; - - const QTreeView *treeView = qobject_cast<const QTreeView*>(view()); - int row = treeView->d_func()->viewIndex(index) + (horizontalHeader() ? 1 : 0); - int column = index.column(); - - int i = row * view()->model()->columnCount() + column; - return child(i); -} - -int QAccessibleTree::childCount() const -{ - const QTreeView *treeView = qobject_cast<const QTreeView*>(view()); - Q_ASSERT(treeView); - if (!view()->model()) - return 0; - - int hHeader = horizontalHeader() ? 1 : 0; - return (treeView->d_func()->viewItems.count() + hHeader)* view()->model()->columnCount(); -} - - -QAccessibleInterface *QAccessibleTree::child(int logicalIndex) const -{ - if (logicalIndex < 0 || !view()->model() || !view()->model()->columnCount()) - return 0; - - QAccessibleInterface *iface = 0; - int index = logicalIndex; - - if (horizontalHeader()) { - if (index < view()->model()->columnCount()) { - iface = new QAccessibleTableHeaderCell(view(), index, Qt::Horizontal); - } else { - index -= view()->model()->columnCount(); - } - } - - if (!iface) { - int row = index / view()->model()->columnCount(); - int column = index % view()->model()->columnCount(); - QModelIndex modelIndex = indexFromLogical(row, column); - if (!modelIndex.isValid()) - return 0; - iface = new QAccessibleTableCell(view(), modelIndex, cellRole()); - } - QAccessible::registerAccessibleInterface(iface); - // ### FIXME: get interfaces from the cache instead of re-creating them - return iface; -} - -int QAccessibleTree::rowCount() const -{ - const QTreeView *treeView = qobject_cast<const QTreeView*>(view()); - Q_ASSERT(treeView); - return treeView->d_func()->viewItems.count(); -} - -int QAccessibleTree::indexOfChild(const QAccessibleInterface *iface) const -{ - if (!view()->model()) - return -1; - QAccessibleInterface *parent = iface->parent(); - if (parent->object() != view()) - return -1; - - if (iface->role() == QAccessible::TreeItem) { - const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface); - const QTreeView *treeView = qobject_cast<const QTreeView*>(view()); - Q_ASSERT(treeView); - int row = treeView->d_func()->viewIndex(cell->m_index) + (horizontalHeader() ? 1 : 0); - int column = cell->m_index.column(); - - int index = row * view()->model()->columnCount() + column; - return index; - } else if (iface->role() == QAccessible::ColumnHeader){ - const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface); - return cell->index; - } else { - qWarning() << "WARNING QAccessibleTable::indexOfChild invalid child" - << iface->role() << iface->text(QAccessible::Name); - } - // FIXME: add scrollbars and don't just ignore them - return -1; -} - -QAccessibleInterface *QAccessibleTree::cellAt(int row, int column) const -{ - QModelIndex index = indexFromLogical(row, column); - if (!index.isValid()) { - qWarning() << "Requested invalid tree cell: " << row << column; - return 0; - } - const QTreeView *treeView = qobject_cast<const QTreeView*>(view()); - Q_ASSERT(treeView); - int logicalIndex = treeView->d_func()->accessibleTable2Index(index); - - return child(logicalIndex); // FIXME ### new QAccessibleTableCell(view(), index, cellRole()); -} - -QString QAccessibleTree::rowDescription(int) const -{ - return QString(); // no headers for rows in trees -} - -bool QAccessibleTree::isRowSelected(int row) const -{ - if (!view()->selectionModel()) - return false; - QModelIndex index = indexFromLogical(row); - return view()->selectionModel()->isRowSelected(index.row(), index.parent()); -} - -bool QAccessibleTree::selectRow(int row) -{ - if (!view()->selectionModel()) - return false; - QModelIndex index = indexFromLogical(row); - - if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectColumns) - return false; - - switch (view()->selectionMode()) { - case QAbstractItemView::NoSelection: - return false; - case QAbstractItemView::SingleSelection: - if ((view()->selectionBehavior() != QAbstractItemView::SelectRows) && (columnCount() > 1)) - return false; - view()->clearSelection(); - break; - case QAbstractItemView::ContiguousSelection: - if ((!row || !view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex())) - && !view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex())) - view()->clearSelection(); - break; - default: - break; - } - - view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows); - return true; -} - -// TABLE CELL - -QAccessibleTableCell::QAccessibleTableCell(QAbstractItemView *view_, const QModelIndex &index_, QAccessible::Role role_) - : /* QAccessibleSimpleEditableTextInterface(this), */ view(view_), m_index(index_), m_role(role_) -{ - if (!index_.isValid()) - qWarning() << "QAccessibleTableCell::QAccessibleTableCell with invalid index: " << index_; -} - -void *QAccessibleTableCell::interface_cast(QAccessible::InterfaceType t) -{ - if (t == QAccessible::TableCellInterface) - return static_cast<QAccessibleTableCellInterface*>(this); - if (t == QAccessible::ActionInterface) - return static_cast<QAccessibleActionInterface*>(this); - return 0; -} - -int QAccessibleTableCell::columnExtent() const { return 1; } -int QAccessibleTableCell::rowExtent() const { return 1; } - -QList<QAccessibleInterface*> QAccessibleTableCell::rowHeaderCells() const -{ - QList<QAccessibleInterface*> headerCell; - if (verticalHeader()) { - // FIXME - headerCell.append(new QAccessibleTableHeaderCell(view, m_index.row(), Qt::Vertical)); - } - return headerCell; -} - -QList<QAccessibleInterface*> QAccessibleTableCell::columnHeaderCells() const -{ - QList<QAccessibleInterface*> headerCell; - if (horizontalHeader()) { - // FIXME - headerCell.append(new QAccessibleTableHeaderCell(view, m_index.column(), Qt::Horizontal)); - } - return headerCell; -} - -QHeaderView *QAccessibleTableCell::horizontalHeader() const -{ - QHeaderView *header = 0; - - if (false) { -#ifndef QT_NO_TABLEVIEW - } else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) { - header = tv->horizontalHeader(); -#endif -#ifndef QT_NO_TREEVIEW - } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view)) { - header = tv->header(); -#endif - } - - return header; -} - -QHeaderView *QAccessibleTableCell::verticalHeader() const -{ - QHeaderView *header = 0; -#ifndef QT_NO_TABLEVIEW - if (const QTableView *tv = qobject_cast<const QTableView*>(view)) - header = tv->verticalHeader(); -#endif - return header; -} - -int QAccessibleTableCell::columnIndex() const -{ - return m_index.column(); -} - -int QAccessibleTableCell::rowIndex() const -{ - if (role() == QAccessible::TreeItem) { - const QTreeView *treeView = qobject_cast<const QTreeView*>(view); - Q_ASSERT(treeView); - int row = treeView->d_func()->viewIndex(m_index); - return row; - } - return m_index.row(); -} - -bool QAccessibleTableCell::isSelected() const -{ - return view->selectionModel()->isSelected(m_index); -} - -QStringList QAccessibleTableCell::actionNames() const -{ - QStringList names; - names << toggleAction(); - return names; -} - -void QAccessibleTableCell::doAction(const QString& actionName) -{ - if (actionName == toggleAction()) { - if (isSelected()) - unselectCell(); - else - selectCell(); - } -} - -QStringList QAccessibleTableCell::keyBindingsForAction(const QString &) const -{ - return QStringList(); -} - - -void QAccessibleTableCell::selectCell() -{ - QAbstractItemView::SelectionMode selectionMode = view->selectionMode(); - if (!m_index.isValid() || (selectionMode == QAbstractItemView::NoSelection)) - return; - Q_ASSERT(table()); - QAccessibleTableInterface *cellTable = table()->tableInterface(); - - switch (view->selectionBehavior()) { - case QAbstractItemView::SelectItems: - break; - case QAbstractItemView::SelectColumns: - if (cellTable) - cellTable->selectColumn(m_index.column()); - return; - case QAbstractItemView::SelectRows: - if (cellTable) - cellTable->selectRow(m_index.row()); - return; - } - - if (selectionMode == QAbstractItemView::SingleSelection) { - view->clearSelection(); - } - - view->selectionModel()->select(m_index, QItemSelectionModel::Select); -} - -void QAccessibleTableCell::unselectCell() -{ - - QAbstractItemView::SelectionMode selectionMode = view->selectionMode(); - if (!m_index.isValid() || (selectionMode & QAbstractItemView::NoSelection)) - return; - - QAccessibleTableInterface *cellTable = table()->tableInterface(); - - switch (view->selectionBehavior()) { - case QAbstractItemView::SelectItems: - break; - case QAbstractItemView::SelectColumns: - if (cellTable) - cellTable->unselectColumn(m_index.column()); - return; - case QAbstractItemView::SelectRows: - if (cellTable) - cellTable->unselectRow(m_index.row()); - return; - } - - //If the mode is not MultiSelection or ExtendedSelection and only - //one cell is selected it cannot be unselected by the user - if ((selectionMode != QAbstractItemView::MultiSelection) - && (selectionMode != QAbstractItemView::ExtendedSelection) - && (view->selectionModel()->selectedIndexes().count() <= 1)) - return; - - view->selectionModel()->select(m_index, QItemSelectionModel::Deselect); -} - -QAccessibleInterface *QAccessibleTableCell::table() const -{ - return QAccessible::queryAccessibleInterface(view); -} - -QAccessible::Role QAccessibleTableCell::role() const -{ - return m_role; -} - -QAccessible::State QAccessibleTableCell::state() const -{ - QAccessible::State st; - QRect globalRect = view->rect(); - globalRect.translate(view->mapToGlobal(QPoint(0,0))); - if (!globalRect.intersects(rect())) - st.invisible = true; - - if (view->selectionModel()->isSelected(m_index)) - st.selected = true; - if (view->selectionModel()->currentIndex() == m_index) - st.focused = true; - if (m_index.model()->data(m_index, Qt::CheckStateRole).toInt() == Qt::Checked) - st.checked = true; - - Qt::ItemFlags flags = m_index.flags(); - if (flags & Qt::ItemIsSelectable) { - st.selectable = true; - st.focusable = true; - if (view->selectionMode() == QAbstractItemView::MultiSelection) - st.multiSelectable = true; - if (view->selectionMode() == QAbstractItemView::ExtendedSelection) - st.extSelectable = true; - } - if (m_role == QAccessible::TreeItem) { - const QTreeView *treeView = qobject_cast<const QTreeView*>(view); - if (treeView->model()->hasChildren(m_index)) - st.expandable = true; - if (treeView->isExpanded(m_index)) - st.expanded = true; - } - return st; -} - - -QRect QAccessibleTableCell::rect() const -{ - QRect r; - r = view->visualRect(m_index); - - if (!r.isNull()) { - r.translate(view->viewport()->mapTo(view, QPoint(0,0))); - r.translate(view->mapToGlobal(QPoint(0, 0))); - } - return r; -} - -QString QAccessibleTableCell::text(QAccessible::Text t) const -{ - QAbstractItemModel *model = view->model(); - QString value; - switch (t) { - case QAccessible::Name: - value = model->data(m_index, Qt::AccessibleTextRole).toString(); - if (value.isEmpty()) - value = model->data(m_index, Qt::DisplayRole).toString(); - break; - case QAccessible::Description: - value = model->data(m_index, Qt::AccessibleDescriptionRole).toString(); - break; - default: - break; - } - return value; -} - -void QAccessibleTableCell::setText(QAccessible::Text /*t*/, const QString &text) -{ - if (!(m_index.flags() & Qt::ItemIsEditable)) - return; - view->model()->setData(m_index, text); -} - -bool QAccessibleTableCell::isValid() const -{ - return view && view->model() && m_index.isValid(); -} - -QAccessibleInterface *QAccessibleTableCell::parent() const -{ - return QAccessible::queryAccessibleInterface(view); -} - -QAccessibleInterface *QAccessibleTableCell::child(int) const -{ - return 0; -} - -QAccessibleTableHeaderCell::QAccessibleTableHeaderCell(QAbstractItemView *view_, int index_, Qt::Orientation orientation_) - : view(view_), index(index_), orientation(orientation_) -{ - Q_ASSERT(index_ >= 0); -} - -QAccessible::Role QAccessibleTableHeaderCell::role() const -{ - if (orientation == Qt::Horizontal) - return QAccessible::ColumnHeader; - return QAccessible::RowHeader; -} - -QAccessible::State QAccessibleTableHeaderCell::state() const -{ - QAccessible::State s; - if (QHeaderView *h = headerView()) { - s.invisible = !h->testAttribute(Qt::WA_WState_Visible); - s.disabled = !h->isEnabled(); - } - return s; -} - -QRect QAccessibleTableHeaderCell::rect() const -{ - QHeaderView *header = 0; - if (false) { -#ifndef QT_NO_TABLEVIEW - } else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) { - if (orientation == Qt::Horizontal) { - header = tv->horizontalHeader(); - } else { - header = tv->verticalHeader(); - } -#endif -#ifndef QT_NO_TREEVIEW - } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view)) { - header = tv->header(); -#endif - } - if (!header) - return QRect(); - QPoint zero = header->mapToGlobal(QPoint(0, 0)); - int sectionSize = header->sectionSize(index); - int sectionPos = header->sectionPosition(index); - return orientation == Qt::Horizontal - ? QRect(zero.x() + sectionPos, zero.y(), sectionSize, header->height()) - : QRect(zero.x(), zero.y() + sectionPos, header->width(), sectionSize); -} - -QString QAccessibleTableHeaderCell::text(QAccessible::Text t) const -{ - QAbstractItemModel *model = view->model(); - QString value; - switch (t) { - case QAccessible::Name: - value = model->headerData(index, orientation, Qt::AccessibleTextRole).toString(); - if (value.isEmpty()) - value = model->headerData(index, orientation, Qt::DisplayRole).toString(); - break; - case QAccessible::Description: - value = model->headerData(index, orientation, Qt::AccessibleDescriptionRole).toString(); - break; - default: - break; - } - return value; -} - -void QAccessibleTableHeaderCell::setText(QAccessible::Text, const QString &) -{ - return; -} - -bool QAccessibleTableHeaderCell::isValid() const -{ - return view && view->model() && (index >= 0) - && ((orientation == Qt::Horizontal) ? (index < view->model()->columnCount()) : (index < view->model()->rowCount())); -} - -QAccessibleInterface *QAccessibleTableHeaderCell::parent() const -{ - return QAccessible::queryAccessibleInterface(view); -} - -QAccessibleInterface *QAccessibleTableHeaderCell::child(int) const -{ - return 0; -} - -QHeaderView *QAccessibleTableHeaderCell::headerView() const -{ - QHeaderView *header = 0; - if (false) { -#ifndef QT_NO_TABLEVIEW - } else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) { - if (orientation == Qt::Horizontal) { - header = tv->horizontalHeader(); - } else { - header = tv->verticalHeader(); - } -#endif -#ifndef QT_NO_TREEVIEW - } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view)) { - header = tv->header(); -#endif - } - return header; -} - -#endif // QT_NO_ITEMVIEWS - -QT_END_NAMESPACE - -#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/widgets/itemviews.h b/src/plugins/accessible/widgets/itemviews.h deleted file mode 100644 index 45a07c5972..0000000000 --- a/src/plugins/accessible/widgets/itemviews.h +++ /dev/null @@ -1,292 +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 ACCESSIBLE_ITEMVIEWS_H -#define ACCESSIBLE_ITEMVIEWS_H - -#include "QtCore/qpointer.h" -#include <QtGui/qaccessible.h> -#include <QtWidgets/qaccessiblewidget.h> -#include <QtWidgets/qabstractitemview.h> -#include <QtWidgets/qheaderview.h> - - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_ACCESSIBILITY - -#ifndef QT_NO_ITEMVIEWS - -class QAccessibleTableCell; -class QAccessibleTableHeaderCell; - -class QAccessibleTable :public QAccessibleTableInterface, public QAccessibleObject -{ -public: - explicit QAccessibleTable(QWidget *w); - bool isValid() const Q_DECL_OVERRIDE; - - QAccessible::Role role() const Q_DECL_OVERRIDE; - QAccessible::State state() const Q_DECL_OVERRIDE; - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - QRect rect() const Q_DECL_OVERRIDE; - - QAccessibleInterface *childAt(int x, int y) const Q_DECL_OVERRIDE; - int childCount() const Q_DECL_OVERRIDE; - int indexOfChild(const QAccessibleInterface *) const Q_DECL_OVERRIDE; - - QAccessibleInterface *parent() const Q_DECL_OVERRIDE; - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - - void *interface_cast(QAccessible::InterfaceType t) Q_DECL_OVERRIDE; - - // table interface - virtual QAccessibleInterface *cellAt(int row, int column) const Q_DECL_OVERRIDE; - virtual QAccessibleInterface *caption() const Q_DECL_OVERRIDE; - virtual QAccessibleInterface *summary() const Q_DECL_OVERRIDE; - virtual QString columnDescription(int column) const Q_DECL_OVERRIDE; - virtual QString rowDescription(int row) const Q_DECL_OVERRIDE; - virtual int columnCount() const Q_DECL_OVERRIDE; - virtual int rowCount() const Q_DECL_OVERRIDE; - - // selection - virtual int selectedCellCount() const Q_DECL_OVERRIDE; - virtual int selectedColumnCount() const Q_DECL_OVERRIDE; - virtual int selectedRowCount() const Q_DECL_OVERRIDE; - virtual QList<QAccessibleInterface*> selectedCells() const Q_DECL_OVERRIDE; - virtual QList<int> selectedColumns() const Q_DECL_OVERRIDE; - virtual QList<int> selectedRows() const Q_DECL_OVERRIDE; - virtual bool isColumnSelected(int column) const Q_DECL_OVERRIDE; - virtual bool isRowSelected(int row) const Q_DECL_OVERRIDE; - virtual bool selectRow(int row) Q_DECL_OVERRIDE; - virtual bool selectColumn(int column) Q_DECL_OVERRIDE; - virtual bool unselectRow(int row) Q_DECL_OVERRIDE; - virtual bool unselectColumn(int column) Q_DECL_OVERRIDE; - - QAbstractItemView *view() const; - - void modelChange(QAccessibleTableModelChangeEvent *event) Q_DECL_OVERRIDE; - -protected: - inline QAccessible::Role cellRole() const { - switch (m_role) { - case QAccessible::List: - return QAccessible::ListItem; - case QAccessible::Table: - return QAccessible::Cell; - case QAccessible::Tree: - return QAccessible::TreeItem; - default: - Q_ASSERT(0); - } - return QAccessible::NoRole; - } - - QHeaderView *horizontalHeader() const; - QHeaderView *verticalHeader() const; - - // maybe vector - typedef QHash<int, QAccessible::Id> ChildCache; - mutable ChildCache childToId; - - virtual ~QAccessibleTable(); - -private: - // the child index for a model index - inline int logicalIndex(const QModelIndex &index) const; - QAccessible::Role m_role; -}; - -class QAccessibleTree :public QAccessibleTable -{ -public: - explicit QAccessibleTree(QWidget *w) - : QAccessibleTable(w) - {} - - - QAccessibleInterface *childAt(int x, int y) const Q_DECL_OVERRIDE; - int childCount() const Q_DECL_OVERRIDE; - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - - int indexOfChild(const QAccessibleInterface *) const Q_DECL_OVERRIDE; - - int rowCount() const Q_DECL_OVERRIDE; - - // table interface - QAccessibleInterface *cellAt(int row, int column) const Q_DECL_OVERRIDE; - QString rowDescription(int row) const Q_DECL_OVERRIDE; - bool isRowSelected(int row) const Q_DECL_OVERRIDE; - bool selectRow(int row) Q_DECL_OVERRIDE; - -private: - QModelIndex indexFromLogical(int row, int column = 0) const; - - inline int logicalIndex(const QModelIndex &index) const; -}; - -class QAccessibleTableCell: public QAccessibleInterface, public QAccessibleTableCellInterface, public QAccessibleActionInterface -{ -public: - QAccessibleTableCell(QAbstractItemView *view, const QModelIndex &m_index, QAccessible::Role role); - - void *interface_cast(QAccessible::InterfaceType t) Q_DECL_OVERRIDE; - QObject *object() const Q_DECL_OVERRIDE { return 0; } - QAccessible::Role role() const Q_DECL_OVERRIDE; - QAccessible::State state() const Q_DECL_OVERRIDE; - QRect rect() const Q_DECL_OVERRIDE; - bool isValid() const Q_DECL_OVERRIDE; - - QAccessibleInterface *childAt(int, int) const Q_DECL_OVERRIDE { return 0; } - int childCount() const Q_DECL_OVERRIDE { return 0; } - int indexOfChild(const QAccessibleInterface *) const Q_DECL_OVERRIDE { return -1; } - - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - void setText(QAccessible::Text t, const QString &text) Q_DECL_OVERRIDE; - - QAccessibleInterface *parent() const Q_DECL_OVERRIDE; - QAccessibleInterface *child(int) const Q_DECL_OVERRIDE; - - // cell interface - virtual int columnExtent() const Q_DECL_OVERRIDE; - virtual QList<QAccessibleInterface*> columnHeaderCells() const Q_DECL_OVERRIDE; - virtual int columnIndex() const Q_DECL_OVERRIDE; - virtual int rowExtent() const Q_DECL_OVERRIDE; - virtual QList<QAccessibleInterface*> rowHeaderCells() const Q_DECL_OVERRIDE; - virtual int rowIndex() const Q_DECL_OVERRIDE; - virtual bool isSelected() const Q_DECL_OVERRIDE; - virtual QAccessibleInterface* table() const Q_DECL_OVERRIDE; - - //action interface - virtual QStringList actionNames() const Q_DECL_OVERRIDE; - virtual void doAction(const QString &actionName) Q_DECL_OVERRIDE; - virtual QStringList keyBindingsForAction(const QString &actionName) const Q_DECL_OVERRIDE; - -private: - QHeaderView *verticalHeader() const; - QHeaderView *horizontalHeader() const; - QPointer<QAbstractItemView > view; - QModelIndex m_index; - QAccessible::Role m_role; - - void selectCell(); - void unselectCell(); - -friend class QAccessibleTable; -friend class QAccessibleTree; -}; - - -class QAccessibleTableHeaderCell: public QAccessibleInterface -{ -public: - // For header cells, pass the header view in addition - QAccessibleTableHeaderCell(QAbstractItemView *view, int index, Qt::Orientation orientation); - - QObject *object() const Q_DECL_OVERRIDE { return 0; } - QAccessible::Role role() const Q_DECL_OVERRIDE; - QAccessible::State state() const Q_DECL_OVERRIDE; - QRect rect() const Q_DECL_OVERRIDE; - bool isValid() const Q_DECL_OVERRIDE; - - QAccessibleInterface *childAt(int, int) const Q_DECL_OVERRIDE { return 0; } - int childCount() const Q_DECL_OVERRIDE { return 0; } - int indexOfChild(const QAccessibleInterface *) const Q_DECL_OVERRIDE { return -1; } - - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - void setText(QAccessible::Text t, const QString &text) Q_DECL_OVERRIDE; - - QAccessibleInterface *parent() const Q_DECL_OVERRIDE; - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - -private: - QHeaderView *headerView() const; - - QPointer<QAbstractItemView> view; - int index; - Qt::Orientation orientation; - -friend class QAccessibleTable; -friend class QAccessibleTree; -}; - -// This is the corner button on the top left of a table. -// It can be used to select all cells or it is not active at all. -// For now it is ignored. -class QAccessibleTableCornerButton: public QAccessibleInterface -{ -public: - QAccessibleTableCornerButton(QAbstractItemView *view_) - :view(view_) - {} - - QObject *object() const Q_DECL_OVERRIDE { return 0; } - QAccessible::Role role() const Q_DECL_OVERRIDE { return QAccessible::Pane; } - QAccessible::State state() const Q_DECL_OVERRIDE { return QAccessible::State(); } - QRect rect() const Q_DECL_OVERRIDE { return QRect(); } - bool isValid() const Q_DECL_OVERRIDE { return true; } - - QAccessibleInterface *childAt(int, int) const Q_DECL_OVERRIDE { return 0; } - int childCount() const Q_DECL_OVERRIDE { return 0; } - int indexOfChild(const QAccessibleInterface *) const Q_DECL_OVERRIDE { return -1; } - - QString text(QAccessible::Text) const Q_DECL_OVERRIDE { return QString(); } - void setText(QAccessible::Text, const QString &) Q_DECL_OVERRIDE {} - - QAccessibleInterface *parent() const Q_DECL_OVERRIDE { - return QAccessible::queryAccessibleInterface(view); - } - QAccessibleInterface *child(int) const Q_DECL_OVERRIDE { - return 0; - } - -private: - QPointer<QAbstractItemView> view; -}; - - -#endif - -#endif // QT_NO_ACCESSIBILITY - -QT_END_NAMESPACE - -#endif // ACCESSIBLE_ITEMVIEWS_H diff --git a/src/plugins/accessible/widgets/main.cpp b/src/plugins/accessible/widgets/main.cpp deleted file mode 100644 index 717c15edd1..0000000000 --- a/src/plugins/accessible/widgets/main.cpp +++ /dev/null @@ -1,262 +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 "qaccessiblewidgets.h" -#include "qaccessiblemenu.h" -#include "simplewidgets.h" -#include "rangecontrols.h" -#include "complexwidgets.h" -#include "itemviews.h" - -#include <qaccessibleplugin.h> -#include <qplugin.h> -#include <qpushbutton.h> -#include <qtoolbutton.h> -#include <qtreeview.h> -#include <qvariant.h> -#include <qaccessible.h> - -#ifndef QT_NO_ACCESSIBILITY - -QT_BEGIN_NAMESPACE - - -class AccessibleFactory : public QAccessiblePlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QAccessibleFactoryInterface" FILE "widgets.json") - -public: - AccessibleFactory(); - - QAccessibleInterface *create(const QString &classname, QObject *object); -}; - -AccessibleFactory::AccessibleFactory() -{ -} - -QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObject *object) -{ - QAccessibleInterface *iface = 0; - if (!object || !object->isWidgetType()) - return iface; - QWidget *widget = static_cast<QWidget*>(object); - - if (false) { -#ifndef QT_NO_LINEEDIT - } else if (classname == QLatin1String("QLineEdit")) { - iface = new QAccessibleLineEdit(widget); -#endif -#ifndef QT_NO_COMBOBOX - } else if (classname == QLatin1String("QComboBox")) { - iface = new QAccessibleComboBox(widget); -#endif -#ifndef QT_NO_SPINBOX - } else if (classname == QLatin1String("QAbstractSpinBox")) { - iface = new QAccessibleAbstractSpinBox(widget); - } else if (classname == QLatin1String("QSpinBox")) { - iface = new QAccessibleSpinBox(widget); - } else if (classname == QLatin1String("QDoubleSpinBox")) { - iface = new QAccessibleDoubleSpinBox(widget); -#endif -#ifndef QT_NO_SCROLLBAR - } else if (classname == QLatin1String("QScrollBar")) { - iface = new QAccessibleScrollBar(widget); -#endif - } else if (classname == QLatin1String("QAbstractSlider")) { - iface = new QAccessibleAbstractSlider(widget); -#ifndef QT_NO_SLIDER - } else if (classname == QLatin1String("QSlider")) { - iface = new QAccessibleSlider(widget); -#endif -#ifndef QT_NO_TOOLBUTTON - } else if (classname == QLatin1String("QToolButton")) { - QAccessible::Role role = QAccessible::NoRole; -#ifndef QT_NO_MENU - QToolButton *tb = qobject_cast<QToolButton*>(widget); - if (!tb->menu()) - role = tb->isCheckable() ? QAccessible::CheckBox : QAccessible::PushButton; - else if (tb->popupMode() == QToolButton::DelayedPopup) - role = QAccessible::ButtonDropDown; - else -#endif - role = QAccessible::ButtonMenu; - iface = new QAccessibleToolButton(widget, role); -#endif // QT_NO_TOOLBUTTON - } else if (classname == QLatin1String("QCheckBox")) { - iface = new QAccessibleButton(widget, QAccessible::CheckBox); - } else if (classname == QLatin1String("QRadioButton")) { - iface = new QAccessibleButton(widget, QAccessible::RadioButton); - } else if (classname == QLatin1String("QPushButton")) { - QAccessible::Role role = QAccessible::NoRole; - QPushButton *pb = qobject_cast<QPushButton*>(widget); -#ifndef QT_NO_MENU - if (pb->menu()) - role = QAccessible::ButtonMenu; - else -#endif - if (pb->isCheckable()) - role = QAccessible::CheckBox; - else - role = QAccessible::PushButton; - iface = new QAccessibleButton(widget, role); - } else if (classname == QLatin1String("QAbstractButton")) { - iface = new QAccessibleButton(widget, QAccessible::PushButton); - } else if (classname == QLatin1String("QDialog")) { - iface = new QAccessibleWidget(widget, QAccessible::Dialog); - } else if (classname == QLatin1String("QMessageBox")) { - iface = new QAccessibleWidget(widget, QAccessible::AlertMessage); -#ifndef QT_NO_MAINWINDOW - } else if (classname == QLatin1String("QMainWindow")) { - iface = new QAccessibleMainWindow(widget); -#endif - } else if (classname == QLatin1String("QLabel") || classname == QLatin1String("QLCDNumber")) { - iface = new QAccessibleDisplay(widget); -#ifndef QT_NO_GROUPBOX - } else if (classname == QLatin1String("QGroupBox")) { - iface = new QAccessibleGroupBox(widget); -#endif - } else if (classname == QLatin1String("QStatusBar")) { - iface = new QAccessibleDisplay(widget); -#ifndef QT_NO_PROGRESSBAR - } else if (classname == QLatin1String("QProgressBar")) { - iface = new QAccessibleProgressBar(widget); -#endif - } else if (classname == QLatin1String("QToolBar")) { - iface = new QAccessibleWidget(widget, QAccessible::ToolBar, widget->windowTitle()); -#ifndef QT_NO_MENUBAR - } else if (classname == QLatin1String("QMenuBar")) { - iface = new QAccessibleMenuBar(widget); -#endif -#ifndef QT_NO_MENU - } else if (classname == QLatin1String("QMenu")) { - iface = new QAccessibleMenu(widget); -#endif -#ifndef QT_NO_ITEMVIEWS - } else if (classname == QLatin1String("QTreeView")) { - iface = new QAccessibleTree(widget); - } else if (classname == QLatin1String("QTableView") || classname == QLatin1String("QListView")) { - iface = new QAccessibleTable(widget); - // ### This should be cleaned up. We return the parent for the scrollarea to hide it. -#endif // QT_NO_ITEMVIEWS -#ifndef QT_NO_TABBAR - } else if (classname == QLatin1String("QTabBar")) { - iface = new QAccessibleTabBar(widget); -#endif - } else if (classname == QLatin1String("QSizeGrip")) { - iface = new QAccessibleWidget(widget, QAccessible::Grip); -#ifndef QT_NO_SPLITTER - } else if (classname == QLatin1String("QSplitter")) { - iface = new QAccessibleWidget(widget, QAccessible::Splitter); - } else if (classname == QLatin1String("QSplitterHandle")) { - iface = new QAccessibleWidget(widget, QAccessible::Grip); -#endif -#if !defined(QT_NO_TEXTEDIT) && !defined(QT_NO_CURSOR) - } else if (classname == QLatin1String("QTextEdit")) { - iface = new QAccessibleTextEdit(widget); - } else if (classname == QLatin1String("QPlainTextEdit")) { - iface = new QAccessiblePlainTextEdit(widget); -#endif - } else if (classname == QLatin1String("QTipLabel")) { - iface = new QAccessibleDisplay(widget, QAccessible::ToolTip); - } else if (classname == QLatin1String("QFrame")) { - iface = new QAccessibleWidget(widget, QAccessible::Border); -#ifndef QT_NO_STACKEDWIDGET - } else if (classname == QLatin1String("QStackedWidget")) { - iface = new QAccessibleStackedWidget(widget); -#endif -#ifndef QT_NO_TOOLBOX - } else if (classname == QLatin1String("QToolBox")) { - iface = new QAccessibleToolBox(widget); -#endif -#ifndef QT_NO_MDIAREA - } else if (classname == QLatin1String("QMdiArea")) { - iface = new QAccessibleMdiArea(widget); - } else if (classname == QLatin1String("QMdiSubWindow")) { - iface = new QAccessibleMdiSubWindow(widget); -#endif - } else if (classname == QLatin1String("QDialogButtonBox")) { - iface = new QAccessibleDialogButtonBox(widget); -#ifndef QT_NO_DIAL - } else if (classname == QLatin1String("QDial")) { - iface = new QAccessibleDial(widget); -#endif -#ifndef QT_NO_RUBBERBAND - } else if (classname == QLatin1String("QRubberBand")) { - iface = new QAccessibleWidget(widget, QAccessible::Border); -#endif -#if !defined(QT_NO_TEXTBROWSER) && !defined(QT_NO_CURSOR) - } else if (classname == QLatin1String("QTextBrowser")) { - iface = new QAccessibleTextBrowser(widget); -#endif -#ifndef QT_NO_SCROLLAREA - } else if (classname == QLatin1String("QAbstractScrollArea")) { - iface = new QAccessibleAbstractScrollArea(widget); - } else if (classname == QLatin1String("QScrollArea")) { - iface = new QAccessibleScrollArea(widget); -#endif -#ifndef QT_NO_CALENDARWIDGET - } else if (classname == QLatin1String("QCalendarWidget")) { - iface = new QAccessibleCalendarWidget(widget); -#endif -#ifndef QT_NO_DOCKWIDGET - } else if (classname == QLatin1String("QDockWidget")) { - iface = new QAccessibleDockWidget(widget); -#endif - - } else if (classname == QLatin1String("QDesktopScreenWidget")) { - iface = 0; - } else if (classname == QLatin1String("QWidget")) { - iface = new QAccessibleWidget(widget); - } else if (classname == QLatin1String("QWindowContainer")) { - iface = new QAccessibleWindowContainer(widget); - } - - return iface; -} - - -QT_END_NAMESPACE - -#include "main.moc" - -#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/widgets/qaccessiblemenu.cpp b/src/plugins/accessible/widgets/qaccessiblemenu.cpp deleted file mode 100644 index 39ac335131..0000000000 --- a/src/plugins/accessible/widgets/qaccessiblemenu.cpp +++ /dev/null @@ -1,377 +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 "qaccessiblemenu.h" - -#include <qmenu.h> -#include <qmenubar.h> -#include <QtWidgets/QAction> -#include <qstyle.h> - -#ifndef QT_NO_ACCESSIBILITY - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_MENU - -QString Q_GUI_EXPORT qt_accStripAmp(const QString &text); -QString Q_GUI_EXPORT qt_accHotKey(const QString &text); - -QAccessibleInterface *getOrCreateMenu(QWidget *menu, QAction *action) -{ - QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(action); - if (!iface) { - iface = new QAccessibleMenuItem(menu, action); - QAccessible::registerAccessibleInterface(iface); - } - return iface; -} - -QAccessibleMenu::QAccessibleMenu(QWidget *w) -: QAccessibleWidget(w) -{ - Q_ASSERT(menu()); -} - -QMenu *QAccessibleMenu::menu() const -{ - return qobject_cast<QMenu*>(object()); -} - -int QAccessibleMenu::childCount() const -{ - return menu()->actions().count(); -} - -QAccessibleInterface *QAccessibleMenu::childAt(int x, int y) const -{ - QAction *act = menu()->actionAt(menu()->mapFromGlobal(QPoint(x,y))); - if(act && act->isSeparator()) - act = 0; - return act ? getOrCreateMenu(menu(), act) : 0; -} - -QString QAccessibleMenu::text(QAccessible::Text t) const -{ - QString tx = QAccessibleWidget::text(t); - if (!tx.isEmpty()) - return tx; - - if (t == QAccessible::Name) - return menu()->windowTitle(); - return tx; -} - -QAccessible::Role QAccessibleMenu::role() const -{ - return QAccessible::PopupMenu; -} - -QAccessibleInterface *QAccessibleMenu::child(int index) const -{ - if (index < childCount()) - return getOrCreateMenu(menu(), menu()->actions().at(index)); - return 0; -} - -QAccessibleInterface *QAccessibleMenu::parent() const -{ - if (QAction *menuAction = menu()->menuAction()) { - QList<QWidget *> parentCandidates; - parentCandidates << menu()->parentWidget(); - parentCandidates << menuAction->associatedWidgets(); - foreach (QWidget *w, parentCandidates) { - if (qobject_cast<QMenu*>(w) || qobject_cast<QMenuBar*>(w)) { - if (w->actions().indexOf(menuAction) != -1) - return getOrCreateMenu(w, menuAction); - } - } - } - return QAccessibleWidget::parent(); -} - -int QAccessibleMenu::indexOfChild( const QAccessibleInterface *child) const -{ - QAccessible::Role r = child->role(); - if ((r == QAccessible::MenuItem || r == QAccessible::Separator) && menu()) { - return menu()->actions().indexOf(qobject_cast<QAction*>(child->object())); - } - return -1; -} - -#ifndef QT_NO_MENUBAR -QAccessibleMenuBar::QAccessibleMenuBar(QWidget *w) - : QAccessibleWidget(w, QAccessible::MenuBar) -{ - Q_ASSERT(menuBar()); -} - -QMenuBar *QAccessibleMenuBar::menuBar() const -{ - return qobject_cast<QMenuBar*>(object()); -} - -int QAccessibleMenuBar::childCount() const -{ - return menuBar()->actions().count(); -} - -QAccessibleInterface *QAccessibleMenuBar::child(int index) const -{ - if (index < childCount()) { - return getOrCreateMenu(menuBar(), menuBar()->actions().at(index)); - } - return 0; -} - -int QAccessibleMenuBar::indexOfChild(const QAccessibleInterface *child) const -{ - QAccessible::Role r = child->role(); - if ((r == QAccessible::MenuItem || r == QAccessible::Separator) && menuBar()) { - return menuBar()->actions().indexOf(qobject_cast<QAction*>(child->object())); - } - return -1; -} - -#endif // QT_NO_MENUBAR - -QAccessibleMenuItem::QAccessibleMenuItem(QWidget *owner, QAction *action) -: m_action(action), m_owner(owner) -{ -} - -QAccessibleMenuItem::~QAccessibleMenuItem() -{} - -QAccessibleInterface *QAccessibleMenuItem::childAt(int x, int y ) const -{ - for (int i = childCount() - 1; i >= 0; --i) { - QAccessibleInterface *childInterface = child(i); - if (childInterface->rect().contains(x,y)) { - return childInterface; - } - } - return 0; -} - -int QAccessibleMenuItem::childCount() const -{ - return m_action->menu() ? 1 : 0; -} - -int QAccessibleMenuItem::indexOfChild(const QAccessibleInterface * child) const -{ - if (child && child->role() == QAccessible::PopupMenu && child->object() == m_action->menu()) - return 0; - return -1; -} - -bool QAccessibleMenuItem::isValid() const -{ - return m_action && m_owner ? true : false; -} - -QAccessibleInterface *QAccessibleMenuItem::parent() const -{ - return QAccessible::queryAccessibleInterface(owner()); -} - -QAccessibleInterface *QAccessibleMenuItem::child(int index) const -{ - if (index == 0 && action()->menu()) - return QAccessible::queryAccessibleInterface(action()->menu()); - return 0; -} - -void *QAccessibleMenuItem::interface_cast(QAccessible::InterfaceType t) -{ - if (t == QAccessible::ActionInterface) - return static_cast<QAccessibleActionInterface*>(this); - return 0; -} - -QObject *QAccessibleMenuItem::object() const -{ - return m_action; -} - -QRect QAccessibleMenuItem::rect() const -{ - QRect rect; - QWidget *own = owner(); -#ifndef QT_NO_MENUBAR - if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(own)) { - rect = menuBar->actionGeometry(m_action); - QPoint globalPos = menuBar->mapToGlobal(QPoint(0,0)); - rect = rect.translated(globalPos); - } else -#endif // QT_NO_MENUBAR - if (QMenu *menu = qobject_cast<QMenu*>(own)) { - rect = menu->actionGeometry(m_action); - QPoint globalPos = menu->mapToGlobal(QPoint(0,0)); - rect = rect.translated(globalPos); - } - return rect; -} - -QAccessible::Role QAccessibleMenuItem::role() const -{ - return m_action->isSeparator() ? QAccessible::Separator : QAccessible::MenuItem; -} - -void QAccessibleMenuItem::setText(QAccessible::Text /*t*/, const QString & /*text */) -{ -} - -QAccessible::State QAccessibleMenuItem::state() const -{ - QAccessible::State s; - QWidget *own = owner(); - - if (own && (own->testAttribute(Qt::WA_WState_Visible) == false || m_action->isVisible() == false)) { - s.invisible = true; - } - - if (QMenu *menu = qobject_cast<QMenu*>(own)) { - if (menu->activeAction() == m_action) - s.focused = true; -#ifndef QT_NO_MENUBAR - } else if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(own)) { - if (menuBar->activeAction() == m_action) - s.focused = true; -#endif - } - if (own && own->style()->styleHint(QStyle::SH_Menu_MouseTracking)) - s.hotTracked = true; - if (m_action->isSeparator() || !m_action->isEnabled()) - s.disabled = true; - if (m_action->isChecked()) - s.checked = true; - - return s; -} - -QString QAccessibleMenuItem::text(QAccessible::Text t) const -{ - QString str; - switch (t) { - case QAccessible::Name: - str = m_action->text(); - str = qt_accStripAmp(str); - break; - case QAccessible::Accelerator: { -#ifndef QT_NO_SHORTCUT - QKeySequence key = m_action->shortcut(); - if (!key.isEmpty()) { - str = key.toString(); - } else -#endif - { - str = qt_accHotKey(m_action->text()); - } - break; - } - default: - break; - } - return str; -} - -QStringList QAccessibleMenuItem::actionNames() const -{ - QStringList actions; - if (!m_action || m_action->isSeparator()) - return actions; - - if (m_action->menu()) { - actions << showMenuAction(); - } else { - actions << pressAction(); - } - return actions; -} - -void QAccessibleMenuItem::doAction(const QString &actionName) -{ - if (!m_action->isEnabled()) - return; - - if (actionName == pressAction()) { - m_action->trigger(); - } else if (actionName == showMenuAction()) { - if (QMenuBar *bar = qobject_cast<QMenuBar*>(owner())) { - if (m_action->menu() && m_action->menu()->isVisible()) { - m_action->menu()->hide(); - } else { - bar->setActiveAction(m_action); - } - } else if (QMenu *menu = qobject_cast<QMenu*>(owner())){ - if (m_action->menu() && m_action->menu()->isVisible()) { - m_action->menu()->hide(); - } else { - menu->setActiveAction(m_action); - } - } - } -} - -QStringList QAccessibleMenuItem::keyBindingsForAction(const QString &) const -{ - return QStringList(); -} - - -QAction *QAccessibleMenuItem::action() const -{ - return m_action; -} - -QWidget *QAccessibleMenuItem::owner() const -{ - return m_owner; -} - -#endif // QT_NO_MENU - -QT_END_NAMESPACE - -#endif // QT_NO_ACCESSIBILITY - diff --git a/src/plugins/accessible/widgets/qaccessiblemenu.h b/src/plugins/accessible/widgets/qaccessiblemenu.h deleted file mode 100644 index e8c9f8af3a..0000000000 --- a/src/plugins/accessible/widgets/qaccessiblemenu.h +++ /dev/null @@ -1,131 +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 QACCESSIBLEMENU_H -#define QACCESSIBLEMENU_H - -#include <QtWidgets/qaccessiblewidget.h> -#include <QtCore/qpointer.h> - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_ACCESSIBILITY - -#ifndef QT_NO_MENU -class QMenu; -class QMenuBar; -class QAction; - -class QAccessibleMenu : public QAccessibleWidget -{ -public: - explicit QAccessibleMenu(QWidget *w); - - int childCount() const Q_DECL_OVERRIDE; - QAccessibleInterface *childAt(int x, int y) const Q_DECL_OVERRIDE; - - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - QAccessible::Role role() const Q_DECL_OVERRIDE; - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - QAccessibleInterface *parent() const Q_DECL_OVERRIDE; - int indexOfChild( const QAccessibleInterface *child ) const Q_DECL_OVERRIDE; - -protected: - QMenu *menu() const; -}; - -#ifndef QT_NO_MENUBAR -class QAccessibleMenuBar : public QAccessibleWidget -{ -public: - explicit QAccessibleMenuBar(QWidget *w); - - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - int childCount() const Q_DECL_OVERRIDE; - - int indexOfChild(const QAccessibleInterface *child) const Q_DECL_OVERRIDE; - -protected: - QMenuBar *menuBar() const; -}; -#endif // QT_NO_MENUBAR - - -class QAccessibleMenuItem : public QAccessibleInterface, public QAccessibleActionInterface -{ -public: - explicit QAccessibleMenuItem(QWidget *owner, QAction *w); - - ~QAccessibleMenuItem(); - void *interface_cast(QAccessible::InterfaceType t) Q_DECL_OVERRIDE; - - int childCount() const Q_DECL_OVERRIDE; - QAccessibleInterface *childAt(int x, int y) const Q_DECL_OVERRIDE; - bool isValid() const Q_DECL_OVERRIDE; - int indexOfChild(const QAccessibleInterface * child) const Q_DECL_OVERRIDE; - - QAccessibleInterface *parent() const Q_DECL_OVERRIDE; - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - QObject * object() const Q_DECL_OVERRIDE; - QRect rect() const Q_DECL_OVERRIDE; - QAccessible::Role role() const Q_DECL_OVERRIDE; - void setText(QAccessible::Text t, const QString & text) Q_DECL_OVERRIDE; - QAccessible::State state() const Q_DECL_OVERRIDE; - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - - // QAccessibleActionInterface - QStringList actionNames() const Q_DECL_OVERRIDE; - void doAction(const QString &actionName) Q_DECL_OVERRIDE; - QStringList keyBindingsForAction(const QString &actionName) const Q_DECL_OVERRIDE; - - QWidget *owner() const; -protected: - QAction *action() const; -private: - QAction *m_action; - QPointer<QWidget> m_owner; // can hold either QMenu or the QMenuBar that contains the action -}; - -#endif // QT_NO_MENU - -QT_END_NAMESPACE -#endif // QT_NO_ACCESSIBILITY -#endif // QACCESSIBLEMENU_H diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp deleted file mode 100644 index b502682938..0000000000 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp +++ /dev/null @@ -1,1024 +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 "qaccessiblewidgets.h" -#include "qabstracttextdocumentlayout.h" -#include "qapplication.h" -#include "qclipboard.h" -#include "qtextedit.h" -#include "private/qtextedit_p.h" -#include "qtextdocument.h" -#include "qtextobject.h" -#include "qplaintextedit.h" -#include "qtextboundaryfinder.h" -#include "qscrollbar.h" -#include "qdebug.h" -#include <QApplication> -#include <QStackedWidget> -#include <QToolBox> -#include <QMdiArea> -#include <QMdiSubWindow> -#include <QDialogButtonBox> -#include <limits.h> -#include <QRubberBand> -#include <QTextBrowser> -#include <QCalendarWidget> -#include <QAbstractItemView> -#include <QDockWidget> -#include <QMainWindow> -#include <QAbstractButton> -#include <private/qdockwidget_p.h> -#include <QFocusFrame> - -#ifndef QT_NO_ACCESSIBILITY - -QT_BEGIN_NAMESPACE - -QString Q_GUI_EXPORT qt_accStripAmp(const QString &text); -QString Q_GUI_EXPORT qt_accHotKey(const QString &text); - -QList<QWidget*> childWidgets(const QWidget *widget, bool includeTopLevel) -{ - if (widget == 0) - return QList<QWidget*>(); - QList<QObject*> list = widget->children(); - QList<QWidget*> widgets; - for (int i = 0; i < list.size(); ++i) { - QWidget *w = qobject_cast<QWidget *>(list.at(i)); - if (!w) - continue; - QString objectName = w->objectName(); - if ((includeTopLevel || !w->isWindow()) - && !qobject_cast<QFocusFrame*>(w) - && !qobject_cast<QMenu*>(w) - && objectName != QLatin1String("qt_rubberband") - && objectName != QLatin1String("qt_qmainwindow_extended_splitter")) { - widgets.append(w); - } - } - return widgets; -} - -#if !defined(QT_NO_TEXTEDIT) && !defined(QT_NO_CURSOR) - -QAccessiblePlainTextEdit::QAccessiblePlainTextEdit(QWidget* o) - :QAccessibleTextWidget(o) -{ - Q_ASSERT(widget()->inherits("QPlainTextEdit")); -} - -QPlainTextEdit* QAccessiblePlainTextEdit::plainTextEdit() const -{ - return static_cast<QPlainTextEdit *>(widget()); -} - -QString QAccessiblePlainTextEdit::text(QAccessible::Text t) const -{ - if (t == QAccessible::Value) - return plainTextEdit()->toPlainText(); - - return QAccessibleWidget::text(t); -} - -void QAccessiblePlainTextEdit::setText(QAccessible::Text t, const QString &text) -{ - if (t != QAccessible::Value) { - QAccessibleWidget::setText(t, text); - return; - } - if (plainTextEdit()->isReadOnly()) - return; - - plainTextEdit()->setPlainText(text); -} - -QAccessible::State QAccessiblePlainTextEdit::state() const -{ - QAccessible::State st = QAccessibleTextWidget::state(); - if (plainTextEdit()->isReadOnly()) - st.readOnly = true; - else - st.editable = true; - return st; -} - -void *QAccessiblePlainTextEdit::interface_cast(QAccessible::InterfaceType t) -{ - if (t == QAccessible::TextInterface) - return static_cast<QAccessibleTextInterface*>(this); - else if (t == QAccessible::EditableTextInterface) - return static_cast<QAccessibleEditableTextInterface*>(this); - return QAccessibleWidget::interface_cast(t); -} - -QPoint QAccessiblePlainTextEdit::scrollBarPosition() const -{ - QPoint result; - result.setX(plainTextEdit()->horizontalScrollBar() ? plainTextEdit()->horizontalScrollBar()->sliderPosition() : 0); - result.setY(plainTextEdit()->verticalScrollBar() ? plainTextEdit()->verticalScrollBar()->sliderPosition() : 0); - return result; -} - -QTextCursor QAccessiblePlainTextEdit::textCursor() const -{ - return plainTextEdit()->textCursor(); -} - -void QAccessiblePlainTextEdit::setTextCursor(const QTextCursor &textCursor) -{ - plainTextEdit()->setTextCursor(textCursor); -} - -QTextDocument* QAccessiblePlainTextEdit::textDocument() const -{ - return plainTextEdit()->document(); -} - -QWidget* QAccessiblePlainTextEdit::viewport() const -{ - return plainTextEdit()->viewport(); -} - -void QAccessiblePlainTextEdit::scrollToSubstring(int startIndex, int endIndex) -{ - //TODO: Not implemented - Q_UNUSED(startIndex); - Q_UNUSED(endIndex); -} - - -/*! - \class QAccessibleTextEdit - \brief The QAccessibleTextEdit class implements the QAccessibleInterface for richtext editors. - \internal -*/ - -/*! - \fn QAccessibleTextEdit::QAccessibleTextEdit(QWidget *widget) - - Constructs a QAccessibleTextEdit object for a \a widget. -*/ -QAccessibleTextEdit::QAccessibleTextEdit(QWidget *o) -: QAccessibleTextWidget(o, QAccessible::EditableText) -{ - Q_ASSERT(widget()->inherits("QTextEdit")); -} - -/*! Returns the text edit. */ -QTextEdit *QAccessibleTextEdit::textEdit() const -{ - return static_cast<QTextEdit *>(widget()); -} - -QTextCursor QAccessibleTextEdit::textCursor() const -{ - return textEdit()->textCursor(); -} - -QTextDocument *QAccessibleTextEdit::textDocument() const -{ - return textEdit()->document(); -} - -void QAccessibleTextEdit::setTextCursor(const QTextCursor &textCursor) -{ - textEdit()->setTextCursor(textCursor); -} - -QWidget *QAccessibleTextEdit::viewport() const -{ - return textEdit()->viewport(); -} - -QPoint QAccessibleTextEdit::scrollBarPosition() const -{ - QPoint result; - result.setX(textEdit()->horizontalScrollBar() ? textEdit()->horizontalScrollBar()->sliderPosition() : 0); - result.setY(textEdit()->verticalScrollBar() ? textEdit()->verticalScrollBar()->sliderPosition() : 0); - return result; -} - -QString QAccessibleTextEdit::text(QAccessible::Text t) const -{ - if (t == QAccessible::Value) - return textEdit()->toPlainText(); - - return QAccessibleWidget::text(t); -} - -void QAccessibleTextEdit::setText(QAccessible::Text t, const QString &text) -{ - if (t != QAccessible::Value) { - QAccessibleWidget::setText(t, text); - return; - } - if (textEdit()->isReadOnly()) - return; - - textEdit()->setText(text); -} - -QAccessible::State QAccessibleTextEdit::state() const -{ - QAccessible::State st = QAccessibleTextWidget::state(); - if (textEdit()->isReadOnly()) - st.readOnly = true; - else - st.editable = true; - return st; -} - -void *QAccessibleTextEdit::interface_cast(QAccessible::InterfaceType t) -{ - if (t == QAccessible::TextInterface) - return static_cast<QAccessibleTextInterface*>(this); - else if (t == QAccessible::EditableTextInterface) - return static_cast<QAccessibleEditableTextInterface*>(this); - return QAccessibleWidget::interface_cast(t); -} - -void QAccessibleTextEdit::scrollToSubstring(int startIndex, int endIndex) -{ - QTextEdit *edit = textEdit(); - - QTextCursor cursor = textCursor(); - cursor.setPosition(startIndex); - QRect r = edit->cursorRect(cursor); - - cursor.setPosition(endIndex); - r.setBottomRight(edit->cursorRect(cursor).bottomRight()); - - r.moveTo(r.x() + edit->horizontalScrollBar()->value(), - r.y() + edit->verticalScrollBar()->value()); - - // E V I L, but ensureVisible is not public - if (!QMetaObject::invokeMethod(edit, "_q_ensureVisible", Q_ARG(QRectF, r))) - qWarning("AccessibleTextEdit::scrollToSubstring failed!"); -} - -#endif // QT_NO_TEXTEDIT && QT_NO_CURSOR - -#ifndef QT_NO_STACKEDWIDGET -// ======================= QAccessibleStackedWidget ====================== -QAccessibleStackedWidget::QAccessibleStackedWidget(QWidget *widget) - : QAccessibleWidget(widget, QAccessible::LayeredPane) -{ - Q_ASSERT(qobject_cast<QStackedWidget *>(widget)); -} - -QAccessibleInterface *QAccessibleStackedWidget::childAt(int x, int y) const -{ - if (!stackedWidget()->isVisible()) - return 0; - QWidget *currentWidget = stackedWidget()->currentWidget(); - if (!currentWidget) - return 0; - QPoint position = currentWidget->mapFromGlobal(QPoint(x, y)); - if (currentWidget->rect().contains(position)) - return child(stackedWidget()->currentIndex()); - return 0; -} - -int QAccessibleStackedWidget::childCount() const -{ - return stackedWidget()->count(); -} - -int QAccessibleStackedWidget::indexOfChild(const QAccessibleInterface *child) const -{ - if (!child) - return -1; - - QWidget *widget = qobject_cast<QWidget*>(child->object()); - return stackedWidget()->indexOf(widget); -} - -QAccessibleInterface *QAccessibleStackedWidget::child(int index) const -{ - if (index < 0 || index >= stackedWidget()->count()) - return 0; - return QAccessible::queryAccessibleInterface(stackedWidget()->widget(index)); -} - -QStackedWidget *QAccessibleStackedWidget::stackedWidget() const -{ - return static_cast<QStackedWidget *>(object()); -} -#endif // QT_NO_STACKEDWIDGET - -#ifndef QT_NO_TOOLBOX -// ======================= QAccessibleToolBox ====================== -QAccessibleToolBox::QAccessibleToolBox(QWidget *widget) - : QAccessibleWidget(widget, QAccessible::LayeredPane) -{ - Q_ASSERT(qobject_cast<QToolBox *>(widget)); -} - -QToolBox * QAccessibleToolBox::toolBox() const -{ - return static_cast<QToolBox *>(object()); -} -#endif // QT_NO_TOOLBOX - -// ======================= QAccessibleMdiArea ====================== -#ifndef QT_NO_MDIAREA -QAccessibleMdiArea::QAccessibleMdiArea(QWidget *widget) - : QAccessibleWidget(widget, QAccessible::LayeredPane) -{ - Q_ASSERT(qobject_cast<QMdiArea *>(widget)); -} - -int QAccessibleMdiArea::childCount() const -{ - return mdiArea()->subWindowList().count(); -} - -QAccessibleInterface *QAccessibleMdiArea::child(int index) const -{ - QList<QMdiSubWindow *> subWindows = mdiArea()->subWindowList(); - QWidget *targetObject = subWindows.value(index); - if (!targetObject) - return 0; - return QAccessible::queryAccessibleInterface(targetObject); -} - - -int QAccessibleMdiArea::indexOfChild(const QAccessibleInterface *child) const -{ - if (!child || !child->object() || mdiArea()->subWindowList().isEmpty()) - return -1; - if (QMdiSubWindow *window = qobject_cast<QMdiSubWindow *>(child->object())) { - return mdiArea()->subWindowList().indexOf(window); - } - return -1; -} - -QMdiArea *QAccessibleMdiArea::mdiArea() const -{ - return static_cast<QMdiArea *>(object()); -} - -// ======================= QAccessibleMdiSubWindow ====================== -QAccessibleMdiSubWindow::QAccessibleMdiSubWindow(QWidget *widget) - : QAccessibleWidget(widget, QAccessible::Window) -{ - Q_ASSERT(qobject_cast<QMdiSubWindow *>(widget)); -} - -QString QAccessibleMdiSubWindow::text(QAccessible::Text textType) const -{ - if (textType == QAccessible::Name) { - QString title = mdiSubWindow()->windowTitle(); - title.replace(QLatin1String("[*]"), QLatin1String("")); - return title; - } - return QAccessibleWidget::text(textType); -} - -void QAccessibleMdiSubWindow::setText(QAccessible::Text textType, const QString &text) -{ - if (textType == QAccessible::Name) - mdiSubWindow()->setWindowTitle(text); - else - QAccessibleWidget::setText(textType, text); -} - -QAccessible::State QAccessibleMdiSubWindow::state() const -{ - QAccessible::State state; - state.focusable = true; - if (!mdiSubWindow()->isMaximized()) { - state.movable = true; - state.sizeable = true; - } - if (mdiSubWindow()->isAncestorOf(QApplication::focusWidget()) - || QApplication::focusWidget() == mdiSubWindow()) - state.focused = true; - if (!mdiSubWindow()->isVisible()) - state.invisible = true; - if (const QWidget *parent = mdiSubWindow()->parentWidget()) - if (!parent->contentsRect().contains(mdiSubWindow()->geometry())) - state.offscreen = true; - if (!mdiSubWindow()->isEnabled()) - state.disabled = true; - return state; -} - -int QAccessibleMdiSubWindow::childCount() const -{ - if (mdiSubWindow()->widget()) - return 1; - return 0; -} - -QAccessibleInterface *QAccessibleMdiSubWindow::child(int index) const -{ - QMdiSubWindow *source = mdiSubWindow(); - if (index != 0 || !source->widget()) - return 0; - - return QAccessible::queryAccessibleInterface(source->widget()); -} - -int QAccessibleMdiSubWindow::indexOfChild(const QAccessibleInterface *child) const -{ - if (child && child->object() && child->object() == mdiSubWindow()->widget()) - return 0; - return -1; -} - -QRect QAccessibleMdiSubWindow::rect() const -{ - if (mdiSubWindow()->isHidden()) - return QRect(); - if (!mdiSubWindow()->parent()) - return QAccessibleWidget::rect(); - const QPoint pos = mdiSubWindow()->mapToGlobal(QPoint(0, 0)); - return QRect(pos, mdiSubWindow()->size()); -} - -QMdiSubWindow *QAccessibleMdiSubWindow::mdiSubWindow() const -{ - return static_cast<QMdiSubWindow *>(object()); -} -#endif // QT_NO_MDIAREA - -#ifndef QT_NO_DIALOGBUTTONBOX -// ======================= QAccessibleDialogButtonBox ====================== -QAccessibleDialogButtonBox::QAccessibleDialogButtonBox(QWidget *widget) - : QAccessibleWidget(widget, QAccessible::Grouping) -{ - Q_ASSERT(qobject_cast<QDialogButtonBox*>(widget)); -} - -#endif // QT_NO_DIALOGBUTTONBOX - -#if !defined(QT_NO_TEXTBROWSER) && !defined(QT_NO_CURSOR) -QAccessibleTextBrowser::QAccessibleTextBrowser(QWidget *widget) - : QAccessibleTextEdit(widget) -{ - Q_ASSERT(qobject_cast<QTextBrowser *>(widget)); -} - -QAccessible::Role QAccessibleTextBrowser::role() const -{ - return QAccessible::StaticText; -} -#endif // QT_NO_TEXTBROWSER && QT_NO_CURSOR - -#ifndef QT_NO_CALENDARWIDGET -// ===================== QAccessibleCalendarWidget ======================== -QAccessibleCalendarWidget::QAccessibleCalendarWidget(QWidget *widget) - : QAccessibleWidget(widget, QAccessible::Table) -{ - Q_ASSERT(qobject_cast<QCalendarWidget *>(widget)); -} - -int QAccessibleCalendarWidget::childCount() const -{ - return calendarWidget()->isNavigationBarVisible() ? 2 : 1; -} - -int QAccessibleCalendarWidget::indexOfChild(const QAccessibleInterface *child) const -{ - if (!child || !child->object() || childCount() <= 0) - return -1; - if (qobject_cast<QAbstractItemView *>(child->object())) - return childCount() - 1; // FIXME - return 0; -} - -QAccessibleInterface *QAccessibleCalendarWidget::child(int index) const -{ - if (index < 0 || index >= childCount()) - return 0; - - if (childCount() > 1 && index == 0) - return QAccessible::queryAccessibleInterface(navigationBar()); - - return QAccessible::queryAccessibleInterface(calendarView()); -} - -QCalendarWidget *QAccessibleCalendarWidget::calendarWidget() const -{ - return static_cast<QCalendarWidget *>(object()); -} - -QAbstractItemView *QAccessibleCalendarWidget::calendarView() const -{ - foreach (QObject *child, calendarWidget()->children()) { - if (child->objectName() == QLatin1String("qt_calendar_calendarview")) - return static_cast<QAbstractItemView *>(child); - } - return 0; -} - -QWidget *QAccessibleCalendarWidget::navigationBar() const -{ - foreach (QObject *child, calendarWidget()->children()) { - if (child->objectName() == QLatin1String("qt_calendar_navigationbar")) - return static_cast<QWidget *>(child); - } - return 0; -} -#endif // QT_NO_CALENDARWIDGET - -#ifndef QT_NO_DOCKWIDGET - -// Dock Widget - order of children: -// - Content widget -// - Float button -// - Close button -// If there is a custom title bar widget, that one becomes child 1, after the content 0 -// (in that case the buttons are ignored) -QAccessibleDockWidget::QAccessibleDockWidget(QWidget *widget) - : QAccessibleWidget(widget, QAccessible::Window) -{ -} - -QDockWidgetLayout *QAccessibleDockWidget::dockWidgetLayout() const -{ - return qobject_cast<QDockWidgetLayout*>(dockWidget()->layout()); -} - -int QAccessibleDockWidget::childCount() const -{ - if (dockWidget()->titleBarWidget()) { - return dockWidget()->widget() ? 2 : 1; - } - return dockWidgetLayout()->count(); -} - -QAccessibleInterface *QAccessibleDockWidget::child(int index) const -{ - if (dockWidget()->titleBarWidget()) { - if ((!dockWidget()->widget() && index == 0) || (index == 1)) - return QAccessible::queryAccessibleInterface(dockWidget()->titleBarWidget()); - if (index == 0) - return QAccessible::queryAccessibleInterface(dockWidget()->widget()); - } else { - QLayoutItem *item = dockWidgetLayout()->itemAt(index); - if (item) - return QAccessible::queryAccessibleInterface(item->widget()); - } - return 0; -} - -int QAccessibleDockWidget::indexOfChild(const QAccessibleInterface *child) const -{ - if (!child || !child->object() || child->object()->parent() != object()) - return -1; - - if (dockWidget()->titleBarWidget() == child->object()) { - return dockWidget()->widget() ? 1 : 0; - } - - return dockWidgetLayout()->indexOf(qobject_cast<QWidget*>(child->object())); -} - -QRect QAccessibleDockWidget::rect() const -{ - QRect rect; - - if (dockWidget()->isFloating()) { - rect = dockWidget()->frameGeometry(); - } else { - rect = dockWidget()->rect(); - rect.moveTopLeft(dockWidget()->mapToGlobal(rect.topLeft())); - } - - return rect; -} - -QDockWidget *QAccessibleDockWidget::dockWidget() const -{ - return static_cast<QDockWidget *>(object()); -} - -QString QAccessibleDockWidget::text(QAccessible::Text t) const -{ - if (t == QAccessible::Name) { - return qt_accStripAmp(dockWidget()->windowTitle()); - } - return QString(); -} -#endif // QT_NO_DOCKWIDGET - -#ifndef QT_NO_CURSOR - -QAccessibleTextWidget::QAccessibleTextWidget(QWidget *o, QAccessible::Role r, const QString &name): - QAccessibleWidget(o, r, name) -{ - -} - -QAccessible::State QAccessibleTextWidget::state() const -{ - QAccessible::State s = QAccessibleWidget::state(); - s.multiLine = true; - return s; -} - -QRect QAccessibleTextWidget::characterRect(int offset) const -{ - QTextBlock block = textDocument()->findBlock(offset); - if (!block.isValid()) - return QRect(); - - QTextLayout *layout = block.layout(); - QPointF layoutPosition = layout->position(); - int relativeOffset = offset - block.position(); - QTextLine line = layout->lineForTextPosition(relativeOffset); - - QRect r; - - if (line.isValid()) { - qreal x = line.cursorToX(relativeOffset); - QFontMetrics fm(textCursor().charFormat().font()); - const QString ch = text(offset, offset + 1); - if (!ch.isEmpty()) { - int w = fm.width(ch); - int h = fm.height(); - r = QRect(layoutPosition.x() + x, layoutPosition.y() + line.y(), - w, h); - r.moveTo(viewport()->mapToGlobal(r.topLeft())); - } - r.translate(-scrollBarPosition()); - } - - return r; -} - -int QAccessibleTextWidget::offsetAtPoint(const QPoint &point) const -{ - QPoint p = viewport()->mapFromGlobal(point); - // convert to document coordinates - p += scrollBarPosition(); - return textDocument()->documentLayout()->hitTest(p, Qt::ExactHit); -} - -int QAccessibleTextWidget::selectionCount() const -{ - return textCursor().hasSelection() ? 1 : 0; -} - -QString QAccessibleTextWidget::attributes(int offset, int *startOffset, int *endOffset) const -{ - /* The list of attributes can be found at: - http://linuxfoundation.org/collaborate/workgroups/accessibility/iaccessible2/textattributes - */ - - if (offset >= characterCount()) { - *startOffset = -1; - *endOffset = -1; - return QString(); - } - - QMap<QString, QString> attrs; - - QTextCursor cursor = textCursor(); - - //cursor.charFormat returns the format of the previous character - cursor.setPosition(offset + 1); - QTextCharFormat charFormat = cursor.charFormat(); - - cursor.setPosition(offset); - QTextBlockFormat blockFormat = cursor.blockFormat(); - - QTextCharFormat charFormatComp; - QTextBlockFormat blockFormatComp; - - *startOffset = offset; - cursor.setPosition(*startOffset); - while (*startOffset > 0) { - charFormatComp = cursor.charFormat(); - cursor.setPosition(*startOffset - 1); - blockFormatComp = cursor.blockFormat(); - if ((charFormat == charFormatComp) && (blockFormat == blockFormatComp)) - (*startOffset)--; - else - break; - } - - int limit = characterCount() + 1; - *endOffset = offset + 1; - cursor.setPosition(*endOffset); - while (*endOffset < limit) { - blockFormatComp = cursor.blockFormat(); - cursor.setPosition(*endOffset + 1); - charFormatComp = cursor.charFormat(); - if ((charFormat == charFormatComp) && (cursor.blockFormat() == blockFormatComp)) - (*endOffset)++; - else - break; - } - - QString family = charFormat.fontFamily(); - if (!family.isEmpty()) { - family = family.replace('\\',"\\\\"); - family = family.replace(':',"\\:"); - family = family.replace(',',"\\,"); - family = family.replace('=',"\\="); - family = family.replace(';',"\\;"); - family = family.replace('\"',"\\\""); - attrs["font-family"] = '"'+family+'"'; - } - - int fontSize = int(charFormat.fontPointSize()); - if (fontSize) - attrs["font-size"] = QString::number(fontSize).append("pt"); - - //Different weight values are not handled - attrs["font-weight"] = (charFormat.fontWeight() > QFont::Normal) ? "bold" : "normal"; - - QFont::Style style = charFormat.font().style(); - attrs["font-style"] = (style == QFont::StyleItalic) ? "italic" : ((style == QFont::StyleOblique) ? "oblique": "normal"); - - attrs["text-underline-style"] = charFormat.font().underline() ? "solid" : "none"; - - QTextCharFormat::VerticalAlignment alignment = charFormat.verticalAlignment(); - attrs["text-position"] = (alignment == QTextCharFormat::AlignSubScript) ? "sub" : ((alignment == QTextCharFormat::AlignSuperScript) ? "super" : "baseline" ); - - QBrush background = charFormat.background(); - if (background.style() == Qt::SolidPattern) { - attrs["background-color"] = QString("rgb(%1,%2,%3)").arg(background.color().red()).arg(background.color().green()).arg(background.color().blue()); - } - - QBrush foreground = charFormat.foreground(); - if (foreground.style() == Qt::SolidPattern) { - attrs["color"] = QString("rgb(%1,%2,%3)").arg(foreground.color().red()).arg(foreground.color().green()).arg(foreground.color().blue()); - } - - switch (blockFormat.alignment() & (Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter | Qt::AlignJustify)) { - case Qt::AlignLeft: - attrs["text-align"] = "left"; - break; - case Qt::AlignRight: - attrs["text-align"] = "right"; - break; - case Qt::AlignHCenter: - attrs["text-align"] = "center"; - break; - case Qt::AlignJustify: - attrs["text-align"] = "left"; - break; - } - - QString result; - foreach (const QString &attributeName, attrs.keys()) { - result.append(attributeName).append(':').append(attrs[attributeName]).append(';'); - } - - return result; -} - -int QAccessibleTextWidget::cursorPosition() const -{ - return textCursor().position(); -} - -void QAccessibleTextWidget::selection(int selectionIndex, int *startOffset, int *endOffset) const -{ - *startOffset = *endOffset = 0; - QTextCursor cursor = textCursor(); - - if (selectionIndex != 0 || !cursor.hasSelection()) - return; - - *startOffset = cursor.selectionStart(); - *endOffset = cursor.selectionEnd(); -} - -QString QAccessibleTextWidget::text(int startOffset, int endOffset) const -{ - QTextCursor cursor(textCursor()); - - cursor.setPosition(startOffset, QTextCursor::MoveAnchor); - cursor.setPosition(endOffset, QTextCursor::KeepAnchor); - - return cursor.selectedText().replace(QChar(QChar::ParagraphSeparator), QLatin1Char('\n')); -} - -QPoint QAccessibleTextWidget::scrollBarPosition() const -{ - return QPoint(0, 0); -} - - -QString QAccessibleTextWidget::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int *startOffset, int *endOffset) const -{ - Q_ASSERT(startOffset); - Q_ASSERT(endOffset); - - QTextCursor cursor = textCursor(); - cursor.setPosition(offset); - QPair<int, int> boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType); - cursor.setPosition(boundaries.first - 1); - boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType); - - *startOffset = boundaries.first; - *endOffset = boundaries.second; - - return text(boundaries.first, boundaries.second); - } - - -QString QAccessibleTextWidget::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int *startOffset, int *endOffset) const -{ - Q_ASSERT(startOffset); - Q_ASSERT(endOffset); - - QTextCursor cursor = textCursor(); - cursor.setPosition(offset); - QPair<int, int> boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType); - cursor.setPosition(boundaries.second); - boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType); - - *startOffset = boundaries.first; - *endOffset = boundaries.second; - - return text(boundaries.first, boundaries.second); -} - -QString QAccessibleTextWidget::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int *startOffset, int *endOffset) const -{ - Q_ASSERT(startOffset); - Q_ASSERT(endOffset); - - QTextCursor cursor = textCursor(); - cursor.setPosition(offset); - QPair<int, int> boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType); - - *startOffset = boundaries.first; - *endOffset = boundaries.second; - - return text(boundaries.first, boundaries.second); -} - -void QAccessibleTextWidget::setCursorPosition(int position) -{ - QTextCursor cursor = textCursor(); - cursor.setPosition(position); - setTextCursor(cursor); -} - -void QAccessibleTextWidget::addSelection(int startOffset, int endOffset) -{ - setSelection(0, startOffset, endOffset); -} - -void QAccessibleTextWidget::removeSelection(int selectionIndex) -{ - if (selectionIndex != 0) - return; - - QTextCursor cursor = textCursor(); - cursor.clearSelection(); - setTextCursor(cursor); -} - -void QAccessibleTextWidget::setSelection(int selectionIndex, int startOffset, int endOffset) -{ - if (selectionIndex != 0) - return; - - QTextCursor cursor = textCursor(); - cursor.setPosition(startOffset, QTextCursor::MoveAnchor); - cursor.setPosition(endOffset, QTextCursor::KeepAnchor); - setTextCursor(cursor); -} - -int QAccessibleTextWidget::characterCount() const -{ - QTextCursor cursor = textCursor(); - cursor.movePosition(QTextCursor::End); - return cursor.position(); -} - -QTextCursor QAccessibleTextWidget::textCursorForRange(int startOffset, int endOffset) const -{ - QTextCursor cursor = textCursor(); - cursor.setPosition(startOffset, QTextCursor::MoveAnchor); - cursor.setPosition(endOffset, QTextCursor::KeepAnchor); - - return cursor; -} - -void QAccessibleTextWidget::deleteText(int startOffset, int endOffset) -{ - QTextCursor cursor = textCursorForRange(startOffset, endOffset); - cursor.removeSelectedText(); -} - -void QAccessibleTextWidget::insertText(int offset, const QString &text) -{ - QTextCursor cursor = textCursor(); - cursor.setPosition(offset); - cursor.insertText(text); -} - -void QAccessibleTextWidget::replaceText(int startOffset, int endOffset, const QString &text) -{ - QTextCursor cursor = textCursorForRange(startOffset, endOffset); - cursor.removeSelectedText(); - cursor.insertText(text); -} -#endif // QT_NO_CURSOR - - -#ifndef QT_NO_MAINWINDOW -QAccessibleMainWindow::QAccessibleMainWindow(QWidget *widget) - : QAccessibleWidget(widget, QAccessible::Window) { } - -QAccessibleInterface *QAccessibleMainWindow::child(int index) const -{ - QList<QWidget*> kids = childWidgets(mainWindow(), true); - if (index >= 0 && index < kids.count()) { - return QAccessible::queryAccessibleInterface(kids.at(index)); - } - return 0; -} - -int QAccessibleMainWindow::childCount() const -{ - QList<QWidget*> kids = childWidgets(mainWindow(), true); - return kids.count(); -} - -int QAccessibleMainWindow::indexOfChild(const QAccessibleInterface *iface) const -{ - QList<QWidget*> kids = childWidgets(mainWindow(), true); - return kids.indexOf(static_cast<QWidget*>(iface->object())); -} - -QAccessibleInterface *QAccessibleMainWindow::childAt(int x, int y) const -{ - QWidget *w = widget(); - if (!w->isVisible()) - return 0; - QPoint gp = w->mapToGlobal(QPoint(0, 0)); - if (!QRect(gp.x(), gp.y(), w->width(), w->height()).contains(x, y)) - return 0; - - QWidgetList kids = childWidgets(mainWindow(), true); - QPoint rp = mainWindow()->mapFromGlobal(QPoint(x, y)); - for (int i = 0; i < kids.size(); ++i) { - QWidget *child = kids.at(i); - if (!child->isWindow() && !child->isHidden() && child->geometry().contains(rp)) { - return QAccessible::queryAccessibleInterface(child); - } - } - return 0; -} - -QMainWindow *QAccessibleMainWindow::mainWindow() const -{ - return qobject_cast<QMainWindow *>(object()); -} - -#endif //QT_NO_MAINWINDOW - -QT_END_NAMESPACE - -#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.h b/src/plugins/accessible/widgets/qaccessiblewidgets.h deleted file mode 100644 index 3f50010685..0000000000 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.h +++ /dev/null @@ -1,314 +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 QACCESSIBLEWIDGETS_H -#define QACCESSIBLEWIDGETS_H - -#include <QtWidgets/qaccessiblewidget.h> - -#ifndef QT_NO_ACCESSIBILITY - -#include <QtCore/QPointer> -#include <QtCore/QPair> - -QT_BEGIN_NAMESPACE - -class QTextEdit; -class QStackedWidget; -class QToolBox; -class QMdiArea; -class QMdiSubWindow; -class QRubberBand; -class QTextBrowser; -class QCalendarWidget; -class QAbstractItemView; -class QDockWidget; -class QDockWidgetLayout; -class QMainWindow; -class QPlainTextEdit; -class QTextCursor; -class QTextDocument; - -#ifndef QT_NO_CURSOR -class QAccessibleTextWidget : public QAccessibleWidget, - public QAccessibleTextInterface, - public QAccessibleEditableTextInterface -{ -public: - QAccessibleTextWidget(QWidget *o, QAccessible::Role r = QAccessible::EditableText, const QString &name = QString()); - - QAccessible::State state() const; - - // QAccessibleTextInterface - // selection - void selection(int selectionIndex, int *startOffset, int *endOffset) const Q_DECL_OVERRIDE; - int selectionCount() const Q_DECL_OVERRIDE; - void addSelection(int startOffset, int endOffset) Q_DECL_OVERRIDE; - void removeSelection(int selectionIndex) Q_DECL_OVERRIDE; - void setSelection(int selectionIndex, int startOffset, int endOffset) Q_DECL_OVERRIDE; - - // cursor - int cursorPosition() const Q_DECL_OVERRIDE; - void setCursorPosition(int position) Q_DECL_OVERRIDE; - - // text - QString text(int startOffset, int endOffset) const Q_DECL_OVERRIDE; - QString textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int *startOffset, int *endOffset) const Q_DECL_OVERRIDE; - QString textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int *startOffset, int *endOffset) const Q_DECL_OVERRIDE; - QString textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int *startOffset, int *endOffset) const Q_DECL_OVERRIDE; - int characterCount() const; - - // character <-> geometry - QRect characterRect(int offset) const Q_DECL_OVERRIDE; - int offsetAtPoint(const QPoint &point) const Q_DECL_OVERRIDE; - - QString attributes(int offset, int *startOffset, int *endOffset) const Q_DECL_OVERRIDE; - - // QAccessibleEditableTextInterface - void deleteText(int startOffset, int endOffset) Q_DECL_OVERRIDE; - void insertText(int offset, const QString &text) Q_DECL_OVERRIDE; - void replaceText(int startOffset, int endOffset, const QString &text) Q_DECL_OVERRIDE; - - using QAccessibleWidget::text; - -protected: - QTextCursor textCursorForRange(int startOffset, int endOffset) const; - virtual QPoint scrollBarPosition() const; - // return the current text cursor at the caret position including a potential selection - virtual QTextCursor textCursor() const = 0; - virtual void setTextCursor(const QTextCursor &) = 0; - virtual QTextDocument *textDocument() const = 0; - virtual QWidget *viewport() const = 0; -}; - -#ifndef QT_NO_TEXTEDIT -class QAccessiblePlainTextEdit : public QAccessibleTextWidget -{ -public: - explicit QAccessiblePlainTextEdit(QWidget *o); - - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - void setText(QAccessible::Text t, const QString &text) Q_DECL_OVERRIDE; - QAccessible::State state() const Q_DECL_OVERRIDE; - - void *interface_cast(QAccessible::InterfaceType t) Q_DECL_OVERRIDE; - - // QAccessibleTextInterface - void scrollToSubstring(int startIndex, int endIndex) Q_DECL_OVERRIDE; - - using QAccessibleTextWidget::text; - -protected: - QPlainTextEdit *plainTextEdit() const; - - QPoint scrollBarPosition() const Q_DECL_OVERRIDE; - QTextCursor textCursor() const Q_DECL_OVERRIDE; - void setTextCursor(const QTextCursor &textCursor) Q_DECL_OVERRIDE; - QTextDocument *textDocument() const Q_DECL_OVERRIDE; - QWidget *viewport() const Q_DECL_OVERRIDE; -}; - -class QAccessibleTextEdit : public QAccessibleTextWidget -{ -public: - explicit QAccessibleTextEdit(QWidget *o); - - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - void setText(QAccessible::Text t, const QString &text) Q_DECL_OVERRIDE; - QAccessible::State state() const Q_DECL_OVERRIDE; - - void *interface_cast(QAccessible::InterfaceType t) Q_DECL_OVERRIDE; - - // QAccessibleTextInterface - void scrollToSubstring(int startIndex, int endIndex) Q_DECL_OVERRIDE; - - using QAccessibleTextWidget::text; - -protected: - QTextEdit *textEdit() const; - - QPoint scrollBarPosition() const Q_DECL_OVERRIDE; - QTextCursor textCursor() const Q_DECL_OVERRIDE; - void setTextCursor(const QTextCursor &textCursor) Q_DECL_OVERRIDE; - QTextDocument *textDocument() const Q_DECL_OVERRIDE; - QWidget *viewport() const Q_DECL_OVERRIDE; -}; -#endif // QT_NO_TEXTEDIT -#endif //QT_NO_CURSOR - -class QAccessibleStackedWidget : public QAccessibleWidget -{ -public: - explicit QAccessibleStackedWidget(QWidget *widget); - - QAccessibleInterface *childAt(int x, int y) const Q_DECL_OVERRIDE; - int childCount() const Q_DECL_OVERRIDE; - int indexOfChild(const QAccessibleInterface *child) const Q_DECL_OVERRIDE; - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - -protected: - QStackedWidget *stackedWidget() const; -}; - -class QAccessibleToolBox : public QAccessibleWidget -{ -public: - explicit QAccessibleToolBox(QWidget *widget); - -// FIXME we currently expose the toolbox but it is not keyboard navigatable -// and the accessible hierarchy is not exactly beautiful. -// int childCount() const; -// QAccessibleInterface *child(int index) const; -// int indexOfChild(const QAccessibleInterface *child) const; - -protected: - QToolBox *toolBox() const; -}; - -#ifndef QT_NO_MDIAREA -class QAccessibleMdiArea : public QAccessibleWidget -{ -public: - explicit QAccessibleMdiArea(QWidget *widget); - - int childCount() const Q_DECL_OVERRIDE; - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - int indexOfChild(const QAccessibleInterface *child) const Q_DECL_OVERRIDE; - -protected: - QMdiArea *mdiArea() const; -}; - -class QAccessibleMdiSubWindow : public QAccessibleWidget -{ -public: - explicit QAccessibleMdiSubWindow(QWidget *widget); - - QString text(QAccessible::Text textType) const Q_DECL_OVERRIDE; - void setText(QAccessible::Text textType, const QString &text) Q_DECL_OVERRIDE; - QAccessible::State state() const Q_DECL_OVERRIDE; - int childCount() const Q_DECL_OVERRIDE; - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - int indexOfChild(const QAccessibleInterface *child) const Q_DECL_OVERRIDE; - QRect rect() const Q_DECL_OVERRIDE; - -protected: - QMdiSubWindow *mdiSubWindow() const; -}; -#endif // QT_NO_MDIAREA - -class QAccessibleDialogButtonBox : public QAccessibleWidget -{ -public: - explicit QAccessibleDialogButtonBox(QWidget *widget); -}; - -#if !defined(QT_NO_TEXTBROWSER) && !defined(QT_NO_CURSOR) -class QAccessibleTextBrowser : public QAccessibleTextEdit -{ -public: - explicit QAccessibleTextBrowser(QWidget *widget); - - QAccessible::Role role() const Q_DECL_OVERRIDE; -}; -#endif // QT_NO_TEXTBROWSER && QT_NO_CURSOR - -#ifndef QT_NO_CALENDARWIDGET -class QAccessibleCalendarWidget : public QAccessibleWidget -{ -public: - explicit QAccessibleCalendarWidget(QWidget *widget); - - int childCount() const Q_DECL_OVERRIDE; - int indexOfChild(const QAccessibleInterface *child) const Q_DECL_OVERRIDE; - - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - -protected: - QCalendarWidget *calendarWidget() const; - -private: - QAbstractItemView *calendarView() const; - QWidget *navigationBar() const; -}; -#endif // QT_NO_CALENDARWIDGET - -#ifndef QT_NO_DOCKWIDGET -class QAccessibleDockWidget: public QAccessibleWidget -{ -public: - explicit QAccessibleDockWidget(QWidget *widget); - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - int indexOfChild(const QAccessibleInterface *child) const Q_DECL_OVERRIDE; - int childCount() const Q_DECL_OVERRIDE; - QRect rect () const Q_DECL_OVERRIDE; - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - - QDockWidget *dockWidget() const; -protected: - QDockWidgetLayout *dockWidgetLayout() const; -}; - -#endif // QT_NO_DOCKWIDGET - -#ifndef QT_NO_MAINWINDOW -class QAccessibleMainWindow : public QAccessibleWidget -{ -public: - explicit QAccessibleMainWindow(QWidget *widget); - - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - int childCount() const Q_DECL_OVERRIDE; - int indexOfChild(const QAccessibleInterface *iface) const Q_DECL_OVERRIDE; - QAccessibleInterface *childAt(int x, int y) const Q_DECL_OVERRIDE; - QMainWindow *mainWindow() const; - -}; -#endif //QT_NO_MAINWINDOW - -#endif // QT_NO_ACCESSIBILITY - -QT_END_NAMESPACE - -#endif // QACESSIBLEWIDGETS_H diff --git a/src/plugins/accessible/widgets/rangecontrols.cpp b/src/plugins/accessible/widgets/rangecontrols.cpp deleted file mode 100644 index f2aa5522e8..0000000000 --- a/src/plugins/accessible/widgets/rangecontrols.cpp +++ /dev/null @@ -1,323 +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 "rangecontrols.h" - -#include <qslider.h> -#include <qdial.h> -#include <qspinbox.h> -#include <qscrollbar.h> -#include <qstyle.h> -#include <qstyleoption.h> -#include <qdebug.h> -#include <qglobal.h> -#include <QDoubleSpinBox> -#include <QDial> -#include <qmath.h> -#include <private/qmath_p.h> - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_ACCESSIBILITY -extern QString Q_GUI_EXPORT qt_accStripAmp(const QString &text); -#ifndef QT_NO_SCROLLBAR -extern QStyleOptionSlider Q_GUI_EXPORT qt_qscrollbarStyleOption(QScrollBar *scrollBar); -#endif -#ifndef QT_NO_SLIDER -extern QStyleOptionSlider Q_GUI_EXPORT qt_qsliderStyleOption(QSlider *slider); -#endif - -#ifndef QT_NO_SPINBOX -QAccessibleAbstractSpinBox::QAccessibleAbstractSpinBox(QWidget *w) -: QAccessibleWidget(w, QAccessible::SpinBox) -{ - Q_ASSERT(abstractSpinBox()); -} - -/*! - Returns the underlying QAbstractSpinBox. -*/ -QAbstractSpinBox *QAccessibleAbstractSpinBox::abstractSpinBox() const -{ - return qobject_cast<QAbstractSpinBox*>(object()); -} - -QString QAccessibleAbstractSpinBox::text(QAccessible::Text t) const -{ - if (t == QAccessible::Value) - return abstractSpinBox()->text(); - return QAccessibleWidget::text(t); -} - -void *QAccessibleAbstractSpinBox::interface_cast(QAccessible::InterfaceType t) -{ - if (t == QAccessible::ValueInterface) - return static_cast<QAccessibleValueInterface*>(this); - return QAccessibleWidget::interface_cast(t); -} - -QVariant QAccessibleAbstractSpinBox::currentValue() const -{ - QVariant result = abstractSpinBox()->property("value"); - QVariant::Type type = result.type(); - - // IA2 only allows numeric types - if (type == QVariant::Int || type == QVariant::UInt || type == QVariant::LongLong - || type == QVariant::ULongLong || type == QVariant::Double) - return result; - - return QVariant(); -} - -void QAccessibleAbstractSpinBox::setCurrentValue(const QVariant &value) -{ - abstractSpinBox()->setProperty("value", value); -} - -QVariant QAccessibleAbstractSpinBox::maximumValue() const -{ - return abstractSpinBox()->property("maximum"); -} - -QVariant QAccessibleAbstractSpinBox::minimumValue() const -{ - return abstractSpinBox()->property("minimum"); -} - -QVariant QAccessibleAbstractSpinBox::minimumStepSize() const -{ - return abstractSpinBox()->property("stepSize"); -} - -/*! - \class QAccessibleSpinBox - \brief The QAccessibleSpinBox class implements the QAccessibleInterface for spinbox widgets. - \internal - - \ingroup accessibility -*/ - -/*! - Constructs a QAccessibleSpinWidget object for \a w. -*/ -QAccessibleSpinBox::QAccessibleSpinBox(QWidget *w) -: QAccessibleAbstractSpinBox(w) -{ - Q_ASSERT(spinBox()); - addControllingSignal(QLatin1String("valueChanged(int)")); - addControllingSignal(QLatin1String("valueChanged(QString)")); -} - -/*! - Returns the underlying QSpinBox. -*/ -QSpinBox *QAccessibleSpinBox::spinBox() const -{ - return qobject_cast<QSpinBox*>(object()); -} - - -// ================================== QAccessibleDoubleSpinBox ================================== -QAccessibleDoubleSpinBox::QAccessibleDoubleSpinBox(QWidget *widget) - : QAccessibleAbstractSpinBox(widget) -{ - Q_ASSERT(qobject_cast<QDoubleSpinBox *>(widget)); - addControllingSignal(QLatin1String("valueChanged(double)")); - addControllingSignal(QLatin1String("valueChanged(QString)")); -} - -/*! - Returns the underlying QDoubleSpinBox. -*/ -QDoubleSpinBox *QAccessibleDoubleSpinBox::doubleSpinBox() const -{ - return static_cast<QDoubleSpinBox*>(object()); -} - -QString QAccessibleDoubleSpinBox::text(QAccessible::Text textType) const -{ - if (textType == QAccessible::Value) - return doubleSpinBox()->textFromValue(doubleSpinBox()->value()); - return QAccessibleWidget::text(textType); -} - -#endif // QT_NO_SPINBOX - -#ifndef QT_NO_SCROLLBAR -/*! - \class QAccessibleScrollBar - \brief The QAccessibleScrollBar class implements the QAccessibleInterface for scroll bars. - \internal - - \ingroup accessibility -*/ - -/*! - Constructs a QAccessibleScrollBar object for \a w. - \a name is propagated to the QAccessibleWidget constructor. -*/ -QAccessibleScrollBar::QAccessibleScrollBar(QWidget *w) -: QAccessibleAbstractSlider(w, QAccessible::ScrollBar) -{ - Q_ASSERT(scrollBar()); - addControllingSignal(QLatin1String("valueChanged(int)")); -} - -/*! Returns the scroll bar. */ -QScrollBar *QAccessibleScrollBar::scrollBar() const -{ - return qobject_cast<QScrollBar*>(object()); -} - -QString QAccessibleScrollBar::text(QAccessible::Text t) const -{ - if (t == QAccessible::Value) - return QString::number(scrollBar()->value()); - return QAccessibleAbstractSlider::text(t); -} - -#endif // QT_NO_SCROLLBAR - -#ifndef QT_NO_SLIDER -/*! - \class QAccessibleSlider - \brief The QAccessibleSlider class implements the QAccessibleInterface for sliders. - \internal - - \ingroup accessibility -*/ - -/*! - Constructs a QAccessibleScrollBar object for \a w. - \a name is propagated to the QAccessibleWidget constructor. -*/ -QAccessibleSlider::QAccessibleSlider(QWidget *w) -: QAccessibleAbstractSlider(w) -{ - Q_ASSERT(slider()); - addControllingSignal(QLatin1String("valueChanged(int)")); -} - -/*! Returns the slider. */ -QSlider *QAccessibleSlider::slider() const -{ - return qobject_cast<QSlider*>(object()); -} - -QString QAccessibleSlider::text(QAccessible::Text t) const -{ - if (t == QAccessible::Value) - return QString::number(slider()->value()); - - return QAccessibleAbstractSlider::text(t); -} - -QAccessibleAbstractSlider::QAccessibleAbstractSlider(QWidget *w, QAccessible::Role r) - : QAccessibleWidget(w, r) -{ - Q_ASSERT(qobject_cast<QAbstractSlider *>(w)); -} - -void *QAccessibleAbstractSlider::interface_cast(QAccessible::InterfaceType t) -{ - if (t == QAccessible::ValueInterface) - return static_cast<QAccessibleValueInterface*>(this); - return QAccessibleWidget::interface_cast(t); -} - -QVariant QAccessibleAbstractSlider::currentValue() const -{ - return abstractSlider()->value(); -} - -void QAccessibleAbstractSlider::setCurrentValue(const QVariant &value) -{ - abstractSlider()->setValue(value.toInt()); -} - -QVariant QAccessibleAbstractSlider::maximumValue() const -{ - return abstractSlider()->maximum(); -} - -QVariant QAccessibleAbstractSlider::minimumValue() const -{ - return abstractSlider()->minimum(); -} - -QVariant QAccessibleAbstractSlider::minimumStepSize() const -{ - return abstractSlider()->singleStep(); -} - -QAbstractSlider *QAccessibleAbstractSlider::abstractSlider() const -{ - return static_cast<QAbstractSlider *>(object()); -} - -#endif // QT_NO_SLIDER - -#ifndef QT_NO_DIAL -// ======================================= QAccessibleDial ====================================== -QAccessibleDial::QAccessibleDial(QWidget *widget) - : QAccessibleAbstractSlider(widget, QAccessible::Dial) -{ - Q_ASSERT(qobject_cast<QDial *>(widget)); - addControllingSignal(QLatin1String("valueChanged(int)")); -} - -QString QAccessibleDial::text(QAccessible::Text textType) const -{ - if (textType == QAccessible::Value) - return QString::number(dial()->value()); - - return QAccessibleAbstractSlider::text(textType); -} - -QDial *QAccessibleDial::dial() const -{ - return static_cast<QDial*>(object()); -} -#endif // QT_NO_DIAL - -#endif // QT_NO_ACCESSIBILITY - -QT_END_NAMESPACE diff --git a/src/plugins/accessible/widgets/rangecontrols.h b/src/plugins/accessible/widgets/rangecontrols.h deleted file mode 100644 index dd69788bb1..0000000000 --- a/src/plugins/accessible/widgets/rangecontrols.h +++ /dev/null @@ -1,160 +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 RANGECONTROLS_H -#define RANGECONTROLS_H - -#include <QtWidgets/qaccessiblewidget.h> - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_ACCESSIBILITY - -class QAbstractSpinBox; -class QAbstractSlider; -class QScrollBar; -class QSlider; -class QSpinBox; -class QDoubleSpinBox; -class QDial; - -#ifndef QT_NO_SPINBOX -class QAccessibleAbstractSpinBox: public QAccessibleWidget, public QAccessibleValueInterface // TODO, public QAccessibleActionInterface -{ -public: - explicit QAccessibleAbstractSpinBox(QWidget *w); - - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - void *interface_cast(QAccessible::InterfaceType t) Q_DECL_OVERRIDE; - - // QAccessibleValueInterface - QVariant currentValue() const Q_DECL_OVERRIDE; - void setCurrentValue(const QVariant &value) Q_DECL_OVERRIDE; - QVariant maximumValue() const Q_DECL_OVERRIDE; - QVariant minimumValue() const Q_DECL_OVERRIDE; - QVariant minimumStepSize() const Q_DECL_OVERRIDE; - - // FIXME Action interface - -protected: - QAbstractSpinBox *abstractSpinBox() const; -}; - -class QAccessibleSpinBox : public QAccessibleAbstractSpinBox -{ -public: - explicit QAccessibleSpinBox(QWidget *w); - -protected: - QSpinBox *spinBox() const; -}; - -class QAccessibleDoubleSpinBox : public QAccessibleAbstractSpinBox -{ -public: - explicit QAccessibleDoubleSpinBox(QWidget *widget); - - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - -protected: - QDoubleSpinBox *doubleSpinBox() const; -}; -#endif // QT_NO_SPINBOX - -class QAccessibleAbstractSlider: public QAccessibleWidget, public QAccessibleValueInterface -{ -public: - explicit QAccessibleAbstractSlider(QWidget *w, QAccessible::Role r = QAccessible::Slider); - void *interface_cast(QAccessible::InterfaceType t) Q_DECL_OVERRIDE; - - // QAccessibleValueInterface - QVariant currentValue() const Q_DECL_OVERRIDE; - void setCurrentValue(const QVariant &value) Q_DECL_OVERRIDE; - QVariant maximumValue() const Q_DECL_OVERRIDE; - QVariant minimumValue() const Q_DECL_OVERRIDE; - QVariant minimumStepSize() const Q_DECL_OVERRIDE; - -protected: - QAbstractSlider *abstractSlider() const; -}; - -#ifndef QT_NO_SCROLLBAR -class QAccessibleScrollBar : public QAccessibleAbstractSlider -{ -public: - explicit QAccessibleScrollBar(QWidget *w); - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - -protected: - QScrollBar *scrollBar() const; -}; -#endif // QT_NO_SCROLLBAR - -#ifndef QT_NO_SLIDER -class QAccessibleSlider : public QAccessibleAbstractSlider -{ -public: - explicit QAccessibleSlider(QWidget *w); - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - -protected: - QSlider *slider() const; -}; -#endif // QT_NO_SLIDER - -#ifndef QT_NO_DIAL -class QAccessibleDial : public QAccessibleAbstractSlider -{ -public: - explicit QAccessibleDial(QWidget *w); - - QString text(QAccessible::Text textType) const Q_DECL_OVERRIDE; - -protected: - QDial *dial() const; -}; -#endif // QT_NO_DIAL - -#endif // QT_NO_ACCESSIBILITY - -QT_END_NAMESPACE - -#endif // RANGECONTROLS_H diff --git a/src/plugins/accessible/widgets/simplewidgets.cpp b/src/plugins/accessible/widgets/simplewidgets.cpp deleted file mode 100644 index a5365b2598..0000000000 --- a/src/plugins/accessible/widgets/simplewidgets.cpp +++ /dev/null @@ -1,884 +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 "simplewidgets.h" - -#include <qabstractbutton.h> -#include <qcheckbox.h> -#include <qpushbutton.h> -#include <qprogressbar.h> -#include <qstatusbar.h> -#include <qradiobutton.h> -#include <qtoolbutton.h> -#include <qmenu.h> -#include <qlabel.h> -#include <qgroupbox.h> -#include <qlcdnumber.h> -#include <qlineedit.h> -#include <private/qlineedit_p.h> -#include <qstyle.h> -#include <qstyleoption.h> -#include <qtextdocument.h> -#include <qwindow.h> -#include <private/qwindowcontainer_p.h> -#include <QtCore/qvarlengtharray.h> - -#ifdef Q_OS_MAC -#include <qfocusframe.h> -#endif - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_ACCESSIBILITY - -extern QList<QWidget*> childWidgets(const QWidget *widget, bool includeTopLevel = false); - -QString Q_GUI_EXPORT qt_accStripAmp(const QString &text); -QString Q_GUI_EXPORT qt_accHotKey(const QString &text); - -/*! - \class QAccessibleButton - \brief The QAccessibleButton class implements the QAccessibleInterface for button type widgets. - \internal - - \ingroup accessibility -*/ - -/*! - Creates a QAccessibleButton object for \a w. - \a role is propagated to the QAccessibleWidget constructor. -*/ -QAccessibleButton::QAccessibleButton(QWidget *w, QAccessible::Role role) -: QAccessibleWidget(w, role) -{ - Q_ASSERT(button()); - if (button()->isCheckable()) - addControllingSignal(QLatin1String("toggled(bool)")); - else - addControllingSignal(QLatin1String("clicked()")); -} - -/*! Returns the button. */ -QAbstractButton *QAccessibleButton::button() const -{ - return qobject_cast<QAbstractButton*>(object()); -} - -/*! \reimp */ -QString QAccessibleButton::text(QAccessible::Text t) const -{ - QString str; - switch (t) { - case QAccessible::Accelerator: - { -#ifndef QT_NO_SHORTCUT - QPushButton *pb = qobject_cast<QPushButton*>(object()); - if (pb && pb->isDefault()) - str = QKeySequence(Qt::Key_Enter).toString(QKeySequence::NativeText); -#endif - if (str.isEmpty()) - str = qt_accHotKey(button()->text()); - } - break; - case QAccessible::Name: - str = widget()->accessibleName(); - if (str.isEmpty()) - str = button()->text(); - break; - default: - break; - } - if (str.isEmpty()) - str = QAccessibleWidget::text(t); - return qt_accStripAmp(str); -} - -QAccessible::State QAccessibleButton::state() const -{ - QAccessible::State state = QAccessibleWidget::state(); - - QAbstractButton *b = button(); - QCheckBox *cb = qobject_cast<QCheckBox *>(b); - if (b->isCheckable()) - state.checkable = true; - if (b->isChecked()) - state.checked = true; - else if (cb && cb->checkState() == Qt::PartiallyChecked) - state.checkStateMixed = true; - if (b->isDown()) - state.pressed = true; - QPushButton *pb = qobject_cast<QPushButton*>(b); - if (pb) { - if (pb->isDefault()) - state.defaultButton = true; -#ifndef QT_NO_MENU - if (pb->menu()) - state.hasPopup = true; -#endif - } - - return state; -} - -QStringList QAccessibleButton::actionNames() const -{ - QStringList names; - if (widget()->isEnabled()) { - switch (role()) { - case QAccessible::ButtonMenu: - names << showMenuAction(); - break; - case QAccessible::RadioButton: - names << toggleAction(); - break; - default: - if (button()->isCheckable()) { - names << toggleAction(); - } else { - names << pressAction(); - } - break; - } - } - names << QAccessibleWidget::actionNames(); - return names; -} - -void QAccessibleButton::doAction(const QString &actionName) -{ - if (!widget()->isEnabled()) - return; - if (actionName == pressAction() || - actionName == showMenuAction()) { -#ifndef QT_NO_MENU - QPushButton *pb = qobject_cast<QPushButton*>(object()); - if (pb && pb->menu()) - pb->showMenu(); - else -#endif - button()->animateClick(); - } else if (actionName == toggleAction()) { - button()->toggle(); - } else { - QAccessibleWidget::doAction(actionName); - } -} - -QStringList QAccessibleButton::keyBindingsForAction(const QString &actionName) const -{ - if (actionName == pressAction()) { -#ifndef QT_NO_SHORTCUT - return QStringList() << button()->shortcut().toString(); -#endif - } - return QStringList(); -} - - -#ifndef QT_NO_TOOLBUTTON -/*! - \class QAccessibleToolButton - \brief The QAccessibleToolButton class implements the QAccessibleInterface for tool buttons. - \internal - - \ingroup accessibility -*/ - -/*! - Creates a QAccessibleToolButton object for \a w. - \a role is propagated to the QAccessibleWidget constructor. -*/ -QAccessibleToolButton::QAccessibleToolButton(QWidget *w, QAccessible::Role role) -: QAccessibleButton(w, role) -{ - Q_ASSERT(toolButton()); -} - -/*! Returns the button. */ -QToolButton *QAccessibleToolButton::toolButton() const -{ - return qobject_cast<QToolButton*>(object()); -} - -/*! - Returns \c true if this tool button is a split button. -*/ -bool QAccessibleToolButton::isSplitButton() const -{ -#ifndef QT_NO_MENU - return toolButton()->menu() && toolButton()->popupMode() == QToolButton::MenuButtonPopup; -#else - return false; -#endif -} - -QAccessible::State QAccessibleToolButton::state() const -{ - QAccessible::State st = QAccessibleButton::state(); - if (toolButton()->autoRaise()) - st.hotTracked = true; -#ifndef QT_NO_MENU - if (toolButton()->menu()) - st.hasPopup = true; -#endif - return st; -} - -int QAccessibleToolButton::childCount() const -{ - return isSplitButton() ? 1 : 0; -} - -QAccessibleInterface *QAccessibleToolButton::child(int index) const -{ -#ifndef QT_NO_MENU - if (index == 0 && toolButton()->menu()) - { - return QAccessible::queryAccessibleInterface(toolButton()->menu()); - } -#endif - return 0; -} - -/*! - \internal - - Returns the button's text label, depending on the text \a t, and - the \a child. -*/ -QString QAccessibleToolButton::text(QAccessible::Text t) const -{ - QString str; - switch (t) { - case QAccessible::Name: - str = toolButton()->accessibleName(); - if (str.isEmpty()) - str = toolButton()->text(); - break; - default: - break; - } - if (str.isEmpty()) - str = QAccessibleButton::text(t); - return qt_accStripAmp(str); -} - -/* - The three different tool button types can have the following actions: -| DelayedPopup | ShowMenuAction + (PressedAction || CheckedAction) | -| MenuButtonPopup | ShowMenuAction + (PressedAction || CheckedAction) | -| InstantPopup | ShowMenuAction | -*/ -QStringList QAccessibleToolButton::actionNames() const -{ - QStringList names; - if (widget()->isEnabled()) { - if (toolButton()->menu()) - names << showMenuAction(); - if (toolButton()->popupMode() != QToolButton::InstantPopup) - names << QAccessibleButton::actionNames(); - } - return names; -} - -void QAccessibleToolButton::doAction(const QString &actionName) -{ - if (!widget()->isEnabled()) - return; - - if (actionName == pressAction()) { - button()->click(); - } else if (actionName == showMenuAction()) { - if (toolButton()->popupMode() != QToolButton::InstantPopup) { - toolButton()->setDown(true); -#ifndef QT_NO_MENU - toolButton()->showMenu(); -#endif - } - } else { - QAccessibleButton::doAction(actionName); - } - -} - -#endif // QT_NO_TOOLBUTTON - -/*! - \class QAccessibleDisplay - \brief The QAccessibleDisplay class implements the QAccessibleInterface for widgets that display information. - \internal - - \ingroup accessibility -*/ - -/*! - Constructs a QAccessibleDisplay object for \a w. - \a role is propagated to the QAccessibleWidget constructor. -*/ -QAccessibleDisplay::QAccessibleDisplay(QWidget *w, QAccessible::Role role) -: QAccessibleWidget(w, role) -{ -} - -QAccessible::Role QAccessibleDisplay::role() const -{ - QLabel *l = qobject_cast<QLabel*>(object()); - if (l) { - if (l->pixmap()) - return QAccessible::Graphic; -#ifndef QT_NO_PICTURE - if (l->picture()) - return QAccessible::Graphic; -#endif -#ifndef QT_NO_MOVIE - if (l->movie()) - return QAccessible::Animation; -#endif -#ifndef QT_NO_PROGRESSBAR - } else if (qobject_cast<QProgressBar*>(object())) { - return QAccessible::ProgressBar; -#endif - } else if (qobject_cast<QStatusBar*>(object())) { - return QAccessible::StatusBar; - } - return QAccessibleWidget::role(); -} - -QString QAccessibleDisplay::text(QAccessible::Text t) const -{ - QString str; - switch (t) { - case QAccessible::Name: - str = widget()->accessibleName(); - if (str.isEmpty()) { - if (qobject_cast<QLabel*>(object())) { - QLabel *label = qobject_cast<QLabel*>(object()); - str = label->text(); - if (label->textFormat() == Qt::RichText - || (label->textFormat() == Qt::AutoText && Qt::mightBeRichText(str))) { - QTextDocument doc; - doc.setHtml(str); - str = doc.toPlainText(); - } -#ifndef QT_NO_LCDNUMBER - } else if (qobject_cast<QLCDNumber*>(object())) { - QLCDNumber *l = qobject_cast<QLCDNumber*>(object()); - if (l->digitCount()) - str = QString::number(l->value()); - else - str = QString::number(l->intValue()); -#endif - } else if (qobject_cast<QStatusBar*>(object())) { - return qobject_cast<QStatusBar*>(object())->currentMessage(); - } - } - break; - case QAccessible::Value: -#ifndef QT_NO_PROGRESSBAR - if (qobject_cast<QProgressBar*>(object())) - str = QString::number(qobject_cast<QProgressBar*>(object())->value()); -#endif - break; - default: - break; - } - if (str.isEmpty()) - str = QAccessibleWidget::text(t); - return qt_accStripAmp(str); -} - -/*! \reimp */ -QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > -QAccessibleDisplay::relations(QAccessible::Relation match /* = QAccessible::AllRelations */) const -{ - QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > rels = QAccessibleWidget::relations(match); - if (match & QAccessible::Labelled) { - QVarLengthArray<QObject *, 4> relatedObjects; - -#ifndef QT_NO_SHORTCUT - if (QLabel *label = qobject_cast<QLabel*>(object())) { - relatedObjects.append(label->buddy()); - } -#endif - for (int i = 0; i < relatedObjects.count(); ++i) { - const QAccessible::Relation rel = QAccessible::Labelled; - QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(relatedObjects.at(i)); - if (iface) - rels.append(qMakePair(iface, rel)); - } - } - return rels; -} - -void *QAccessibleDisplay::interface_cast(QAccessible::InterfaceType t) -{ - if (t == QAccessible::ImageInterface) - return static_cast<QAccessibleImageInterface*>(this); - return QAccessibleWidget::interface_cast(t); -} - -/*! \internal */ -QString QAccessibleDisplay::imageDescription() const -{ -#ifndef QT_NO_TOOLTIP - return widget()->toolTip(); -#else - return QString::null; -#endif -} - -/*! \internal */ -QSize QAccessibleDisplay::imageSize() const -{ - QLabel *label = qobject_cast<QLabel *>(widget()); - if (!label) - return QSize(); - const QPixmap *pixmap = label->pixmap(); - if (!pixmap) - return QSize(); - return pixmap->size(); -} - -/*! \internal */ -QPoint QAccessibleDisplay::imagePosition() const -{ - QLabel *label = qobject_cast<QLabel *>(widget()); - if (!label) - return QPoint(); - const QPixmap *pixmap = label->pixmap(); - if (!pixmap) - return QPoint(); - - return QPoint(label->mapToGlobal(label->pos())); -} - -#ifndef QT_NO_GROUPBOX -QAccessibleGroupBox::QAccessibleGroupBox(QWidget *w) -: QAccessibleWidget(w) -{ -} - -QGroupBox* QAccessibleGroupBox::groupBox() const -{ - return static_cast<QGroupBox *>(widget()); -} - -QString QAccessibleGroupBox::text(QAccessible::Text t) const -{ - QString txt = QAccessibleWidget::text(t); - - if (txt.isEmpty()) { - switch (t) { - case QAccessible::Name: - txt = qt_accStripAmp(groupBox()->title()); - break; - case QAccessible::Description: - txt = qt_accStripAmp(groupBox()->toolTip()); - break; - default: - break; - } - } - - return txt; -} - -QAccessible::State QAccessibleGroupBox::state() const -{ - QAccessible::State st = QAccessibleWidget::state(); - st.checkable = groupBox()->isCheckable(); - st.checked = groupBox()->isChecked(); - return st; -} - -QAccessible::Role QAccessibleGroupBox::role() const -{ - return groupBox()->isCheckable() ? QAccessible::CheckBox : QAccessible::Grouping; -} - -QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > -QAccessibleGroupBox::relations(QAccessible::Relation match /* = QAccessible::AllRelations */) const -{ - QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > rels = QAccessibleWidget::relations(match); - - if ((match & QAccessible::Labelled) && (!groupBox()->title().isEmpty())) { - const QList<QWidget*> kids = childWidgets(widget()); - for (int i = 0; i < kids.count(); ++i) { - QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(kids.at(i)); - if (iface) - rels.append(qMakePair(iface, QAccessible::Relation(QAccessible::Labelled))); - } - } - return rels; -} - -QStringList QAccessibleGroupBox::actionNames() const -{ - QStringList actions = QAccessibleWidget::actionNames(); - - if (groupBox()->isCheckable()) { - actions.prepend(QAccessibleActionInterface::toggleAction()); - } - return actions; -} - -void QAccessibleGroupBox::doAction(const QString &actionName) -{ - if (actionName == QAccessibleActionInterface::toggleAction()) - groupBox()->setChecked(!groupBox()->isChecked()); -} - -QStringList QAccessibleGroupBox::keyBindingsForAction(const QString &) const -{ - return QStringList(); -} - -#endif - -#ifndef QT_NO_LINEEDIT -/*! - \class QAccessibleLineEdit - \brief The QAccessibleLineEdit class implements the QAccessibleInterface for widgets with editable text - \internal - - \ingroup accessibility -*/ - -/*! - Constructs a QAccessibleLineEdit object for \a w. - \a name is propagated to the QAccessibleWidget constructor. -*/ -QAccessibleLineEdit::QAccessibleLineEdit(QWidget *w, const QString &name) -: QAccessibleWidget(w, QAccessible::EditableText, name) -{ - addControllingSignal(QLatin1String("textChanged(const QString&)")); - addControllingSignal(QLatin1String("returnPressed()")); -} - -/*! Returns the line edit. */ -QLineEdit *QAccessibleLineEdit::lineEdit() const -{ - return qobject_cast<QLineEdit*>(object()); -} - -QString QAccessibleLineEdit::text(QAccessible::Text t) const -{ - QString str; - switch (t) { - case QAccessible::Value: - if (lineEdit()->echoMode() == QLineEdit::Normal) - str = lineEdit()->text(); - break; - default: - break; - } - if (str.isEmpty()) - str = QAccessibleWidget::text(t); - return qt_accStripAmp(str); -} - -void QAccessibleLineEdit::setText(QAccessible::Text t, const QString &text) -{ - if (t != QAccessible::Value) { - QAccessibleWidget::setText(t, text); - return; - } - - QString newText = text; - if (lineEdit()->validator()) { - int pos = 0; - if (lineEdit()->validator()->validate(newText, pos) != QValidator::Acceptable) - return; - } - lineEdit()->setText(newText); -} - -QAccessible::State QAccessibleLineEdit::state() const -{ - QAccessible::State state = QAccessibleWidget::state(); - - QLineEdit *l = lineEdit(); - if (l->isReadOnly()) - state.readOnly = true; - else - state.editable = true; - - if (l->echoMode() != QLineEdit::Normal) - state.passwordEdit = true; - state.selectable = true; - if (l->hasSelectedText()) - state.selected = true; - - return state; -} - -void *QAccessibleLineEdit::interface_cast(QAccessible::InterfaceType t) -{ - if (t == QAccessible::TextInterface) - return static_cast<QAccessibleTextInterface*>(this); - if (t == QAccessible::EditableTextInterface) - return static_cast<QAccessibleEditableTextInterface*>(this); - return QAccessibleWidget::interface_cast(t); -} - -void QAccessibleLineEdit::addSelection(int startOffset, int endOffset) -{ - setSelection(0, startOffset, endOffset); -} - -QString QAccessibleLineEdit::attributes(int offset, int *startOffset, int *endOffset) const -{ - // QLineEdit doesn't have text attributes - *startOffset = *endOffset = offset; - return QString(); -} - -int QAccessibleLineEdit::cursorPosition() const -{ - return lineEdit()->cursorPosition(); -} - -QRect QAccessibleLineEdit::characterRect(int offset) const -{ - int x = lineEdit()->d_func()->control->cursorToX(offset); - int y; - lineEdit()->getTextMargins(0, &y, 0, 0); - QFontMetrics fm(lineEdit()->font()); - const QString ch = text(offset, offset + 1); - if (ch.isEmpty()) - return QRect(); - int w = fm.width(ch); - int h = fm.height(); - QRect r(x, y, w, h); - r.moveTo(lineEdit()->mapToGlobal(r.topLeft())); - return r; -} - -int QAccessibleLineEdit::selectionCount() const -{ - return lineEdit()->hasSelectedText() ? 1 : 0; -} - -int QAccessibleLineEdit::offsetAtPoint(const QPoint &point) const -{ - QPoint p = lineEdit()->mapFromGlobal(point); - - return lineEdit()->cursorPositionAt(p); -} - -void QAccessibleLineEdit::selection(int selectionIndex, int *startOffset, int *endOffset) const -{ - *startOffset = *endOffset = 0; - if (selectionIndex != 0) - return; - - *startOffset = lineEdit()->selectionStart(); - *endOffset = *startOffset + lineEdit()->selectedText().count(); -} - -QString QAccessibleLineEdit::text(int startOffset, int endOffset) const -{ - if (startOffset > endOffset) - return QString(); - - if (lineEdit()->echoMode() != QLineEdit::Normal) - return QString(); - - return lineEdit()->text().mid(startOffset, endOffset - startOffset); -} - -QString QAccessibleLineEdit::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int *startOffset, int *endOffset) const -{ - if (lineEdit()->echoMode() != QLineEdit::Normal) { - *startOffset = *endOffset = -1; - return QString(); - } - return QAccessibleTextInterface::textBeforeOffset(offset, boundaryType, startOffset, endOffset); -} - -QString QAccessibleLineEdit::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int *startOffset, int *endOffset) const -{ - if (lineEdit()->echoMode() != QLineEdit::Normal) { - *startOffset = *endOffset = -1; - return QString(); - } - return QAccessibleTextInterface::textAfterOffset(offset, boundaryType, startOffset, endOffset); -} - -QString QAccessibleLineEdit::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int *startOffset, int *endOffset) const -{ - if (lineEdit()->echoMode() != QLineEdit::Normal) { - *startOffset = *endOffset = -1; - return QString(); - } - return QAccessibleTextInterface::textAtOffset(offset, boundaryType, startOffset, endOffset); -} - -void QAccessibleLineEdit::removeSelection(int selectionIndex) -{ - if (selectionIndex != 0) - return; - - lineEdit()->deselect(); -} - -void QAccessibleLineEdit::setCursorPosition(int position) -{ - lineEdit()->setCursorPosition(position); -} - -void QAccessibleLineEdit::setSelection(int selectionIndex, int startOffset, int endOffset) -{ - if (selectionIndex != 0) - return; - - lineEdit()->setSelection(startOffset, endOffset - startOffset); -} - -int QAccessibleLineEdit::characterCount() const -{ - return lineEdit()->text().count(); -} - -void QAccessibleLineEdit::scrollToSubstring(int startIndex, int endIndex) -{ - lineEdit()->setCursorPosition(endIndex); - lineEdit()->setCursorPosition(startIndex); -} - -void QAccessibleLineEdit::deleteText(int startOffset, int endOffset) -{ - lineEdit()->setText(lineEdit()->text().remove(startOffset, endOffset - startOffset)); -} - -void QAccessibleLineEdit::insertText(int offset, const QString &text) -{ - lineEdit()->setText(lineEdit()->text().insert(offset, text)); -} - -void QAccessibleLineEdit::replaceText(int startOffset, int endOffset, const QString &text) -{ - lineEdit()->setText(lineEdit()->text().replace(startOffset, endOffset - startOffset, text)); -} - -#endif // QT_NO_LINEEDIT - -#ifndef QT_NO_PROGRESSBAR -QAccessibleProgressBar::QAccessibleProgressBar(QWidget *o) - : QAccessibleDisplay(o) -{ - Q_ASSERT(progressBar()); -} - -void *QAccessibleProgressBar::interface_cast(QAccessible::InterfaceType t) -{ - if (t == QAccessible::ValueInterface) - return static_cast<QAccessibleValueInterface*>(this); - return QAccessibleDisplay::interface_cast(t); -} - -QVariant QAccessibleProgressBar::currentValue() const -{ - return progressBar()->value(); -} - -QVariant QAccessibleProgressBar::maximumValue() const -{ - return progressBar()->maximum(); -} - -QVariant QAccessibleProgressBar::minimumValue() const -{ - return progressBar()->minimum(); -} - -QVariant QAccessibleProgressBar::minimumStepSize() const -{ - // This is arbitrary since any value between min and max is valid. - // Some screen readers (orca use it to calculate how many digits to display though, - // so it makes sense to return a "sensible" value. Providing 100 increments seems ok. - return (progressBar()->maximum() - progressBar()->minimum()) / 100.0; -} - -QProgressBar *QAccessibleProgressBar::progressBar() const -{ - return qobject_cast<QProgressBar *>(object()); -} -#endif - - -QAccessibleWindowContainer::QAccessibleWindowContainer(QWidget *w) - : QAccessibleWidget(w) -{ -} - -int QAccessibleWindowContainer::childCount() const -{ - if (container()->containedWindow()) - return 1; - return 0; -} - -int QAccessibleWindowContainer::indexOfChild(const QAccessibleInterface *child) const -{ - if (child->object() == container()->containedWindow()) - return 0; - return -1; -} - -QAccessibleInterface *QAccessibleWindowContainer::child(int i) const -{ - if (i == 0) - return QAccessible::queryAccessibleInterface(container()->containedWindow()); - return 0; -} - -QWindowContainer *QAccessibleWindowContainer::container() const -{ - return static_cast<QWindowContainer *>(widget()); -} - -#endif // QT_NO_ACCESSIBILITY - -QT_END_NAMESPACE diff --git a/src/plugins/accessible/widgets/simplewidgets.h b/src/plugins/accessible/widgets/simplewidgets.h deleted file mode 100644 index be19d8324f..0000000000 --- a/src/plugins/accessible/widgets/simplewidgets.h +++ /dev/null @@ -1,215 +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 SIMPLEWIDGETS_H -#define SIMPLEWIDGETS_H - -#include <QtCore/qcoreapplication.h> -#include <QtWidgets/qaccessiblewidget.h> - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_ACCESSIBILITY - -class QAbstractButton; -class QLineEdit; -class QToolButton; -class QGroupBox; -class QProgressBar; - -class QAccessibleButton : public QAccessibleWidget -{ - Q_DECLARE_TR_FUNCTIONS(QAccessibleButton) -public: - QAccessibleButton(QWidget *w, QAccessible::Role r); - - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - QAccessible::State state() const Q_DECL_OVERRIDE; - - QStringList actionNames() const Q_DECL_OVERRIDE; - void doAction(const QString &actionName) Q_DECL_OVERRIDE; - QStringList keyBindingsForAction(const QString &actionName) const Q_DECL_OVERRIDE; - -protected: - QAbstractButton *button() const; -}; - -#ifndef QT_NO_TOOLBUTTON -class QAccessibleToolButton : public QAccessibleButton -{ -public: - QAccessibleToolButton(QWidget *w, QAccessible::Role role); - - QAccessible::State state() const Q_DECL_OVERRIDE; - - int childCount() const Q_DECL_OVERRIDE; - QAccessibleInterface *child(int index) const Q_DECL_OVERRIDE; - - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - - // QAccessibleActionInterface - QStringList actionNames() const Q_DECL_OVERRIDE; - void doAction(const QString &actionName) Q_DECL_OVERRIDE; - -protected: - QToolButton *toolButton() const; - - bool isSplitButton() const; -}; -#endif // QT_NO_TOOLBUTTON - -class QAccessibleDisplay : public QAccessibleWidget, public QAccessibleImageInterface -{ -public: - explicit QAccessibleDisplay(QWidget *w, QAccessible::Role role = QAccessible::StaticText); - - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - QAccessible::Role role() const Q_DECL_OVERRIDE; - - QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >relations(QAccessible::Relation match = QAccessible::AllRelations) const Q_DECL_OVERRIDE; - void *interface_cast(QAccessible::InterfaceType t) Q_DECL_OVERRIDE; - - // QAccessibleImageInterface - QString imageDescription() const Q_DECL_OVERRIDE; - QSize imageSize() const Q_DECL_OVERRIDE; - QPoint imagePosition() const Q_DECL_OVERRIDE; -}; - -#ifndef QT_NO_GROUPBOX -class QAccessibleGroupBox : public QAccessibleWidget -{ -public: - explicit QAccessibleGroupBox(QWidget *w); - - QAccessible::State state() const Q_DECL_OVERRIDE; - QAccessible::Role role() const Q_DECL_OVERRIDE; - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - - QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >relations(QAccessible::Relation match = QAccessible::AllRelations) const Q_DECL_OVERRIDE; - - //QAccessibleActionInterface - QStringList actionNames() const Q_DECL_OVERRIDE; - void doAction(const QString &actionName) Q_DECL_OVERRIDE; - QStringList keyBindingsForAction(const QString &) const Q_DECL_OVERRIDE; - -private: - QGroupBox *groupBox() const; -}; -#endif - -#ifndef QT_NO_LINEEDIT -class QAccessibleLineEdit : public QAccessibleWidget, public QAccessibleTextInterface, public QAccessibleEditableTextInterface -{ -public: - explicit QAccessibleLineEdit(QWidget *o, const QString &name = QString()); - - QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; - void setText(QAccessible::Text t, const QString &text) Q_DECL_OVERRIDE; - QAccessible::State state() const Q_DECL_OVERRIDE; - void *interface_cast(QAccessible::InterfaceType t) Q_DECL_OVERRIDE; - - // QAccessibleTextInterface - void addSelection(int startOffset, int endOffset) Q_DECL_OVERRIDE; - QString attributes(int offset, int *startOffset, int *endOffset) const Q_DECL_OVERRIDE; - int cursorPosition() const Q_DECL_OVERRIDE; - QRect characterRect(int offset) const Q_DECL_OVERRIDE; - int selectionCount() const Q_DECL_OVERRIDE; - int offsetAtPoint(const QPoint &point) const Q_DECL_OVERRIDE; - void selection(int selectionIndex, int *startOffset, int *endOffset) const Q_DECL_OVERRIDE; - QString text(int startOffset, int endOffset) const Q_DECL_OVERRIDE; - QString textBeforeOffset (int offset, QAccessible::TextBoundaryType boundaryType, - int *startOffset, int *endOffset) const Q_DECL_OVERRIDE; - QString textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int *startOffset, int *endOffset) const Q_DECL_OVERRIDE; - QString textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, - int *startOffset, int *endOffset) const Q_DECL_OVERRIDE; - void removeSelection(int selectionIndex) Q_DECL_OVERRIDE; - void setCursorPosition(int position) Q_DECL_OVERRIDE; - void setSelection(int selectionIndex, int startOffset, int endOffset) Q_DECL_OVERRIDE; - int characterCount() const Q_DECL_OVERRIDE; - void scrollToSubstring(int startIndex, int endIndex) Q_DECL_OVERRIDE; - - // QAccessibleEditableTextInterface - void deleteText(int startOffset, int endOffset) Q_DECL_OVERRIDE; - void insertText(int offset, const QString &text) Q_DECL_OVERRIDE; - void replaceText(int startOffset, int endOffset, const QString &text) Q_DECL_OVERRIDE; -protected: - QLineEdit *lineEdit() const; -}; -#endif // QT_NO_LINEEDIT - -#ifndef QT_NO_PROGRESSBAR -class QAccessibleProgressBar : public QAccessibleDisplay, public QAccessibleValueInterface -{ -public: - explicit QAccessibleProgressBar(QWidget *o); - void *interface_cast(QAccessible::InterfaceType t) Q_DECL_OVERRIDE; - - // QAccessibleValueInterface - QVariant currentValue() const Q_DECL_OVERRIDE; - QVariant maximumValue() const Q_DECL_OVERRIDE; - QVariant minimumValue() const Q_DECL_OVERRIDE; - QVariant minimumStepSize() const Q_DECL_OVERRIDE; - void setCurrentValue(const QVariant &) Q_DECL_OVERRIDE {} - -protected: - QProgressBar *progressBar() const; -}; -#endif - -class QWindowContainer; -class QAccessibleWindowContainer : public QAccessibleWidget -{ -public: - QAccessibleWindowContainer(QWidget *w); - int childCount() const Q_DECL_OVERRIDE; - int indexOfChild(const QAccessibleInterface *child) const Q_DECL_OVERRIDE; - QAccessibleInterface *child(int i) const Q_DECL_OVERRIDE; - -private: - QWindowContainer *container() const; -}; - -#endif // QT_NO_ACCESSIBILITY - -QT_END_NAMESPACE - -#endif // SIMPLEWIDGETS_H diff --git a/src/plugins/accessible/widgets/widgets.json b/src/plugins/accessible/widgets/widgets.json deleted file mode 100644 index 9ebcc89d35..0000000000 --- a/src/plugins/accessible/widgets/widgets.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "Keys": [ - "QLineEdit", - "QComboBox", - "QAbstractSpinBox", - "QSpinBox", - "QDoubleSpinBox", - "QScrollBar", - "QSlider", - "QAbstractSlider", - "QToolButton", - "QCheckBox", - "QRadioButton", - "QPushButton", - "QAbstractButton", - "QDialog", - "QMessageBox", - "QMainWindow", - "QLabel", - "QLCDNumber", - "QGroupBox", - "QStatusBar", - "QProgressBar", - "QPlainTextEdit", - "QMenuBar", - "QMenu", - "QTabBar", - "QToolBar", - "QSizeGrip", - "QListView", - "QTreeView", - "QTableView", - "QWidget", - "QSplitter", - "QSplitterHandle", - "QTextEdit", - "QTipLabel", - "QFrame", - "QStackedWidget", - "QToolBox", - "QMdiArea", - "QMdiSubWindow", - "QDialogButtonBox", - "QDial", - "QRubberBand", - "QTextBrowser", - "QAbstractScrollArea", - "QScrollArea", - "QCalendarWidget", - "QDockWidget", - "QDesktopScreenWidget", - "QWindowContainer" - ] -} diff --git a/src/plugins/accessible/widgets/widgets.pro b/src/plugins/accessible/widgets/widgets.pro deleted file mode 100644 index c6af6d3f71..0000000000 --- a/src/plugins/accessible/widgets/widgets.pro +++ /dev/null @@ -1,27 +0,0 @@ -TARGET = qtaccessiblewidgets - -PLUGIN_TYPE = accessible -PLUGIN_EXTENDS = widgets -PLUGIN_CLASS_NAME = AccessibleFactory -load(qt_plugin) - -QT += core-private gui-private widgets-private - -QTDIR_build:REQUIRES += "contains(QT_CONFIG, accessibility)" - -SOURCES += main.cpp \ - simplewidgets.cpp \ - rangecontrols.cpp \ - complexwidgets.cpp \ - qaccessiblewidgets.cpp \ - qaccessiblemenu.cpp \ - itemviews.cpp - -HEADERS += qaccessiblewidgets.h \ - simplewidgets.h \ - rangecontrols.h \ - complexwidgets.h \ - qaccessiblemenu.h \ - itemviews.h - - diff --git a/src/plugins/bearer/android/android.pro b/src/plugins/bearer/android/android.pro new file mode 100644 index 0000000000..6a51abf5d7 --- /dev/null +++ b/src/plugins/bearer/android/android.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs + +SUBDIRS += src \ + jar diff --git a/src/plugins/bearer/android/jar/bundledjar.pro b/src/plugins/bearer/android/jar/bundledjar.pro new file mode 100644 index 0000000000..6037f813f2 --- /dev/null +++ b/src/plugins/bearer/android/jar/bundledjar.pro @@ -0,0 +1,3 @@ +TARGET = QtAndroidBearer-bundled +CONFIG += bundled_jar_file +include(jar.pri) diff --git a/src/plugins/bearer/android/jar/distributedjar.pro b/src/plugins/bearer/android/jar/distributedjar.pro new file mode 100644 index 0000000000..c769a113d5 --- /dev/null +++ b/src/plugins/bearer/android/jar/distributedjar.pro @@ -0,0 +1,2 @@ +TARGET = QtAndroidBearer +include(jar.pri) diff --git a/src/plugins/bearer/android/jar/jar.pri b/src/plugins/bearer/android/jar/jar.pri new file mode 100644 index 0000000000..6d9aac3bb3 --- /dev/null +++ b/src/plugins/bearer/android/jar/jar.pri @@ -0,0 +1,13 @@ +load(qt_build_paths) +CONFIG += java +DESTDIR = $$MODULE_BASE_OUTDIR/jar + +JAVACLASSPATH += $$PWD/src + +JAVASOURCES += $$PWD/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java + +# install +target.path = $$[QT_INSTALL_PREFIX]/jar +INSTALLS += target + +OTHER_FILES += $$JAVASOURCES diff --git a/src/plugins/bearer/android/jar/jar.pro b/src/plugins/bearer/android/jar/jar.pro new file mode 100644 index 0000000000..923e757d9b --- /dev/null +++ b/src/plugins/bearer/android/jar/jar.pro @@ -0,0 +1,2 @@ +TEMPLATE=subdirs +SUBDIRS += distributedjar.pro bundledjar.pro diff --git a/src/plugins/bearer/android/jar/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java b/src/plugins/bearer/android/jar/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java new file mode 100644 index 0000000000..df0a37edc0 --- /dev/null +++ b/src/plugins/bearer/android/jar/src/org/qtproject/qt5/android/bearer/QtNetworkReceiver.java @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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$ +** +****************************************************************************/ + +package org.qtproject.qt5.android.bearer; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.util.Log; +import android.app.Activity; +import android.net.ConnectivityManager; + +public class QtNetworkReceiver +{ + private static final String LOG_TAG = "QtNetworkReceiver"; + private static native void activeNetworkInfoChanged(); + private static BroadcastReceiverPrivate m_broadcastReceiver = null; + private static final Object m_lock = new Object(); + + private static class BroadcastReceiverPrivate extends BroadcastReceiver + { + @Override + public void onReceive(Context context, Intent intent) + { + activeNetworkInfoChanged(); + } + } + + private QtNetworkReceiver() {} + + public static void registerReceiver(final Activity activity) + { + synchronized (m_lock) { + if (m_broadcastReceiver == null) { + m_broadcastReceiver = new BroadcastReceiverPrivate(); + IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); + activity.registerReceiver(m_broadcastReceiver, intentFilter); + } + } + } + + public static void unregisterReceiver(final Activity activity) + { + synchronized (m_lock) { + if (m_broadcastReceiver == null) + return; + + activity.unregisterReceiver(m_broadcastReceiver); + } + } + + public static ConnectivityManager getConnectivityManager(final Activity activity) + { + return (ConnectivityManager)activity.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); + } +} diff --git a/src/plugins/bearer/android/src/android.json b/src/plugins/bearer/android/src/android.json new file mode 100644 index 0000000000..6843bd3301 --- /dev/null +++ b/src/plugins/bearer/android/src/android.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "android" ] +} diff --git a/src/plugins/platforms/winrt/qwinrtplatformtheme.cpp b/src/plugins/bearer/android/src/main.cpp index d4034ec571..9880b94b0c 100644 --- a/src/plugins/platforms/winrt/qwinrtplatformtheme.cpp +++ b/src/plugins/bearer/android/src/main.cpp @@ -39,38 +39,27 @@ ** ****************************************************************************/ -#include "qwinrtplatformtheme.h" -#include "qwinrtplatformmessagedialoghelper.h" +#include "qandroidbearerengine.h" +#include <QtNetwork/private/qbearerplugin_p.h> -QT_BEGIN_NAMESPACE +#ifndef QT_NO_BEARERMANAGEMENT -QWinRTPlatformTheme::QWinRTPlatformTheme() -{ -} +QT_BEGIN_NAMESPACE -bool QWinRTPlatformTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const +class QAndroidBearerEnginePlugin : public QBearerEnginePlugin { -#if !(defined(Q_OS_WINPHONE) && _MSC_VER<=1700) - if (type == QPlatformTheme::MessageDialog) - return true; -#else - Q_UNUSED(type) -#endif // !(Q_OS_WINPHONE && _MSC_VER<=1700) - return false; -} + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QBearerEngineFactoryInterface" FILE "android.json") -QPlatformDialogHelper *QWinRTPlatformTheme::createPlatformDialogHelper(QPlatformTheme::DialogType type) const -{ -#if !(defined(Q_OS_WINPHONE) && _MSC_VER<=1700) - switch (type) { - case QPlatformTheme::MessageDialog: - return new QWinRTPlatformMessageDialogHelper(); - default: - return QPlatformTheme::createPlatformDialogHelper(type); +public: + QBearerEngine *create(const QString &key) const Q_DECL_OVERRIDE + { + return (key == QStringLiteral("android")) ? new QAndroidBearerEngine() : 0; } -#else // !(Q_OS_WINPHONE && _MSC_VER<=1700) - return QPlatformTheme::createPlatformDialogHelper(type); -#endif // Q_OS_WINPHONE && _MSC_VER<=1700 -} +}; QT_END_NAMESPACE + +#include "main.moc" + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/android/src/qandroidbearerengine.cpp b/src/plugins/bearer/android/src/qandroidbearerengine.cpp new file mode 100644 index 0000000000..38cd9c2de3 --- /dev/null +++ b/src/plugins/bearer/android/src/qandroidbearerengine.cpp @@ -0,0 +1,405 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 "qandroidbearerengine.h" +#include "../../qnetworksession_impl.h" +#include "wrappers/androidconnectivitymanager.h" + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +static QString networkConfType(const AndroidNetworkInfo &networkInfo) +{ + switch (networkInfo.getType()) { + case AndroidNetworkInfo::Mobile: + return QStringLiteral("Mobile"); + case AndroidNetworkInfo::Wifi: + return QStringLiteral("WiFi"); + case AndroidNetworkInfo::Wimax: + return QStringLiteral("WiMax"); + case AndroidNetworkInfo::Ethernet: + return QStringLiteral("Ethernet"); + case AndroidNetworkInfo::Bluetooth: + return QStringLiteral("Bluetooth"); + default: + break; + } + + return QString(); +} + +static inline bool isMobile(QNetworkConfiguration::BearerType type) +{ + if (type == QNetworkConfiguration::BearerWLAN + || type == QNetworkConfiguration::BearerWiMAX + || type == QNetworkConfiguration::BearerBluetooth + || type == QNetworkConfiguration::BearerEthernet + || type == QNetworkConfiguration::BearerUnknown) { + return false; + } + + return true; +} + +static QNetworkConfiguration::BearerType getBearerType(const AndroidNetworkInfo &networkInfo) +{ + switch (networkInfo.getType()) { + case AndroidNetworkInfo::Mobile: + { + switch (networkInfo.getSubtype()) { + case AndroidNetworkInfo::Gprs: + case AndroidNetworkInfo::Edge: + case AndroidNetworkInfo::Iden: // 2G + return QNetworkConfiguration::Bearer2G; + case AndroidNetworkInfo::Umts: // BearerWCDMA (3 .5 .75 G) + case AndroidNetworkInfo::Hsdpa: // 3G (?) UMTS + case AndroidNetworkInfo::Hsupa: // 3G (?) UMTS + return QNetworkConfiguration::BearerWCDMA; + case AndroidNetworkInfo::Cdma: // CDMA ISA95[AB] + case AndroidNetworkInfo::Cdma1xRTT: // BearerCDMA2000 (3G) + case AndroidNetworkInfo::Ehrpd: // CDMA Bridge thing?!? + return QNetworkConfiguration::BearerCDMA2000; + case AndroidNetworkInfo::Evdo0: // BearerEVDO + case AndroidNetworkInfo::EvdoA: // BearerEVDO + case AndroidNetworkInfo::EvdoB: // BearerEVDO + return QNetworkConfiguration::BearerEVDO; + case AndroidNetworkInfo::Hspa: + case AndroidNetworkInfo::Hspap: // HSPA+ + return QNetworkConfiguration::BearerHSPA; + case AndroidNetworkInfo::Lte: // BearerLTE (4G) + return QNetworkConfiguration::BearerLTE; + default: + break; + } + } + case AndroidNetworkInfo::Wifi: + return QNetworkConfiguration::BearerWLAN; + case AndroidNetworkInfo::Wimax: + return QNetworkConfiguration::BearerWiMAX; + case AndroidNetworkInfo::Bluetooth: + case AndroidNetworkInfo::MobileDun: + return QNetworkConfiguration::BearerBluetooth; + case AndroidNetworkInfo::Ethernet: + return QNetworkConfiguration::BearerEthernet; + case AndroidNetworkInfo::MobileMms: + case AndroidNetworkInfo::MobileSupl: + case AndroidNetworkInfo::MobileHipri: + case AndroidNetworkInfo::Dummy: + case AndroidNetworkInfo::UnknownType: + break; + } + + return QNetworkConfiguration::BearerUnknown; +} + +QAndroidBearerEngine::QAndroidBearerEngine(QObject *parent) + : QBearerEngineImpl(parent), + m_connectivityManager(0) +{ +} + +QAndroidBearerEngine::~QAndroidBearerEngine() +{ +} + +QString QAndroidBearerEngine::getInterfaceFromId(const QString &id) +{ + const QMutexLocker locker(&mutex); + return m_configurationInterface.value(id); +} + +bool QAndroidBearerEngine::hasIdentifier(const QString &id) +{ + const QMutexLocker locker(&mutex); + return m_configurationInterface.contains(id); +} + +void QAndroidBearerEngine::connectToId(const QString &id) +{ + Q_EMIT connectionError(id, OperationNotSupported); +} + +void QAndroidBearerEngine::disconnectFromId(const QString &id) +{ + Q_EMIT connectionError(id, OperationNotSupported); +} + +QNetworkSession::State QAndroidBearerEngine::sessionStateForId(const QString &id) +{ + const QMutexLocker locker(&mutex); + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + if ((!ptr || !ptr->isValid) || m_connectivityManager == 0) + return QNetworkSession::Invalid; + + const QMutexLocker configLocker(&ptr->mutex); + // Don't re-order... + if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + return (m_connectivityManager->isActiveNetworkMetered() + || m_connectivityManager->getActiveNetworkInfo().isRoaming()) + ? QNetworkSession::Roaming + : QNetworkSession::Connected; + } else if ((ptr->state & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered) { + return QNetworkSession::Disconnected; + } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) { + return QNetworkSession::NotAvailable; + } else if ((ptr->state & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined) { + return QNetworkSession::NotAvailable; + } + + return QNetworkSession::Invalid; +} + +QNetworkConfigurationManager::Capabilities QAndroidBearerEngine::capabilities() const +{ + + return AndroidTrafficStats::isTrafficStatsSupported() + ? QNetworkConfigurationManager::ForcedRoaming + | QNetworkConfigurationManager::DataStatistics + : QNetworkConfigurationManager::ForcedRoaming; + +} + +QNetworkSessionPrivate *QAndroidBearerEngine::createSessionBackend() +{ + return new QNetworkSessionPrivateImpl(); +} + +QNetworkConfigurationPrivatePointer QAndroidBearerEngine::defaultConfiguration() +{ + return QNetworkConfigurationPrivatePointer(); +} + +bool QAndroidBearerEngine::requiresPolling() const +{ + return false; +} + +quint64 QAndroidBearerEngine::bytesWritten(const QString &id) +{ + QMutexLocker lock(&mutex); + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + if (!ptr || !ptr->isValid) + return 0; + + return isMobile(ptr->bearerType) + ? AndroidTrafficStats::getMobileTxBytes() + : AndroidTrafficStats::getTotalTxBytes() - AndroidTrafficStats::getMobileTxBytes(); +} + +quint64 QAndroidBearerEngine::bytesReceived(const QString &id) +{ + QMutexLocker lock(&mutex); + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + if (!ptr || !ptr->isValid) + return 0; + + return isMobile(ptr->bearerType) + ? AndroidTrafficStats::getMobileRxBytes() + : AndroidTrafficStats::getTotalRxBytes() - AndroidTrafficStats::getMobileRxBytes(); +} + +quint64 QAndroidBearerEngine::startTime(const QString &id) +{ + Q_UNUSED(id); + return Q_UINT64_C(0); +} + +void QAndroidBearerEngine::initialize() +{ + if (m_connectivityManager != 0) + return; + + m_connectivityManager = AndroidConnectivityManager::getInstance(); + if (m_connectivityManager == 0) + return; + + updateConfigurations(); + + connect(m_connectivityManager, &AndroidConnectivityManager::activeNetworkChanged, + this, &QAndroidBearerEngine::updateConfigurations); + +} + +void QAndroidBearerEngine::requestUpdate() +{ + updateConfigurations(); +} + +void QAndroidBearerEngine::updateConfigurations() +{ +#ifndef QT_NO_NETWORKINTERFACE + if (m_connectivityManager == 0) + return; + + { + QMutexLocker locker(&mutex); + QStringList oldKeys = accessPointConfigurations.keys(); + + // Create a configuration for each of the main types (WiFi, Mobile, Bluetooth, WiMax, Ethernet) + foreach (const AndroidNetworkInfo &netInfo, m_connectivityManager->getAllNetworkInfo()) { + + if (!netInfo.isValid()) + continue; + + const QString name = networkConfType(netInfo); + if (name.isEmpty()) + continue; + + QNetworkConfiguration::BearerType bearerType = getBearerType(netInfo); + + QNetworkConfiguration::StateFlag state; + QString interfaceName; + if (netInfo.isAvailable()) { + if (netInfo.isConnected()) { + state = QNetworkConfiguration::Active; + // Attempt to map an interface to this configuration + const QList<QNetworkInterface> &interfaces = QNetworkInterface::allInterfaces(); + foreach (const QNetworkInterface &interface, interfaces) { + // ignore loopback interface + if (!interface.isValid()) + continue; + + if (interface.flags() & QNetworkInterface::IsLoopBack) + continue; + // There is no way to get the interface from the NetworkInfo, so + // look for an active interface... + if (interface.flags() & QNetworkInterface::IsRunning + && !interface.addressEntries().isEmpty()) { + interfaceName = interface.humanReadableName(); + if (interfaceName.isEmpty()) + interfaceName = interface.name(); + } + } + } else if (netInfo.isConnectedOrConnecting()) { + state = QNetworkConfiguration::Undefined; + } else { + state = QNetworkConfiguration::Discovered; + } + } else { + state = QNetworkConfiguration::Defined; + } + + const uint identifier = qHash(QLatin1String("android:") + name); + const QString id = QString::number(identifier); + + oldKeys.removeAll(id); + if (accessPointConfigurations.contains(id)) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + bool changed = false; + { + const QMutexLocker confLocker(&ptr->mutex); + + if (!ptr->isValid) { + ptr->isValid = true; + changed = true; + } + + // Don't reset the bearer type to 'Unknown' + if (ptr->bearerType != QNetworkConfiguration::BearerUnknown + && ptr->bearerType != bearerType) { + ptr->bearerType = bearerType; + changed = true; + } + + if (ptr->name != name) { + ptr->name = name; + changed = true; + } + + if (ptr->id != id) { + ptr->id = id; + changed = true; + } + + if (ptr->state != state) { + ptr->state = state; + changed = true; + } + + QString &oldIfName = m_configurationInterface[id]; + if (oldIfName != interfaceName) { + oldIfName = interfaceName; + changed = true; + } + } // Unlock configuration + + if (changed) { + locker.unlock(); + Q_EMIT configurationChanged(ptr); + locker.relock(); + } + } else { + QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate); + ptr->name = name; + ptr->isValid = true; + ptr->id = id; + ptr->state = state; + ptr->type = QNetworkConfiguration::InternetAccessPoint; + ptr->bearerType = bearerType; + accessPointConfigurations.insert(id, ptr); + m_configurationInterface.insert(id, interfaceName); + + locker.unlock(); + Q_EMIT configurationAdded(ptr); + locker.relock(); + } + } + + while (!oldKeys.isEmpty()) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(oldKeys.takeFirst()); + m_configurationInterface.remove(ptr->id); + locker.unlock(); + Q_EMIT configurationRemoved(ptr); + locker.relock(); + } + + } // Unlock engine + +#endif // QT_NO_NETWORKINTERFACE + + Q_EMIT updateCompleted(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/android/src/qandroidbearerengine.h b/src/plugins/bearer/android/src/qandroidbearerengine.h new file mode 100644 index 0000000000..93e576e040 --- /dev/null +++ b/src/plugins/bearer/android/src/qandroidbearerengine.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 QANDROIDBEARERENGINE_H +#define QANDROIDBEARERENGINE_H + +#include "../../qbearerengine_impl.h" + +#include <QAbstractEventDispatcher> +#include <QAbstractNativeEventFilter> +#include <QtCore/private/qjni_p.h> + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +class QNetworkConfigurationPrivate; +class QNetworkSessionPrivate; +class AndroidConnectivityManager; + +class QAndroidBearerEngine : public QBearerEngineImpl +{ + Q_OBJECT + +public: + explicit QAndroidBearerEngine(QObject *parent = 0); + ~QAndroidBearerEngine() Q_DECL_OVERRIDE; + + QString getInterfaceFromId(const QString &id) Q_DECL_OVERRIDE; + bool hasIdentifier(const QString &id) Q_DECL_OVERRIDE; + void connectToId(const QString &id) Q_DECL_OVERRIDE; + void disconnectFromId(const QString &id) Q_DECL_OVERRIDE; + QNetworkSession::State sessionStateForId(const QString &id) Q_DECL_OVERRIDE; + QNetworkConfigurationManager::Capabilities capabilities() const Q_DECL_OVERRIDE; + QNetworkSessionPrivate *createSessionBackend() Q_DECL_OVERRIDE; + QNetworkConfigurationPrivatePointer defaultConfiguration() Q_DECL_OVERRIDE; + bool requiresPolling() const Q_DECL_OVERRIDE; + quint64 bytesWritten(const QString &id) Q_DECL_OVERRIDE; + quint64 bytesReceived(const QString &id) Q_DECL_OVERRIDE; + quint64 startTime(const QString &id) Q_DECL_OVERRIDE; + + Q_INVOKABLE void initialize(); + Q_INVOKABLE void requestUpdate(); + +private Q_SLOTS: + void updateConfigurations(); + +private: + QJNIObjectPrivate m_networkReceiver; + AndroidConnectivityManager *m_connectivityManager; + QMap<QString, QString> m_configurationInterface; +}; + + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT + +#endif // QANDROIDBEARERENGINE_H diff --git a/src/plugins/bearer/android/src/src.pro b/src/plugins/bearer/android/src/src.pro new file mode 100644 index 0000000000..1050601896 --- /dev/null +++ b/src/plugins/bearer/android/src/src.pro @@ -0,0 +1,17 @@ +include(wrappers/wrappers.pri) + +TARGET = qandroidbearer + +PLUGIN_TYPE = bearer +PLUGIN_CLASS_NAME = QAndroidBearerEnginePlugin +load(qt_plugin) + +QT = core-private network-private + +HEADERS += qandroidbearerengine.h \ + ../../qnetworksession_impl.h \ + ../../qbearerengine_impl.h + +SOURCES += main.cpp \ + qandroidbearerengine.cpp \ + ../../qnetworksession_impl.cpp diff --git a/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.cpp b/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.cpp new file mode 100644 index 0000000000..df2c3db0d6 --- /dev/null +++ b/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.cpp @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 "androidconnectivitymanager.h" +#include <QtCore/private/qjni_p.h> +#include <QtCore/private/qjnihelpers_p.h> + +QT_BEGIN_NAMESPACE + +static inline bool exceptionCheckAndClear(JNIEnv *env) +{ + if (!env->ExceptionCheck()) + return false; + +#ifdef QT_DEBUG + env->ExceptionDescribe(); +#endif // QT_DEBUG + env->ExceptionClear(); + + return true; +} + +struct AndroidConnectivityManagerInstance +{ + AndroidConnectivityManagerInstance() + : connManager(new AndroidConnectivityManager) + { } + ~AndroidConnectivityManagerInstance() + { + delete connManager; + } + + AndroidConnectivityManager* connManager; +}; + +Q_GLOBAL_STATIC(AndroidConnectivityManagerInstance, androidConnManagerInstance) + +static const char networkReceiverClass[] = "org/qtproject/qt5/android/bearer/QtNetworkReceiver"; +static const char trafficStatsClass[] = "android/net/TrafficStats"; + +/** + * Returns the number of bytes transmitted over the mobile network since last device boot. + */ +qint64 AndroidTrafficStats::getMobileTxBytes() +{ + return QJNIObjectPrivate::callStaticMethod<jlong>(trafficStatsClass, + "getMobileTxBytes", + "()J"); +} + +/** + * Returns the number of bytes received over the mobile network since last device boot. + */ +qint64 AndroidTrafficStats::getMobileRxBytes() +{ + return QJNIObjectPrivate::callStaticMethod<jlong>(trafficStatsClass, + "getMobileRxBytes", + "()J"); +} + +/** + * Returns the total transmitted bytes since last device boot. + */ +qint64 AndroidTrafficStats::getTotalTxBytes() +{ + return QJNIObjectPrivate::callStaticMethod<jlong>(trafficStatsClass, + "getTotalTxBytes", + "()J"); +} + +/** + * Returns the total received bytes since last device boot. + */ +qint64 AndroidTrafficStats::getTotalRxBytes() +{ + return QJNIObjectPrivate::callStaticMethod<jlong>(trafficStatsClass, + "getTotalRxBytes", + "()J"); +} + +bool AndroidTrafficStats::isTrafficStatsSupported() +{ + // Before API level 18 DataStatistics might not be supported, so make sure that we get something + // else then -1 from from getXXBytes(). + return (AndroidTrafficStats::getMobileRxBytes() != -1 + && AndroidTrafficStats::getTotalRxBytes() != -1); +} + +static AndroidNetworkInfo::NetworkState stateForName(const QString stateName) +{ + if (stateName == QLatin1String("CONNECTED")) + return AndroidNetworkInfo::Connected; + else if (stateName == QLatin1String("CONNECTING")) + return AndroidNetworkInfo::Connecting; + else if (stateName == QLatin1String("DISCONNECTED")) + return AndroidNetworkInfo::Disconnected; + else if (stateName == QLatin1String("DISCONNECTING")) + return AndroidNetworkInfo::Disconnecting; + else if (stateName == QLatin1String("SUSPENDED")) + return AndroidNetworkInfo::Suspended; + + return AndroidNetworkInfo::UnknownState; +} + +AndroidNetworkInfo::NetworkState AndroidNetworkInfo::getDetailedState() const +{ + QJNIObjectPrivate enumObject = m_networkInfo.callObjectMethod("getDetailedState", + "()Landroid/net/NetworkInfo$DetailedState;"); + if (!enumObject.isValid()) + return UnknownState; + + QJNIObjectPrivate enumName = enumObject.callObjectMethod<jstring>("name"); + if (!enumName.isValid()) + return UnknownState; + + return stateForName(enumName.toString()); +} + +QString AndroidNetworkInfo::getExtraInfo() const +{ + QJNIObjectPrivate extraInfo = m_networkInfo.callObjectMethod<jstring>("getExtraInfo"); + if (!extraInfo.isValid()) + return QString(); + + return extraInfo.toString(); +} + +QString AndroidNetworkInfo::getReason() const +{ + QJNIObjectPrivate reason = m_networkInfo.callObjectMethod<jstring>("getReason"); + if (!reason.isValid()) + return QString(); + + return reason.toString(); +} + +AndroidNetworkInfo::NetworkState AndroidNetworkInfo::getState() const +{ + QJNIObjectPrivate enumObject = m_networkInfo.callObjectMethod("getState", + "()Landroid/net/NetworkInfo$State;"); + if (!enumObject.isValid()) + return UnknownState; + + QJNIObjectPrivate enumName = enumObject.callObjectMethod<jstring>("name"); + if (!enumName.isValid()) + return UnknownState; + + return stateForName(enumName.toString()); +} + +AndroidNetworkInfo::NetworkSubType AndroidNetworkInfo::getSubtype() const +{ + return AndroidNetworkInfo::NetworkSubType(m_networkInfo.callMethod<jint>("getSubtype")); +} + +QString AndroidNetworkInfo::getSubtypeName() const +{ + QJNIObjectPrivate subtypeName = m_networkInfo.callObjectMethod<jstring>("getSubtypeName"); + if (!subtypeName.isValid()) + return QString(); + + return subtypeName.toString(); +} + +AndroidNetworkInfo::NetworkType AndroidNetworkInfo::getType() const +{ + return AndroidNetworkInfo::NetworkType(m_networkInfo.callMethod<jint>("getType")); +} + +QString AndroidNetworkInfo::getTypeName() const +{ + QJNIObjectPrivate typeName = m_networkInfo.callObjectMethod<jstring>("getTypeName"); + if (!typeName.isValid()) + return QString(); + + return typeName.toString(); +} + +bool AndroidNetworkInfo::isAvailable() const +{ + return m_networkInfo.callMethod<jboolean>("isAvailable"); +} + +bool AndroidNetworkInfo::isConnected() const +{ + return m_networkInfo.callMethod<jboolean>("isConnected"); +} + +bool AndroidNetworkInfo::isConnectedOrConnecting() const +{ + return m_networkInfo.callMethod<jboolean>("isConnectedOrConnecting"); +} + +bool AndroidNetworkInfo::isFailover() const +{ + return m_networkInfo.callMethod<jboolean>("isFailover"); +} + +bool AndroidNetworkInfo::isRoaming() const +{ + return m_networkInfo.callMethod<jboolean>("isRoaming"); +} + +bool AndroidNetworkInfo::isValid() const +{ + return m_networkInfo.isValid(); +} + +AndroidConnectivityManager::AndroidConnectivityManager() +{ + QJNIEnvironmentPrivate env; + if (!registerNatives(env)) + return; + + m_connectivityManager = QJNIObjectPrivate::callStaticObjectMethod(networkReceiverClass, + "getConnectivityManager", + "(Landroid/app/Activity;)Landroid/net/ConnectivityManager;", + QtAndroidPrivate::activity()); + if (!m_connectivityManager.isValid()) + return; + + QJNIObjectPrivate::callStaticMethod<void>(networkReceiverClass, + "registerReceiver", + "(Landroid/app/Activity;)V", + QtAndroidPrivate::activity()); +} + +AndroidConnectivityManager *AndroidConnectivityManager::getInstance() +{ + return androidConnManagerInstance->connManager->isValid() + ? androidConnManagerInstance->connManager + : 0; +} + +AndroidConnectivityManager::~AndroidConnectivityManager() +{ + QJNIObjectPrivate::callStaticMethod<void>(networkReceiverClass, + "unregisterReceiver", + "(Landroid/app/Activity;)V", + QtAndroidPrivate::activity()); +} + +AndroidNetworkInfo AndroidConnectivityManager::getActiveNetworkInfo() const +{ + QJNIObjectPrivate networkInfo = m_connectivityManager.callObjectMethod("getActiveNetworkInfo", + "()Landroid/net/NetworkInfo;"); + return networkInfo; +} + +QList<AndroidNetworkInfo> AndroidConnectivityManager::getAllNetworkInfo() const +{ + QJNIEnvironmentPrivate env; + QJNIObjectPrivate objArray = m_connectivityManager.callObjectMethod("getAllNetworkInfo", + "()[Landroid/net/NetworkInfo;"); + QList<AndroidNetworkInfo> list; + if (!objArray.isValid()) + return list; + + const jsize length = env->GetArrayLength(static_cast<jarray>(objArray.object())); + if (exceptionCheckAndClear(env)) + return list; + + for (int i = 0; i != length; ++i) { + jobject lref = env->GetObjectArrayElement(static_cast<jobjectArray>(objArray.object()), i); + if (exceptionCheckAndClear(env)) + break; + + list << AndroidNetworkInfo(lref); + env->DeleteLocalRef(lref); + } + + return list; +} + +bool AndroidConnectivityManager::getBackgroundDataSetting() const +{ + return m_connectivityManager.callMethod<jboolean>("getBackgroundDataSetting"); +} + +AndroidNetworkInfo AndroidConnectivityManager::getNetworkInfo(int networkType) const +{ + QJNIObjectPrivate networkInfo = m_connectivityManager.callObjectMethod("getNetworkInfo", + "(I)Landroid/net/NetworkInfo;", + networkType); + return networkInfo; +} + +int AndroidConnectivityManager::getNetworkPreference() const +{ + return m_connectivityManager.callMethod<jint>("getNetworkPreference"); +} + +bool AndroidConnectivityManager::isActiveNetworkMetered() const +{ + // This function was added in JB + if (QtAndroidPrivate::androidSdkVersion() < 16) + return false; + + return m_connectivityManager.callMethod<jboolean>("isActiveNetworkMetered"); +} + +bool AndroidConnectivityManager::isNetworkTypeValid(int networkType) +{ + return QJNIObjectPrivate::callStaticMethod<jboolean>("android/net/ConnectivityManager", + "isNetworkTypeValid", + "(I)Z", + networkType); +} + +bool AndroidConnectivityManager::requestRouteToHost(int networkType, int hostAddress) +{ + return m_connectivityManager.callMethod<jboolean>("requestRouteToHost", "(II)Z", networkType, hostAddress); +} + +void AndroidConnectivityManager::setNetworkPreference(int preference) +{ + m_connectivityManager.callMethod<void>("setNetworkPreference", "(I)V", preference); +} + +int AndroidConnectivityManager::startUsingNetworkFeature(int networkType, const QString &feature) +{ + QJNIObjectPrivate jfeature = QJNIObjectPrivate::fromString(feature); + return m_connectivityManager.callMethod<jint>("startUsingNetworkFeature", + "(ILjava/lang/String;)I", + networkType, + jfeature.object()); +} + +int AndroidConnectivityManager::stopUsingNetworkFeature(int networkType, const QString &feature) +{ + QJNIObjectPrivate jfeature = QJNIObjectPrivate::fromString(feature); + return m_connectivityManager.callMethod<jint>("stopUsingNetworkFeature", + "(ILjava/lang/String;)I", + networkType, + jfeature.object()); +} + +static void activeNetworkInfoChanged() +{ + Q_EMIT androidConnManagerInstance->connManager->activeNetworkChanged(); +} + +bool AndroidConnectivityManager::registerNatives(JNIEnv *env) +{ + QJNIObjectPrivate networkReceiver(networkReceiverClass); + if (!networkReceiver.isValid()) + return false; + + jclass clazz = env->GetObjectClass(networkReceiver.object()); + static JNINativeMethod method = {"activeNetworkInfoChanged", "()V", reinterpret_cast<void *>(activeNetworkInfoChanged)}; + const bool ret = (env->RegisterNatives(clazz, &method, 1) == JNI_OK); + env->DeleteLocalRef(clazz); + return ret; +} + +QT_END_NAMESPACE diff --git a/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.h b/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.h new file mode 100644 index 0000000000..de7e5151fa --- /dev/null +++ b/src/plugins/bearer/android/src/wrappers/androidconnectivitymanager.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 ANDROIDCONNECTIVITYMANAGER_H +#define ANDROIDCONNECTIVITYMANAGER_H + +#include <QObject> +#include <QtCore/private/qjni_p.h> + +QT_BEGIN_NAMESPACE + +class AndroidTrafficStats +{ +public: + static qint64 getMobileTxBytes(); + static qint64 getMobileRxBytes(); + static qint64 getTotalTxBytes(); + static qint64 getTotalRxBytes(); + static bool isTrafficStatsSupported(); +}; + +class AndroidNetworkInfo +{ +public: + // Needs to be in sync with the values from the android api. + enum NetworkState { + UnknownState, + Authenticating, + Blocked, + CaptivePortalCheck, + Connected, + Connecting, + Disconnected, + Disconnecting, + Failed, + Idle, + ObtainingIpAddr, + Scanning, + Suspended, + VerifyingPoorLink + }; + + enum NetworkType { + Mobile, + Wifi, + MobileMms, + MobileSupl, + MobileDun, + MobileHipri, + Wimax, + Bluetooth, + Dummy, + Ethernet, + UnknownType + }; + + enum NetworkSubType { + UnknownSubType, + Gprs, + Edge, + Umts, + Cdma, + Evdo0, + EvdoA, + Cdma1xRTT, + Hsdpa, + Hsupa, + Hspa, + Iden, + EvdoB, + Lte, + Ehrpd, + Hspap + }; + + inline AndroidNetworkInfo(const QJNIObjectPrivate &obj) : m_networkInfo(obj) + { } + + NetworkState getDetailedState() const; + QString getExtraInfo() const; + QString getReason() const; + NetworkState getState() const; + NetworkSubType getSubtype() const; + QString getSubtypeName() const; + NetworkType getType() const; + QString getTypeName() const; + bool isAvailable() const; + bool isConnected() const; + bool isConnectedOrConnecting() const; + bool isFailover() const; + bool isRoaming() const; + bool isValid() const; + +private: + QJNIObjectPrivate m_networkInfo; +}; + +class AndroidConnectivityManager : public QObject +{ + Q_OBJECT +public: + static AndroidConnectivityManager *getInstance(); + ~AndroidConnectivityManager(); + + AndroidNetworkInfo getActiveNetworkInfo() const; + QList<AndroidNetworkInfo> getAllNetworkInfo() const; + bool getBackgroundDataSetting() const; + AndroidNetworkInfo getNetworkInfo(int networkType) const; + int getNetworkPreference() const; + bool isActiveNetworkMetered() const; + static bool isNetworkTypeValid(int networkType); + bool requestRouteToHost(int networkType, int hostAddress); + void setNetworkPreference(int preference); + int startUsingNetworkFeature(int networkType, const QString &feature); + int stopUsingNetworkFeature(int networkType, const QString &feature); + inline bool isValid() const + { + return m_connectivityManager.isValid(); + } + + Q_SIGNAL void activeNetworkChanged(); + +private: + friend struct AndroidConnectivityManagerInstance; + AndroidConnectivityManager(); + bool registerNatives(JNIEnv *env); + QJNIObjectPrivate m_connectivityManager; +}; + +QT_END_NAMESPACE + +#endif // ANDROIDCONNECTIVITYMANAGER_H diff --git a/src/plugins/bearer/android/src/wrappers/wrappers.pri b/src/plugins/bearer/android/src/wrappers/wrappers.pri new file mode 100644 index 0000000000..209b76e533 --- /dev/null +++ b/src/plugins/bearer/android/src/wrappers/wrappers.pri @@ -0,0 +1,6 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/androidconnectivitymanager.h +SOURCES += \ + $$PWD/androidconnectivitymanager.cpp diff --git a/src/plugins/bearer/bearer.pro b/src/plugins/bearer/bearer.pro index 42f039b19b..e52df24857 100644 --- a/src/plugins/bearer/bearer.pro +++ b/src/plugins/bearer/bearer.pro @@ -11,5 +11,6 @@ blackberry:SUBDIRS += blackberry win32:!wince*:SUBDIRS += nativewifi mac:contains(QT_CONFIG, corewlan):SUBDIRS += corewlan mac:SUBDIRS += generic +android:!android-no-sdk:SUBDIRS += android isEmpty(SUBDIRS):SUBDIRS = generic diff --git a/src/plugins/bearer/connman/qconnmanengine.cpp b/src/plugins/bearer/connman/qconnmanengine.cpp index 797c30c7c6..adefb7504e 100644 --- a/src/plugins/bearer/connman/qconnmanengine.cpp +++ b/src/plugins/bearer/connman/qconnmanengine.cpp @@ -186,10 +186,23 @@ void QConnmanEngine::connectToId(const QString &id) QConnmanServiceInterface *serv = connmanServiceInterfaces.value(id); - if (!serv->isValid()) { + if (!serv || !serv->isValid()) { emit connectionError(id, QBearerEngineImpl::InterfaceLookupError); } else { - serv->connect(); + if (serv->type() == QLatin1String("cellular")) { + if (serv->roaming()) { + if (!isRoamingAllowed(serv->path())) { + emit connectionError(id, QBearerEngineImpl::OperationNotSupported); + return; + } + if (isAlwaysAskRoaming()) { + emit connectionError(id, QBearerEngineImpl::OperationNotSupported); + return; + } + } + } + if (serv->autoConnect()) + serv->connect(); } } @@ -198,7 +211,7 @@ void QConnmanEngine::disconnectFromId(const QString &id) QMutexLocker locker(&mutex); QConnmanServiceInterface *serv = connmanServiceInterfaces.value(id); - if (!serv->isValid()) { + if (!serv || !serv->isValid()) { emit connectionError(id, DisconnectionError); } else { serv->disconnect(); @@ -250,6 +263,8 @@ QNetworkSession::State QConnmanEngine::sessionStateForId(const QString &id) QString service = id; QConnmanServiceInterface *serv = connmanServiceInterfaces.value(service); + if (!serv) + return QNetworkSession::Invalid; QString servState = serv->state(); @@ -355,6 +370,8 @@ void QConnmanEngine::serviceStateChanged(const QString &state) void QConnmanEngine::configurationChange(QConnmanServiceInterface *serv) { + if (!serv) + return; QMutexLocker locker(&mutex); QString id = serv->path(); @@ -396,8 +413,10 @@ QNetworkConfiguration::StateFlags QConnmanEngine::getStateForService(const QStri { QMutexLocker locker(&mutex); QConnmanServiceInterface *serv = connmanServiceInterfaces.value(service); - QString state = serv->state(); + if (!serv) + return QNetworkConfiguration::Undefined; + QString state = serv->state(); QNetworkConfiguration::StateFlags flag = QNetworkConfiguration::Defined; if (serv->type() == QLatin1String("cellular")) { @@ -494,7 +513,7 @@ void QConnmanEngine::addServiceConfiguration(const QString &servicePath) { QMutexLocker locker(&mutex); if (!connmanServiceInterfaces.contains(servicePath)) { - QConnmanServiceInterface *serv = new QConnmanServiceInterface(servicePath); + QConnmanServiceInterface *serv = new QConnmanServiceInterface(servicePath, this); connmanServiceInterfaces.insert(serv->path(),serv); } diff --git a/src/plugins/imageformats/ico/ico.json b/src/plugins/imageformats/ico/ico.json index bd46e07e54..14093ee471 100644 --- a/src/plugins/imageformats/ico/ico.json +++ b/src/plugins/imageformats/ico/ico.json @@ -1,4 +1,4 @@ { - "Keys": [ "ico" ], + "Keys": [ "ico", "cur" ], "MimeTypes": [ "image/vnd.microsoft.icon" ] } diff --git a/src/plugins/imageformats/ico/main.cpp b/src/plugins/imageformats/ico/main.cpp index 05e6e1885c..2ff2f36fdc 100644 --- a/src/plugins/imageformats/ico/main.cpp +++ b/src/plugins/imageformats/ico/main.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE QImageIOPlugin::Capabilities QICOPlugin::capabilities(QIODevice *device, const QByteArray &format) const { - if (format == "ico") + if (format == "ico" || format == "cur") return Capabilities(CanRead | CanWrite); if (!format.isEmpty()) return 0; diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp index 505d6cc42b..f013692809 100644 --- a/src/plugins/imageformats/ico/qicohandler.cpp +++ b/src/plugins/imageformats/ico/qicohandler.cpp @@ -75,7 +75,7 @@ typedef struct typedef struct { quint16 idReserved; // Reserved - quint16 idType; // resource type (1 for icons) + quint16 idType; // resource type (1 for icons, 2 for cursors) quint16 idCount; // how many images? ICONDIRENTRY idEntries[1]; // the entries for each image } ICONDIR, *LPICONDIR; @@ -275,10 +275,10 @@ bool ICOReader::canRead(QIODevice *iodev) readBytes += ICONDIRENTRY_SIZE; // ICO format does not have a magic identifier, so we read 6 different values, which will hopefully be enough to identify the file. if ( ikonDir.idReserved == 0 - && ikonDir.idType == 1 + && (ikonDir.idType == 1 || ikonDir.idType == 2) && ikonDir.idEntries[0].bReserved == 0 - && ikonDir.idEntries[0].wPlanes <= 1 - && ikonDir.idEntries[0].wBitCount <= 32 // Bits per pixel + && (ikonDir.idEntries[0].wPlanes <= 1 || ikonDir.idType == 2) + && (ikonDir.idEntries[0].wBitCount <= 32 || ikonDir.idType == 2) // Bits per pixel && ikonDir.idEntries[0].dwBytesInRes >= 40 // Must be over 40, since sizeof (infoheader) == 40 ) { isProbablyICO = true; @@ -339,7 +339,7 @@ bool ICOReader::readHeader() if (iod && !headerRead) { startpos = iod->pos(); if (readIconDir(iod, &iconDir)) { - if (iconDir.idReserved == 0 || iconDir.idType == 1) + if (iconDir.idReserved == 0 && (iconDir.idType == 1 || iconDir.idType == 2)) headerRead = true; } } diff --git a/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml b/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml index dbc79c178b..9c67a38c57 100644 --- a/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml +++ b/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml @@ -35,6 +35,11 @@ <method name="GetEngine"> <arg name="desc" direction="out" type="v"/> </method> + <method name="SetSurroundingText"> + <arg name="text" direction="in" type="v"/> + <arg name="cursor_pos" direction="in" type="u"/> + <arg name="anchor_pos" direction="in" type="u"/> + </method> <method name="Destroy"/> <signal name="CommitText"> <arg name="text" type="v"/> @@ -75,6 +80,11 @@ <signal name="UpdateProperty"> <arg name="prop" type="v"/> </signal> + <signal name="RequireSurroundingText"/> + <signal name="DeleteSurroundingText"> + <arg name="offset" type="i"/> + <arg name="n_chars" type="u"/> + </signal> </interface> </node> diff --git a/src/plugins/platforminputcontexts/ibus/main.cpp b/src/plugins/platforminputcontexts/ibus/main.cpp index d7c34ee9b3..e33c328b9e 100644 --- a/src/plugins/platforminputcontexts/ibus/main.cpp +++ b/src/plugins/platforminputcontexts/ibus/main.cpp @@ -41,7 +41,9 @@ #include <qpa/qplatforminputcontextplugin_p.h> #include <QtCore/QStringList> +#include <QDBusMetaType> #include "qibusplatforminputcontext.h" +#include "qibustypes.h" QT_BEGIN_NAMESPACE @@ -58,8 +60,13 @@ QIBusPlatformInputContext *QIbusPlatformInputContextPlugin::create(const QString { Q_UNUSED(paramList); - if (system.compare(system, QStringLiteral("ibus"), Qt::CaseInsensitive) == 0) + if (system.compare(system, QStringLiteral("ibus"), Qt::CaseInsensitive) == 0) { + qDBusRegisterMetaType<QIBusSerializable>(); + qDBusRegisterMetaType<QIBusAttribute>(); + qDBusRegisterMetaType<QIBusAttributeList>(); + qDBusRegisterMetaType<QIBusText>(); return new QIBusPlatformInputContext; + } return 0; } diff --git a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp index 8df88b339b..454a1e6fda 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp @@ -1,5 +1,5 @@ /* - * This file was generated by qdbusxml2cpp version 0.7 + * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp -N -p qibusinputcontextproxy -c QIBusInputContextProxy interfaces/org.freedesktop.IBus.InputContext.xml * * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). diff --git a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h index b1e33a3ecd..b75a5e0a93 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h +++ b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h @@ -1,5 +1,5 @@ /* - * This file was generated by qdbusxml2cpp version 0.7 + * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp -N -p qibusinputcontextproxy -c QIBusInputContextProxy interfaces/org.freedesktop.IBus.InputContext.xml * * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). @@ -8,8 +8,8 @@ * Do not edit! All changes made to it will be lost. */ -#ifndef QIBUSINPUTCONTEXTPROXY_H_1308831153 -#define QIBUSINPUTCONTEXTPROXY_H_1308831153 +#ifndef QIBUSINPUTCONTEXTPROXY_H_1394889529 +#define QIBUSINPUTCONTEXTPROXY_H_1394889529 #include <QtCore/QObject> #include <QtCore/QByteArray> @@ -119,10 +119,18 @@ public Q_SLOTS: // METHODS return asyncCallWithArgumentList(QLatin1String("SetEngine"), argumentList); } + inline QDBusPendingReply<> SetSurroundingText(const QDBusVariant &text, uint cursor_pos, uint anchor_pos) + { + QList<QVariant> argumentList; + argumentList << QVariant::fromValue(text) << QVariant::fromValue(cursor_pos) << QVariant::fromValue(anchor_pos); + return asyncCallWithArgumentList(QLatin1String("SetSurroundingText"), argumentList); + } + Q_SIGNALS: // SIGNALS void CommitText(const QDBusVariant &text); void CursorDownLookupTable(); void CursorUpLookupTable(); + void DeleteSurroundingText(int offset, uint n_chars); void Disabled(); void Enabled(); void ForwardKeyEvent(uint keyval, uint keycode, uint state); @@ -132,6 +140,7 @@ Q_SIGNALS: // SIGNALS void PageDownLookupTable(); void PageUpLookupTable(); void RegisterProperties(const QDBusVariant &props); + void RequireSurroundingText(); void ShowAuxiliaryText(); void ShowLookupTable(); void ShowPreeditText(); diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index 53e9b171d5..be90bbecb0 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -43,6 +43,7 @@ #include <QtDebug> #include <QTextCharFormat> #include <QGuiApplication> +#include <QDBusVariant> #include <qwindow.h> #include <qevent.h> @@ -78,6 +79,7 @@ public: bool valid; QString predit; + bool needsSurroundingText; }; @@ -87,6 +89,8 @@ QIBusPlatformInputContext::QIBusPlatformInputContext () if (d->context) { connect(d->context, SIGNAL(CommitText(QDBusVariant)), SLOT(commitText(QDBusVariant))); connect(d->context, SIGNAL(UpdatePreeditText(QDBusVariant,uint,bool)), this, SLOT(updatePreeditText(QDBusVariant,uint,bool))); + connect(d->context, SIGNAL(DeleteSurroundingText(int,uint)), this, SLOT(deleteSurroundingText(int,uint))); + connect(d->context, SIGNAL(RequireSurroundingText()), this, SLOT(surroundingTextRequired())); } QInputMethod *p = qApp->inputMethod(); connect(p, SIGNAL(cursorRectangleChanged()), this, SLOT(cursorRectChanged())); @@ -146,6 +150,33 @@ void QIBusPlatformInputContext::commit() void QIBusPlatformInputContext::update(Qt::InputMethodQueries q) { + QObject *input = qApp->focusObject(); + + if (d->needsSurroundingText && input + && (q.testFlag(Qt::ImSurroundingText) + || q.testFlag(Qt::ImCursorPosition) + || q.testFlag(Qt::ImAnchorPosition))) { + QInputMethodQueryEvent srrndTextQuery(Qt::ImSurroundingText); + QInputMethodQueryEvent cursorPosQuery(Qt::ImCursorPosition); + QInputMethodQueryEvent anchorPosQuery(Qt::ImAnchorPosition); + + QCoreApplication::sendEvent(input, &srrndTextQuery); + QCoreApplication::sendEvent(input, &cursorPosQuery); + QCoreApplication::sendEvent(input, &anchorPosQuery); + + QString surroundingText = srrndTextQuery.value(Qt::ImSurroundingText).toString(); + uint cursorPosition = cursorPosQuery.value(Qt::ImCursorPosition).toUInt(); + uint anchorPosition = anchorPosQuery.value(Qt::ImAnchorPosition).toUInt(); + + QIBusText text; + text.text = surroundingText; + + QVariant variant; + variant.setValue(text); + QDBusVariant dbusText(variant); + + d->context->SetSurroundingText(dbusText, cursorPosition, anchorPosition); + } QPlatformInputContext::update(q); } @@ -191,7 +222,7 @@ void QIBusPlatformInputContext::commitText(const QDBusVariant &text) QIBusText t; if (debug) qDebug() << arg.currentSignature(); - t.fromDBusArgument(arg); + arg >> t; if (debug) qDebug() << "commit text:" << t.text; @@ -211,7 +242,7 @@ void QIBusPlatformInputContext::updatePreeditText(const QDBusVariant &text, uint const QDBusArgument arg = text.variant().value<QDBusArgument>(); QIBusText t; - t.fromDBusArgument(arg); + arg >> t; if (debug) qDebug() << "preedit text:" << t.text; @@ -225,6 +256,27 @@ void QIBusPlatformInputContext::updatePreeditText(const QDBusVariant &text, uint d->predit = t.text; } +void QIBusPlatformInputContext::surroundingTextRequired() +{ + if (debug) + qDebug() << "surroundingTextRequired"; + d->needsSurroundingText = true; + update(Qt::ImSurroundingText); +} + +void QIBusPlatformInputContext::deleteSurroundingText(int offset, uint n_chars) +{ + QObject *input = qApp->focusObject(); + if (!input) + return; + + if (debug) + qDebug() << "deleteSurroundingText" << offset << n_chars; + + QInputMethodEvent event; + event.setCommitString("", offset, n_chars); + QCoreApplication::sendEvent(input, &event); +} bool QIBusPlatformInputContext::x11FilterEvent(uint keyval, uint keycode, uint state, bool press) @@ -250,7 +302,8 @@ QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate() : connection(createConnection()), bus(0), context(0), - valid(false) + valid(false), + needsSurroundingText(false) { if (!connection || !connection->isConnected()) return; @@ -284,7 +337,7 @@ QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate() IBUS_CAP_PROPERTY = 1 << 4, IBUS_CAP_SURROUNDING_TEXT = 1 << 5 }; - context->SetCapabilities(IBUS_CAP_PREEDIT_TEXT|IBUS_CAP_FOCUS); + context->SetCapabilities(IBUS_CAP_PREEDIT_TEXT|IBUS_CAP_FOCUS|IBUS_CAP_SURROUNDING_TEXT); if (debug) qDebug(">>>> valid!"); diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h index 400ef3914a..a9e9ac18f9 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h @@ -69,6 +69,8 @@ public Q_SLOTS: void commitText(const QDBusVariant &text); void updatePreeditText(const QDBusVariant &text, uint cursor_pos, bool visible); void cursorRectChanged(); + void deleteSurroundingText(int offset, uint n_chars); + void surroundingTextRequired(); private: QIBusPlatformInputContextPrivate *d; diff --git a/src/plugins/platforminputcontexts/ibus/qibustypes.cpp b/src/plugins/platforminputcontexts/ibus/qibustypes.cpp index 6ab0b1ae3e..5fa0c9ef67 100644 --- a/src/plugins/platforminputcontexts/ibus/qibustypes.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibustypes.cpp @@ -42,6 +42,7 @@ #include "qibustypes.h" #include <qtextformat.h> #include <QtDBus> +#include <QHash> QT_BEGIN_NAMESPACE @@ -53,23 +54,45 @@ QIBusSerializable::~QIBusSerializable() { } -void QIBusSerializable::fromDBusArgument(const QDBusArgument &arg) +const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusSerializable &object) { - arg >> name; - arg.beginMap(); - while (!arg.atEnd()) { - arg.beginMapEntry(); + argument >> object.name; + + argument.beginMap(); + while (!argument.atEnd()) { + argument.beginMapEntry(); QString key; QDBusVariant value; - arg >> key; - arg >> value; - arg.endMapEntry(); - attachments[key] = value.variant().value<QDBusArgument>(); + argument >> key; + argument >> value; + argument.endMapEntry(); + object.attachments[key] = value.variant().value<QDBusArgument>(); } - arg.endMap(); + argument.endMap(); + return argument; } +QDBusArgument &operator<<(QDBusArgument &argument, const QIBusSerializable &object) +{ + argument << object.name; + + argument.beginMap(qMetaTypeId<QString>(), qMetaTypeId<QDBusVariant>()); + + QHashIterator<QString, QDBusArgument> i(object.attachments); + while (i.hasNext()) { + i.next(); + argument.beginMapEntry(); + argument << i.key(); + + QDBusVariant variant(i.value().asVariant()); + + argument << variant; + argument.endMapEntry(); + } + argument.endMap(); + return argument; +} QIBusAttribute::QIBusAttribute() : type(Invalid), @@ -77,28 +100,46 @@ QIBusAttribute::QIBusAttribute() start(0), end(0) { + name = "IBusAttribute"; } QIBusAttribute::~QIBusAttribute() { +} + +QDBusArgument &operator<<(QDBusArgument &argument, const QIBusAttribute &attribute) +{ + argument.beginStructure(); + + argument << static_cast<const QIBusSerializable &>(attribute); + + quint32 t = (quint32) attribute.type; + argument << t; + argument << attribute.value; + argument << attribute.start; + argument << attribute.end; + argument.endStructure(); + + return argument; } -void QIBusAttribute::fromDBusArgument(const QDBusArgument &arg) +const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusAttribute &attribute) { -// qDebug() << "QIBusAttribute::fromDBusArgument()" << arg.currentSignature(); - arg.beginStructure(); + argument.beginStructure(); - QIBusSerializable::fromDBusArgument(arg); + argument >> static_cast<QIBusSerializable &>(attribute); quint32 t; - arg >> t; - type = (Type)t; - arg >> value; - arg >> start; - arg >> end; + argument >> t; + attribute.type = (QIBusAttribute::Type) t; + argument >> attribute.value; + argument >> attribute.start; + argument >> attribute.end; - arg.endStructure(); + argument.endStructure(); + + return argument; } QTextFormat QIBusAttribute::format() const @@ -141,36 +182,53 @@ QTextFormat QIBusAttribute::format() const return fmt; } - QIBusAttributeList::QIBusAttributeList() { - + name = "IBusAttrList"; } QIBusAttributeList::~QIBusAttributeList() { +} + +QDBusArgument &operator<<(QDBusArgument &argument, const QIBusAttributeList &attrList) +{ + argument.beginStructure(); + argument << static_cast<const QIBusSerializable &>(attrList); + + argument.beginArray(qMetaTypeId<QDBusVariant>()); + for (int i = 0; i < attrList.attributes.size(); ++i) { + QVariant variant; + variant.setValue(attrList.attributes.at(i)); + argument << QDBusVariant (variant); + } + argument.endArray(); + + argument.endStructure(); + return argument; } -void QIBusAttributeList::fromDBusArgument(const QDBusArgument &arg) +const QDBusArgument &operator>>(const QDBusArgument &arg, QIBusAttributeList &attrList) { // qDebug() << "QIBusAttributeList::fromDBusArgument()" << arg.currentSignature(); arg.beginStructure(); - QIBusSerializable::fromDBusArgument(arg); + arg >> static_cast<QIBusSerializable &>(attrList); arg.beginArray(); - while(!arg.atEnd()) { + while (!arg.atEnd()) { QDBusVariant var; arg >> var; QIBusAttribute attr; - attr.fromDBusArgument(var.variant().value<QDBusArgument>()); - attributes.append(attr); + var.variant().value<QDBusArgument>() >> attr; + attrList.attributes.append(attr); } arg.endArray(); arg.endStructure(); + return arg; } QList<QInputMethodEvent::Attribute> QIBusAttributeList::imAttributes() const @@ -183,30 +241,40 @@ QList<QInputMethodEvent::Attribute> QIBusAttributeList::imAttributes() const return imAttrs; } - QIBusText::QIBusText() { - + name = "IBusText"; } QIBusText::~QIBusText() { +} + +QDBusArgument &operator<<(QDBusArgument &argument, const QIBusText &text) +{ + argument.beginStructure(); + + argument << static_cast<const QIBusSerializable &>(text); + argument << text.text << text.attributes; + argument.endStructure(); + return argument; } -void QIBusText::fromDBusArgument(const QDBusArgument &arg) +const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusText &text) { // qDebug() << "QIBusText::fromDBusArgument()" << arg.currentSignature(); - arg.beginStructure(); + argument.beginStructure(); - QIBusSerializable::fromDBusArgument(arg); + argument >> static_cast<QIBusSerializable &>(text); - arg >> text; + argument >> text.text; QDBusVariant variant; - arg >> variant; - attributes.fromDBusArgument(variant.variant().value<QDBusArgument>()); + argument >> variant; + variant.variant().value<QDBusArgument>() >> text.attributes; - arg.endStructure(); + argument.endStructure(); + return argument; } QT_END_NAMESPACE diff --git a/src/plugins/platforminputcontexts/ibus/qibustypes.h b/src/plugins/platforminputcontexts/ibus/qibustypes.h index 8e6f853a52..0275c5eed2 100644 --- a/src/plugins/platforminputcontexts/ibus/qibustypes.h +++ b/src/plugins/platforminputcontexts/ibus/qibustypes.h @@ -43,19 +43,16 @@ #include <qvector.h> #include <qevent.h> +#include <QDBusArgument> QT_BEGIN_NAMESPACE -class QDBusArgument; - class QIBusSerializable { public: QIBusSerializable(); virtual ~QIBusSerializable(); - virtual void fromDBusArgument(const QDBusArgument &arg); - QString name; QHash<QString, QDBusArgument> attachments; }; @@ -81,7 +78,6 @@ public: QIBusAttribute(); ~QIBusAttribute(); - void fromDBusArgument(const QDBusArgument &arg); QTextFormat format() const; Type type; @@ -96,8 +92,6 @@ public: QIBusAttributeList(); ~QIBusAttributeList(); - void fromDBusArgument(const QDBusArgument &arg); - QList<QInputMethodEvent::Attribute> imAttributes() const; QVector<QIBusAttribute> attributes; @@ -109,12 +103,27 @@ public: QIBusText(); ~QIBusText(); - void fromDBusArgument(const QDBusArgument &arg); - QString text; QIBusAttributeList attributes; }; +QDBusArgument &operator<<(QDBusArgument &argument, const QIBusSerializable &object); +const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusSerializable &object); + +QDBusArgument &operator<<(QDBusArgument &argument, const QIBusAttribute &attribute); +const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusAttribute &attribute); + +QDBusArgument &operator<<(QDBusArgument &argument, const QIBusAttributeList &attributeList); +const QDBusArgument &operator>>(const QDBusArgument &arg, QIBusAttributeList &attrList); + +QDBusArgument &operator<<(QDBusArgument &argument, const QIBusText &text); +const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusText &text); + QT_END_NAMESPACE +Q_DECLARE_METATYPE(QIBusSerializable) +Q_DECLARE_METATYPE(QIBusAttribute) +Q_DECLARE_METATYPE(QIBusAttributeList) +Q_DECLARE_METATYPE(QIBusText) + #endif diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index 243eea071a..0209379afb 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -21,7 +21,9 @@ CONFIG += qpa/genericunixfontdatabase OTHER_FILES += $$PWD/android.json -INCLUDEPATH += $$PWD +INCLUDEPATH += \ + $$PWD \ + $$QT_SOURCE_TREE/src/3rdparty/android SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/androidjnimain.cpp \ @@ -48,7 +50,9 @@ SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/qandroidplatformrasterwindow.cpp \ $$PWD/qandroidplatformbackingstore.cpp \ $$PWD/qandroidplatformopenglcontext.cpp \ - $$PWD/qandroidplatformforeignwindow.cpp + $$PWD/qandroidplatformforeignwindow.cpp \ + $$PWD/extract.cpp \ + $$PWD/qandroideventdispatcher.cpp HEADERS += $$PWD/qandroidplatformintegration.h \ $$PWD/androidjnimain.h \ @@ -75,7 +79,8 @@ HEADERS += $$PWD/qandroidplatformintegration.h \ $$PWD/qandroidplatformrasterwindow.h \ $$PWD/qandroidplatformbackingstore.h \ $$PWD/qandroidplatformopenglcontext.h \ - $$PWD/qandroidplatformforeignwindow.h + $$PWD/qandroidplatformforeignwindow.h \ + $$PWD/qandroideventdispatcher.h #Non-standard install directory, QTBUG-29859 DESTDIR = $$DESTDIR/android diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index 3f58597c9b..a7fec8748b 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -43,10 +43,12 @@ #include "androidjnimain.h" #include "qandroidplatformintegration.h" #include "qpa/qplatformaccessibility.h" +#include <QtPlatformSupport/private/qaccessiblebridgeutils_p.h> #include "qguiapplication.h" #include "qwindow.h" #include "qrect.h" #include "QtGui/qaccessible.h" +#include <QtCore/qmath.h> #include <QtCore/private/qjnihelpers_p.h> #include "qdebug.h" @@ -67,6 +69,7 @@ namespace QtAndroidAccessibility static jmethodID m_setEnabledMethodID = 0; static jmethodID m_setFocusableMethodID = 0; static jmethodID m_setFocusedMethodID = 0; + static jmethodID m_setScrollableMethodID = 0; static jmethodID m_setTextSelectionMethodID = 0; static jmethodID m_setVisibleToUserMethodID = 0; @@ -169,6 +172,18 @@ namespace QtAndroidAccessibility return false; } + static jboolean scrollForward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) + { + QAccessibleInterface *iface = interfaceFromId(objectId); + return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::increaseAction()); + } + + static jboolean scrollBackward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) + { + QAccessibleInterface *iface = interfaceFromId(objectId); + return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::decreaseAction()); + } + #define FIND_AND_CHECK_CLASS(CLASS_NAME) \ clazz = env->FindClass(CLASS_NAME); \ @@ -202,6 +217,11 @@ if (!clazz) { \ return false; } QAccessible::State state = iface->state(); + const QStringList actions = QAccessibleBridgeUtils::effectiveActionNames(iface); + const bool hasClickableAction = actions.contains(QAccessibleActionInterface::pressAction()) + || actions.contains(QAccessibleActionInterface::toggleAction()); + const bool hasIncreaseAction = actions.contains(QAccessibleActionInterface::increaseAction()); + const bool hasDecreaseAction = actions.contains(QAccessibleActionInterface::decreaseAction()); // try to fill in the text property, this is what the screen reader reads QString desc = iface->text(QAccessible::Value); @@ -219,21 +239,26 @@ if (!clazz) { \ } env->CallVoidMethod(node, m_setEnabledMethodID, !state.disabled); + env->CallVoidMethod(node, m_setCheckableMethodID, (bool)state.checkable); env->CallVoidMethod(node, m_setCheckedMethodID, (bool)state.checked); env->CallVoidMethod(node, m_setFocusableMethodID, (bool)state.focusable); env->CallVoidMethod(node, m_setFocusedMethodID, (bool)state.focused); - env->CallVoidMethod(node, m_setCheckableMethodID, (bool)state.checkable); env->CallVoidMethod(node, m_setVisibleToUserMethodID, !state.invisible); + env->CallVoidMethod(node, m_setScrollableMethodID, hasIncreaseAction || hasDecreaseAction); + env->CallVoidMethod(node, m_setClickableMethodID, hasClickableAction); + + // Add ACTION_CLICK + if (hasClickableAction) + env->CallVoidMethod(node, m_addActionMethodID, (int)16); // ACTION_CLICK defined in AccessibilityNodeInfo + + // Add ACTION_SCROLL_FORWARD + if (hasIncreaseAction) + env->CallVoidMethod(node, m_addActionMethodID, (int)4096); // ACTION_SCROLL_FORWARD defined in AccessibilityNodeInfo + + // Add ACTION_SCROLL_BACKWARD + if (hasDecreaseAction) + env->CallVoidMethod(node, m_addActionMethodID, (int)8192); // ACTION_SCROLL_BACKWARD defined in AccessibilityNodeInfo - if (iface->actionInterface()) { - QStringList actions = iface->actionInterface()->actionNames(); - bool clickable = actions.contains(QAccessibleActionInterface::pressAction()); - bool toggle = actions.contains(QAccessibleActionInterface::toggleAction()); - if (clickable || toggle) { - env->CallVoidMethod(node, m_setClickableMethodID, (bool)clickable); - env->CallVoidMethod(node, m_addActionMethodID, (int)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) @@ -251,6 +276,8 @@ if (!clazz) { \ {"hitTest", "(FF)I", (void*)hitTest}, {"populateNode", "(ILandroid/view/accessibility/AccessibilityNodeInfo;)Z", (void*)populateNode}, {"clickAction", "(I)Z", (void*)clickAction}, + {"scrollForward", "(I)Z", (void*)scrollForward}, + {"scrollBackward", "(I)Z", (void*)scrollBackward}, }; #define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \ @@ -283,6 +310,7 @@ if (!clazz) { \ GET_AND_CHECK_STATIC_METHOD(m_setEnabledMethodID, nodeInfoClass, "setEnabled", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setFocusableMethodID, nodeInfoClass, "setFocusable", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setFocusedMethodID, nodeInfoClass, "setFocused", "(Z)V"); + GET_AND_CHECK_STATIC_METHOD(m_setScrollableMethodID, nodeInfoClass, "setScrollable", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setVisibleToUserMethodID, nodeInfoClass, "setVisibleToUser", "(Z)V"); if (QtAndroidPrivate::androidSdkVersion() >= 18) { diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 3e3e169df9..f776e43efa 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -40,21 +40,10 @@ ** ****************************************************************************/ -#include <QtGui/private/qguiapplication_p.h> - #include <dlfcn.h> #include <pthread.h> -#include <qcoreapplication.h> -#include <qimage.h> -#include <qpoint.h> #include <qplugin.h> -#include <qsemaphore.h> -#include <qmutex.h> #include <qdebug.h> -#include <qglobal.h> -#include <qobjectdefs.h> -#include <QtCore/private/qjni_p.h> -#include <stdlib.h> #include "androidjnimain.h" #include "androidjniaccessibility.h" @@ -63,14 +52,16 @@ #include "androidjnimenu.h" #include "qandroidplatformdialoghelpers.h" #include "qandroidplatformintegration.h" - -#include <qabstracteventdispatcher.h> +#include "qandroidassetsfileenginehandler.h" #include <android/bitmap.h> #include <android/asset_manager_jni.h> -#include "qandroidassetsfileenginehandler.h" +#include "qandroideventdispatcher.h" #include <android/api-level.h> + #include <QtCore/private/qjnihelpers_p.h> +#include <QtCore/private/qjni_p.h> +#include <QtGui/private/qguiapplication_p.h> #include <qpa/qwindowsysteminterface.h> @@ -78,42 +69,42 @@ Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin) QT_BEGIN_NAMESPACE -static JavaVM *m_javaVM = NULL; -static jclass m_applicationClass = NULL; -static jobject m_classLoaderObject = NULL; -static jmethodID m_loadClassMethodID = NULL; -static AAssetManager *m_assetManager = NULL; -static jobject m_resourcesObj; -static jobject m_activityObject = NULL; -static jmethodID m_createSurfaceMethodID = 0; -static jmethodID m_insertNativeViewMethodID = 0; -static jmethodID m_setSurfaceGeometryMethodID = 0; -static jmethodID m_destroySurfaceMethodID = 0; +static JavaVM *m_javaVM = Q_NULLPTR; +static jclass m_applicationClass = Q_NULLPTR; +static jobject m_classLoaderObject = Q_NULLPTR; +static jmethodID m_loadClassMethodID = Q_NULLPTR; +static AAssetManager *m_assetManager = Q_NULLPTR; +static jobject m_resourcesObj = Q_NULLPTR; +static jobject m_activityObject = Q_NULLPTR; +static jmethodID m_createSurfaceMethodID = Q_NULLPTR; +static jmethodID m_insertNativeViewMethodID = Q_NULLPTR; +static jmethodID m_setSurfaceGeometryMethodID = Q_NULLPTR; +static jmethodID m_destroySurfaceMethodID = Q_NULLPTR; 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; -static jobject m_RGB_565_BitmapConfigValue = 0; +static jclass m_bitmapClass = Q_NULLPTR; +static jmethodID m_createBitmapMethodID = Q_NULLPTR; +static jobject m_ARGB_8888_BitmapConfigValue = Q_NULLPTR; +static jobject m_RGB_565_BitmapConfigValue = Q_NULLPTR; -jmethodID m_setFullScreenMethodID = 0; +jmethodID m_setFullScreenMethodID = Q_NULLPTR; static bool m_statusBarShowing = true; -static jclass m_bitmapDrawableClass = 0; -static jmethodID m_bitmapDrawableConstructorMethodID = 0; +static jclass m_bitmapDrawableClass = Q_NULLPTR; +static jmethodID m_bitmapDrawableConstructorMethodID = Q_NULLPTR; extern "C" typedef int (*Main)(int, char **); //use the standard main method to start the application -static Main m_main = NULL; -static void *m_mainLibraryHnd = NULL; +static Main m_main = Q_NULLPTR; +static void *m_mainLibraryHnd = Q_NULLPTR; static QList<QByteArray> m_applicationParams; struct SurfaceData { ~SurfaceData() { delete surface; } - QJNIObjectPrivate *surface = 0; - AndroidSurfaceClient *client = 0; + QJNIObjectPrivate *surface = Q_NULLPTR; + AndroidSurfaceClient *client = Q_NULLPTR; }; QHash<int, AndroidSurfaceClient *> m_surfaces; @@ -121,11 +112,8 @@ QHash<int, AndroidSurfaceClient *> m_surfaces; static QMutex m_surfacesMutex; static int m_surfaceId = 1; -static QSemaphore m_quitAppSemaphore; -static QSemaphore m_pauseApplicationSemaphore; -static QMutex m_pauseApplicationMutex; -static QAndroidPlatformIntegration *m_androidPlatformIntegration = 0; +static QAndroidPlatformIntegration *m_androidPlatformIntegration = Q_NULLPTR; static int m_desktopWidthPixels = 0; static int m_desktopHeightPixels = 0; @@ -133,7 +121,7 @@ static double m_scaledDensity = 0; static volatile bool m_pauseApplication; -static AndroidAssetsFileEngineHandler *m_androidAssetsFileEngineHandler = 0; +static AndroidAssetsFileEngineHandler *m_androidAssetsFileEngineHandler = Q_NULLPTR; @@ -212,7 +200,7 @@ namespace QtAndroid return; QtAndroid::AttachedJNIEnv env; - if (env.jniEnv == 0) { + if (!env.jniEnv) { qWarning("Failed to get JNI Environment."); return; } @@ -227,7 +215,7 @@ namespace QtAndroid return; QtAndroid::AttachedJNIEnv env; - if (env.jniEnv == 0) { + if (!env.jniEnv) { qWarning("Failed to get JNI Environment."); return; } @@ -417,6 +405,9 @@ namespace QtAndroid return; m_surfaces.remove(surfaceId); + if (m_surfaces.isEmpty()) + m_surfaceId = 1; + QJNIEnvironmentPrivate env; if (!env) return; @@ -426,12 +417,18 @@ namespace QtAndroid surfaceId); } + bool blockEventLoopsWhenSuspended() + { + static bool block = qgetenv("QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED").toInt(); + return block; + } + } // namespace QtAndroid static jboolean startQtAndroidPlugin(JNIEnv* /*env*/, jobject /*object*//*, jobject applicationAssetManager*/) { - m_androidPlatformIntegration = 0; + m_androidPlatformIntegration = Q_NULLPTR; m_androidAssetsFileEngineHandler = new AndroidAssetsFileEngineHandler(); return true; } @@ -450,7 +447,8 @@ static void *startMainMethod(void */*data*/) if (res < 0) qWarning() << "dlclose failed:" << dlerror(); } - + m_mainLibraryHnd = Q_NULLPTR; + m_main = Q_NULLPTR; QtAndroid::AttachedJNIEnv env; if (!env.jniEnv) return 0; @@ -465,7 +463,7 @@ static void *startMainMethod(void */*data*/) static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring paramsString, jstring environmentString) { - m_mainLibraryHnd = NULL; + m_mainLibraryHnd = Q_NULLPTR; { // Set env. vars const char *nativeString = env->GetStringUTFChars(environmentString, 0); const QList<QByteArray> envVars = QByteArray(nativeString).split('\t'); @@ -491,7 +489,7 @@ static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring para // Obtain a handle to the main library (the library that contains the main() function). // This library should already be loaded, and calling dlopen() will just return a reference to it. m_mainLibraryHnd = dlopen(m_applicationParams.first().data(), 0); - if (m_mainLibraryHnd == NULL) { + if (m_mainLibraryHnd == Q_NULLPTR) { qCritical() << "dlopen failed:" << dlerror(); return false; } @@ -508,15 +506,16 @@ static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring para } pthread_t appThread; - return pthread_create(&appThread, NULL, startMainMethod, NULL) == 0; + return pthread_create(&appThread, Q_NULLPTR, startMainMethod, Q_NULLPTR) == 0; } static void quitQtAndroidPlugin(JNIEnv *env, jclass /*clazz*/) { Q_UNUSED(env); - m_androidPlatformIntegration = 0; + m_androidPlatformIntegration = Q_NULLPTR; delete m_androidAssetsFileEngineHandler; + m_androidAssetsFileEngineHandler = Q_NULLPTR; } static void terminateQt(JNIEnv *env, jclass /*clazz*/) @@ -535,8 +534,9 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/) env->DeleteGlobalRef(m_RGB_565_BitmapConfigValue); if (m_bitmapDrawableClass) env->DeleteGlobalRef(m_bitmapDrawableClass); - m_androidPlatformIntegration = 0; + m_androidPlatformIntegration = Q_NULLPTR; delete m_androidAssetsFileEngineHandler; + m_androidAssetsFileEngineHandler = Q_NULLPTR; } static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, jint w, jint h) @@ -579,11 +579,11 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/) if (!m_androidPlatformIntegration) return; - if (QGuiApplication::instance() != 0) { + if (QGuiApplication::instance() != Q_NULLPTR) { foreach (QWindow *w, QGuiApplication::topLevelWindows()) { QRect availableGeometry = w->screen()->availableGeometry(); if (w->geometry().width() > 0 && w->geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0) - QWindowSystemInterface::handleExposeEvent(w, QRegion(w->geometry())); + QWindowSystemInterface::handleExposeEvent(w, QRegion(QRect(QPoint(), w->geometry().size()))); } } @@ -596,10 +596,22 @@ static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state { m_activityActive = (state == Qt::ApplicationActive); - if (!m_androidPlatformIntegration || !QGuiApplicationPrivate::platformIntegration()) + if (!m_main || !m_androidPlatformIntegration || !QGuiApplicationPrivate::platformIntegration()) return; - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState(state)); + if (state <= Qt::ApplicationInactive) { + // Don't send timers and sockets events anymore if we are going to hide all windows + QAndroidEventDispatcherStopper::instance()->goingToStop(true); + QCoreApplication::processEvents(); + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState(state)); + QWindowSystemInterface::flushWindowSystemEvents(); + if (state == Qt::ApplicationSuspended) + QAndroidEventDispatcherStopper::instance()->stopAll(); + } else { + QAndroidEventDispatcherStopper::instance()->startAll(); + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState(state)); + QAndroidEventDispatcherStopper::instance()->goingToStop(false); + } } static void handleOrientationChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newRotation, jint nativeOrientation) @@ -762,8 +774,8 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/) __android_log_print(ANDROID_LOG_INFO, "Qt", "qt start"); UnionJNIEnvToVoid uenv; - uenv.venv = NULL; - m_javaVM = 0; + uenv.venv = Q_NULLPTR; + m_javaVM = Q_NULLPTR; if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) { __android_log_print(ANDROID_LOG_FATAL, "Qt", "GetEnv failed"); diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 29896529ca..31b1aa229e 100644 --- a/src/plugins/platforms/android/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -100,7 +100,7 @@ namespace QtAndroid if (QtAndroid::javaVM()->GetEnv((void**)&jniEnv, JNI_VERSION_1_6) < 0) { if (QtAndroid::javaVM()->AttachCurrentThread(&jniEnv, NULL) < 0) { __android_log_print(ANDROID_LOG_ERROR, "Qt", "AttachCurrentThread failed"); - jniEnv = 0; + jniEnv = Q_NULLPTR; return; } attached = true; @@ -120,6 +120,7 @@ namespace QtAndroid const char *qtTagText(); QString deviceName(); + bool blockEventLoopsWhenSuspended(); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/extract.cpp b/src/plugins/platforms/android/extract.cpp new file mode 100644 index 0000000000..25c3a1c29d --- /dev/null +++ b/src/plugins/platforms/android/extract.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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 <jni.h> +#include <android/log.h> +#include <extract.h> +#include <alloca.h> + +#define LOG_TAG "extractSyleInfo" +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) + +extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo(JNIEnv * env, jobject, Res_png_9patch* chunk) +{ + Res_png_9patch::deserialize(chunk); + //printChunkInformation(chunk); + jintArray result; + size_t size = 3+chunk->numXDivs+chunk->numYDivs+chunk->numColors; + result = env->NewIntArray(size); + if (!result) + return 0; + + jint *data = (jint*)malloc(sizeof(jint)*size); + size_t pos = 0; + data[pos++]=chunk->numXDivs; + data[pos++]=chunk->numYDivs; + data[pos++]=chunk->numColors; + for (int x = 0; x <chunk->numXDivs; x ++) + data[pos++]=chunk->xDivs[x]; + for (int y = 0; y <chunk->numYDivs; y ++) + data[pos++]=chunk->yDivs[y]; + for (int c = 0; c <chunk->numColors; c ++) + data[pos++]=chunk->colors[c]; + env->SetIntArrayRegion(result, 0, size, data); + free(data); + return result; +} + +extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractChunkInfo(JNIEnv * env, jobject obj, jbyteArray chunkObj) +{ + size_t chunkSize = env->GetArrayLength(chunkObj); + void* storage = alloca(chunkSize); + env->GetByteArrayRegion(chunkObj, 0, chunkSize, + reinterpret_cast<jbyte*>(storage)); + + if (!env->ExceptionCheck()) + return Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo(env, obj, static_cast<Res_png_9patch*>(storage)); + else + env->ExceptionClear(); + return 0; +} + +// The following part was shamelessly stolen from ResourceTypes.cpp from Android's sources +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +static void deserializeInternal(const void* inData, Res_png_9patch* outData) { + char* patch = (char*) inData; + if (inData != outData) { + memmove(&outData->wasDeserialized, patch, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors + memmove(&outData->paddingLeft, patch + 12, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors + } + outData->wasDeserialized = true; + char* data = (char*)outData; + data += sizeof(Res_png_9patch); + outData->xDivs = (int32_t*) data; + data += outData->numXDivs * sizeof(int32_t); + outData->yDivs = (int32_t*) data; + data += outData->numYDivs * sizeof(int32_t); + outData->colors = (uint32_t*) data; +} + +Res_png_9patch* Res_png_9patch::deserialize(const void* inData) +{ + if (sizeof(void*) != sizeof(int32_t)) { + LOGE("Cannot deserialize on non 32-bit system\n"); + return NULL; + } + deserializeInternal(inData, (Res_png_9patch*) inData); + return (Res_png_9patch*) inData; +} + +extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo20(JNIEnv * env, jobject, long addr) +{ + Res_png_9patch20* chunk = reinterpret_cast<Res_png_9patch20*>(addr); + Res_png_9patch20::deserialize(chunk); + //printChunkInformation(chunk); + jintArray result; + size_t size = 3+chunk->numXDivs+chunk->numYDivs+chunk->numColors; + result = env->NewIntArray(size); + if (!result) + return 0; + + jint *data = (jint*)malloc(sizeof(jint)*size); + size_t pos = 0; + data[pos++] = chunk->numXDivs; + data[pos++] = chunk->numYDivs; + data[pos++] = chunk->numColors; + + int32_t* xDivs = chunk->getXDivs(); + int32_t* yDivs = chunk->getYDivs(); + uint32_t* colors = chunk->getColors(); + + for (int x = 0; x <chunk->numXDivs; x ++) + data[pos++]=xDivs[x]; + for (int y = 0; y <chunk->numYDivs; y ++) + data[pos++] = yDivs[y]; + for (int c = 0; c <chunk->numColors; c ++) + data[pos++] = colors[c]; + env->SetIntArrayRegion(result, 0, size, data); + free(data); + return result; +} + +extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractChunkInfo20(JNIEnv * env, jobject obj, jbyteArray chunkObj) +{ + size_t chunkSize = env->GetArrayLength(chunkObj); + void* storage = alloca(chunkSize); + env->GetByteArrayRegion(chunkObj, 0, chunkSize, + reinterpret_cast<jbyte*>(storage)); + + if (!env->ExceptionCheck()) + return Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo20(env, obj, long(storage)); + else + env->ExceptionClear(); + return 0; +} + +static inline void fill9patchOffsets(Res_png_9patch20* patch) { + patch->xDivsOffset = sizeof(Res_png_9patch20); + patch->yDivsOffset = patch->xDivsOffset + (patch->numXDivs * sizeof(int32_t)); + patch->colorsOffset = patch->yDivsOffset + (patch->numYDivs * sizeof(int32_t)); +} + +Res_png_9patch20* Res_png_9patch20::deserialize(void* inData) +{ + Res_png_9patch20* patch = reinterpret_cast<Res_png_9patch20*>(inData); + patch->wasDeserialized = true; + fill9patchOffsets(patch); + return patch; +} diff --git a/src/plugins/platforms/android/qandroideventdispatcher.cpp b/src/plugins/platforms/android/qandroideventdispatcher.cpp new file mode 100644 index 0000000000..074ba71f80 --- /dev/null +++ b/src/plugins/platforms/android/qandroideventdispatcher.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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 "qandroideventdispatcher.h" +#include "androidjnimain.h" + +QAndroidEventDispatcher::QAndroidEventDispatcher(QObject *parent) : + QUnixEventDispatcherQPA(parent) +{ + if (QtAndroid::blockEventLoopsWhenSuspended()) + QAndroidEventDispatcherStopper::instance()->addEventDispatcher(this); +} + +QAndroidEventDispatcher::~QAndroidEventDispatcher() +{ + if (QtAndroid::blockEventLoopsWhenSuspended()) + QAndroidEventDispatcherStopper::instance()->removeEventDispatcher(this); +} + +void QAndroidEventDispatcher::start() +{ + if (m_stopRequest.testAndSetAcquire(1, 0)) { + m_dispatcherSemaphore.release(); + wakeUp(); + } +} + +void QAndroidEventDispatcher::stop() +{ + if (m_stopRequest.testAndSetAcquire(0, 1)) { + wakeUp(); + m_stopperSemaphore.acquire(); + } +} + +void QAndroidEventDispatcher::goingToStop(bool stop) +{ + m_goingToStop.store(stop ? 1 : 0); + if (!stop) + wakeUp(); +} + +int QAndroidEventDispatcher::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, timespec *timeout) +{ + if (m_stopRequest.load() == 1) { + m_stopperSemaphore.release(); + m_dispatcherSemaphore.acquire(); + wakeUp(); + } + + return QUnixEventDispatcherQPA::select(nfds, readfds, writefds, exceptfds, timeout); +} + +bool QAndroidEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + if (m_goingToStop.load()) { + return QUnixEventDispatcherQPA::processEvents(flags /*| QEventLoop::ExcludeUserInputEvents*/ + | QEventLoop::ExcludeSocketNotifiers + | QEventLoop::X11ExcludeTimers); + } else { + return QUnixEventDispatcherQPA::processEvents(flags); + } +} + + +QAndroidEventDispatcherStopper *QAndroidEventDispatcherStopper::instance() +{ + static QAndroidEventDispatcherStopper androidEventDispatcherStopper; + return &androidEventDispatcherStopper; +} + +void QAndroidEventDispatcherStopper::startAll() +{ + QMutexLocker lock(&m_mutex); + if (started) + return; + + started = true; + foreach (QAndroidEventDispatcher *d, m_dispatchers) + d->start(); +} + +void QAndroidEventDispatcherStopper::stopAll() +{ + QMutexLocker lock(&m_mutex); + if (!started) + return; + + started = false; + foreach (QAndroidEventDispatcher *d, m_dispatchers) + d->stop(); +} + +void QAndroidEventDispatcherStopper::addEventDispatcher(QAndroidEventDispatcher *dispatcher) +{ + QMutexLocker lock(&m_mutex); + m_dispatchers.push_back(dispatcher); +} + +void QAndroidEventDispatcherStopper::removeEventDispatcher(QAndroidEventDispatcher *dispatcher) +{ + QMutexLocker lock(&m_mutex); + m_dispatchers.erase(std::find(m_dispatchers.begin(), m_dispatchers.end(), dispatcher)); +} + +void QAndroidEventDispatcherStopper::goingToStop(bool stop) +{ + QMutexLocker lock(&m_mutex); + foreach (QAndroidEventDispatcher *d, m_dispatchers) + d->goingToStop(stop); +} diff --git a/src/plugins/platforms/android/qandroideventdispatcher.h b/src/plugins/platforms/android/qandroideventdispatcher.h new file mode 100644 index 0000000000..8d1bcf2122 --- /dev/null +++ b/src/plugins/platforms/android/qandroideventdispatcher.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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 QANDROIDEVENTDISPATCHER_H +#define QANDROIDEVENTDISPATCHER_H + +#include <QtCore/QMutex> +#include <QtCore/QSemaphore> +#include <QtPlatformSupport/private/qunixeventdispatcher_qpa_p.h> + +class QAndroidEventDispatcher : public QUnixEventDispatcherQPA +{ + Q_OBJECT +public: + explicit QAndroidEventDispatcher(QObject *parent = 0); + ~QAndroidEventDispatcher(); + void start(); + void stop(); + + void goingToStop(bool stop); + +protected: + int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + timespec *timeout); + + bool processEvents(QEventLoop::ProcessEventsFlags flags); + +private: + QAtomicInt m_stopRequest; + QAtomicInt m_goingToStop; + QSemaphore m_dispatcherSemaphore, m_stopperSemaphore; +}; + +class QAndroidEventDispatcherStopper +{ +public: + static QAndroidEventDispatcherStopper *instance(); + void startAll(); + void stopAll(); + void addEventDispatcher(QAndroidEventDispatcher *dispatcher); + void removeEventDispatcher(QAndroidEventDispatcher *dispatcher); + void goingToStop(bool stop); + +private: + QMutex m_mutex; + bool started = true; + QVector<QAndroidEventDispatcher *> m_dispatchers; +}; + + +#endif // QANDROIDEVENTDISPATCHER_H diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.h b/src/plugins/platforms/android/qandroidplatformbackingstore.h index 4c24e129c3..c51ebe879d 100644 --- a/src/plugins/platforms/android/qandroidplatformbackingstore.h +++ b/src/plugins/platforms/android/qandroidplatformbackingstore.h @@ -55,7 +55,7 @@ public: virtual QPaintDevice *paintDevice(); virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); virtual void resize(const QSize &size, const QRegion &staticContents); - const QImage image() { return m_image; } + QImage toImage() const { return m_image; } void setBackingStore(QWindow *window); protected: QImage m_image; diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index d6d7d3b173..829227f81c 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -47,15 +47,14 @@ #include <QThread> #include <QOffscreenSurface> -#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> #include <QtPlatformSupport/private/qeglpbuffer_p.h> - #include <qpa/qwindowsysteminterface.h> #include <qpa/qplatformwindow.h> #include <qpa/qplatformoffscreensurface.h> #include "androidjnimain.h" #include "qabstracteventdispatcher.h" +#include "qandroideventdispatcher.h" #include "qandroidplatformbackingstore.h" #include "qandroidplatformaccessibility.h" #include "qandroidplatformclipboard.h" @@ -236,7 +235,7 @@ QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *wind QAbstractEventDispatcher *QAndroidPlatformIntegration::createEventDispatcher() const { - return createUnixEventDispatcher(); + return new QAndroidEventDispatcher; } QAndroidPlatformIntegration::~QAndroidPlatformIntegration() diff --git a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp index f27bea8863..2c6e8370ce 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp @@ -58,10 +58,10 @@ QAndroidPlatformOpenGLContext::QAndroidPlatformOpenGLContext(const QSurfaceForma void QAndroidPlatformOpenGLContext::swapBuffers(QPlatformSurface *surface) { - QEGLPlatformContext::swapBuffers(surface); - if (surface->surface()->surfaceClass() == QSurface::Window) static_cast<QAndroidPlatformOpenGLWindow *>(surface)->checkNativeSurface(eglConfig()); + + QEGLPlatformContext::swapBuffers(surface); } bool QAndroidPlatformOpenGLContext::needsFBOReadBackWorkaroud() diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp index f0c4a1de2a..7c39cb718d 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp @@ -57,10 +57,6 @@ QT_BEGIN_NAMESPACE QAndroidPlatformOpenGLWindow::QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display) :QAndroidPlatformWindow(window), m_eglDisplay(display) { - lockSurface(); - m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), bool(window->flags() & Qt::WindowStaysOnTopHint), 32); - m_surfaceWaitCondition.wait(&m_surfaceMutex); - unlockSurface(); } QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow() @@ -97,6 +93,13 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect) EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config) { QMutexLocker lock(&m_surfaceMutex); + + if (m_nativeSurfaceId == -1) { + const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint); + m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32); + m_surfaceWaitCondition.wait(&m_surfaceMutex); + } + if (m_eglSurface == EGL_NO_SURFACE) { m_surfaceMutex.unlock(); checkNativeSurface(config); @@ -117,7 +120,21 @@ void QAndroidPlatformOpenGLWindow::checkNativeSurface(EGLConfig config) // we've create another surface, the window should be repainted QRect availableGeometry = screen()->availableGeometry(); if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0) - QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); + QWindowSystemInterface::handleExposeEvent(window(), QRegion(QRect(QPoint(), geometry().size()))); +} + +void QAndroidPlatformOpenGLWindow::applicationStateChanged(Qt::ApplicationState state) +{ + QAndroidPlatformWindow::applicationStateChanged(state); + if (state <= Qt::ApplicationHidden && QtAndroid::blockEventLoopsWhenSuspended()) { + lockSurface(); + if (m_nativeSurfaceId != -1) { + QtAndroid::destroySurface(m_nativeSurfaceId); + m_nativeSurfaceId = -1; + } + clearEgl(); + unlockSurface(); + } } void QAndroidPlatformOpenGLWindow::createEgl(EGLConfig config) @@ -170,7 +187,7 @@ void QAndroidPlatformOpenGLWindow::surfaceChanged(JNIEnv *jniEnv, jobject surfac // repaint the window QRect availableGeometry = screen()->availableGeometry(); if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0) - QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); + QWindowSystemInterface::handleExposeEvent(window(), QRegion(QRect(QPoint(), geometry().size()))); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.h b/src/plugins/platforms/android/qandroidplatformopenglwindow.h index 83df15a524..713f943bc5 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.h +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.h @@ -64,6 +64,8 @@ public: void checkNativeSurface(EGLConfig config); + void applicationStateChanged(Qt::ApplicationState); + protected: virtual void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h); void createEgl(EGLConfig config); diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index 714a670134..529ae0a80d 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -54,6 +54,7 @@ #include <android/bitmap.h> #include <android/native_window_jni.h> +#include <qguiapplication.h> #include <QtGui/QGuiApplication> #include <QtGui/QWindow> @@ -102,6 +103,7 @@ QAndroidPlatformScreen::QAndroidPlatformScreen():QObject(),QPlatformScreen() m_redrawTimer.setSingleShot(true); m_redrawTimer.setInterval(0); connect(&m_redrawTimer, SIGNAL(timeout()), this, SLOT(doRedraw())); + connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QAndroidPlatformScreen::applicationStateChanged); } QAndroidPlatformScreen::~QAndroidPlatformScreen() @@ -109,8 +111,7 @@ QAndroidPlatformScreen::~QAndroidPlatformScreen() if (m_id != -1) { QtAndroid::destroySurface(m_id); m_surfaceWaitCondition.wakeOne(); - if (m_nativeSurface) - ANativeWindow_release(m_nativeSurface); + releaseSurface(); } } @@ -133,7 +134,7 @@ QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window) { - if (window->parent()) + if (window->parent() && window->isRaster()) return; m_windowStack.prepend(window); @@ -149,10 +150,11 @@ void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window) void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window) { - if (window->parent()) + if (window->parent() && window->isRaster()) return; m_windowStack.removeOne(window); + if (window->isRaster()) { m_rasterSurfaces.deref(); setDirty(window->geometry()); @@ -165,7 +167,7 @@ void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window) void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window) { - if (window->parent()) + if (window->parent() && window->isRaster()) return; int index = m_windowStack.indexOf(window); @@ -182,7 +184,7 @@ void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window) void QAndroidPlatformScreen::lower(QAndroidPlatformWindow *window) { - if (window->parent()) + if (window->parent() && window->isRaster()) return; int index = m_windowStack.indexOf(window); @@ -247,14 +249,25 @@ void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect) } if (m_id != -1) { - if (m_nativeSurface) { - ANativeWindow_release(m_nativeSurface); - m_nativeSurface = 0; - } + releaseSurface(); QtAndroid::setSurfaceGeometry(m_id, rect); } } +void QAndroidPlatformScreen::applicationStateChanged(Qt::ApplicationState state) +{ + foreach (QAndroidPlatformWindow *w, m_windowStack) + w->applicationStateChanged(state); + + if (state <= Qt::ApplicationHidden && QtAndroid::blockEventLoopsWhenSuspended()) { + lockSurface(); + QtAndroid::destroySurface(m_id); + m_id = -1; + releaseSurface(); + unlockSurface(); + } +} + void QAndroidPlatformScreen::topWindowChanged(QWindow *w) { QtAndroidMenu::setActiveTopLevelWindow(w); @@ -332,7 +345,7 @@ void QAndroidPlatformScreen::doRedraw() QRect windowRect = targetRect.translated(-window->geometry().topLeft()); QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformRasterWindow *>(window)->backingStore(); if (backingStore) - compositePainter.drawImage(targetRect.topLeft(), backingStore->image(), windowRect); + compositePainter.drawImage(targetRect.topLeft(), backingStore->toImage(), windowRect); } } @@ -365,18 +378,22 @@ void QAndroidPlatformScreen::surfaceChanged(JNIEnv *env, jobject surface, int w, { lockSurface(); if (surface && w && h) { - if (m_nativeSurface) - ANativeWindow_release(m_nativeSurface); + releaseSurface(); m_nativeSurface = ANativeWindow_fromSurface(env, surface); QMetaObject::invokeMethod(this, "setDirty", Qt::QueuedConnection, Q_ARG(QRect, QRect(0, 0, w, h))); } else { - if (m_nativeSurface) { - ANativeWindow_release(m_nativeSurface); - m_nativeSurface = 0; - } + releaseSurface(); } unlockSurface(); m_surfaceWaitCondition.wakeOne(); } +void QAndroidPlatformScreen::releaseSurface() +{ + if (m_nativeSurface) { + ANativeWindow_release(m_nativeSurface); + m_nativeSurface = 0; + } +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h index cd9cf2ca71..311752c7b4 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.h +++ b/src/plugins/platforms/android/qandroidplatformscreen.h @@ -107,6 +107,8 @@ private: Qt::ScreenOrientation orientation() const; Qt::ScreenOrientation nativeOrientation() const; void surfaceChanged(JNIEnv *env, jobject surface, int w, int h); + void releaseSurface(); + void applicationStateChanged(Qt::ApplicationState); private slots: void doRedraw(); diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp index 558525b78c..d07573fb88 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -45,6 +45,8 @@ #include "qandroidplatformscreen.h" #include "androidjnimain.h" + +#include <qguiapplication.h> #include <qpa/qwindowsysteminterface.h> QT_BEGIN_NAMESPACE @@ -160,5 +162,21 @@ void QAndroidPlatformWindow::updateStatusBarVisibility() } } +bool QAndroidPlatformWindow::isExposed() const +{ + return qApp->applicationState() > Qt::ApplicationHidden + && window()->isVisible() + && !window()->geometry().isEmpty(); +} + +void QAndroidPlatformWindow::applicationStateChanged(Qt::ApplicationState) +{ + QRegion region; + if (isExposed()) + region = QRect(QPoint(), geometry().size()); + + QWindowSystemInterface::handleExposeEvent(window(), region); + QWindowSystemInterface::flushWindowSystemEvents(); +} QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index 764dd3ab86..91e32fa2ac 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -72,7 +72,9 @@ public: void requestActivateWindow(); void updateStatusBarVisibility(); inline bool isRaster() const { return window()->surfaceType() == QSurface::RasterSurface; } + bool isExposed() const; + virtual void applicationStateChanged(Qt::ApplicationState); protected: void setGeometry(const QRect &rect); diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 1f9c0e051d..ad6cb3a1fc 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -14,7 +14,6 @@ OBJECTIVE_SOURCES += main.mm \ qnsviewaccessibility.mm \ qcocoaautoreleasepool.mm \ qnswindowdelegate.mm \ - qcocoaglcontext.mm \ qcocoanativeinterface.mm \ qcocoaeventdispatcher.mm \ qcocoaapplicationdelegate.mm \ @@ -51,7 +50,6 @@ HEADERS += qcocoaintegration.h \ qnsview.h \ qcocoaautoreleasepool.h \ qnswindowdelegate.h \ - qcocoaglcontext.h \ qcocoanativeinterface.h \ qcocoaeventdispatcher.h \ qcocoaapplicationdelegate.h \ @@ -80,6 +78,12 @@ HEADERS += qcocoaintegration.h \ messages.h \ qcocoamimetypes.h +contains(QT_CONFIG, opengl.*) { + OBJECTIVE_SOURCES += qcocoaglcontext.mm + + HEADERS += qcocoaglcontext.h +} + RESOURCES += qcocoaresources.qrc LIBS += -framework Cocoa -framework Carbon -framework IOKit -lcups diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 72045a1bbb..8f83b0fe30 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -55,7 +55,7 @@ QCocoaAccessibility::~QCocoaAccessibility() void QCocoaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) { - QCocoaAccessibleElement *element = [QCocoaAccessibleElement elementWithId: event->uniqueId()]; + QMacAccessibilityElement *element = [QMacAccessibilityElement elementWithId: event->uniqueId()]; if (!element) { qWarning() << "QCocoaAccessibility::notifyAccessibilityUpdate: invalid element"; return; @@ -140,7 +140,7 @@ static void populateRoleMap() roleMap[QAccessible::Row] = NSAccessibilityRowRole; roleMap[QAccessible::RowHeader] = NSAccessibilityRowRole; roleMap[QAccessible::Cell] = NSAccessibilityTextFieldRole; - roleMap[QAccessible::PushButton] = NSAccessibilityButtonRole; + roleMap[QAccessible::Button] = NSAccessibilityButtonRole; roleMap[QAccessible::EditableText] = NSAccessibilityTextFieldRole; roleMap[QAccessible::Link] = NSAccessibilityLinkRole; roleMap[QAccessible::Indicator] = NSAccessibilityValueIndicatorRole; @@ -149,6 +149,9 @@ static void populateRoleMap() roleMap[QAccessible::ListItem] = NSAccessibilityStaticTextRole; roleMap[QAccessible::Cell] = NSAccessibilityStaticTextRole; roleMap[QAccessible::Client] = NSAccessibilityGroupRole; + roleMap[QAccessible::Paragraph] = NSAccessibilityGroupRole; + roleMap[QAccessible::Section] = NSAccessibilityGroupRole; + roleMap[QAccessible::WebDocument] = NSAccessibilityGroupRole; } /* @@ -244,7 +247,7 @@ NSArray *unignoredChildren(QAccessibleInterface *interface) QAccessible::Id childId = QAccessible::uniqueId(child); //qDebug() << " kid: " << childId << child; - QCocoaAccessibleElement *element = [QCocoaAccessibleElement elementWithId: childId]; + QMacAccessibilityElement *element = [QMacAccessibilityElement elementWithId: childId]; if (element) [kids addObject: element]; else @@ -343,7 +346,7 @@ id getValueAttribute(QAccessibleInterface *interface) } if (QAccessibleValueInterface *valueInterface = interface->valueInterface()) { - return QCFString::toNSString(QString::number(valueInterface->currentValue().toDouble())); + return QCFString::toNSString(valueInterface->currentValue().toString()); } if (interface->state().checkable) { diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h index 9760f492ea..4a5baefbc5 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h @@ -50,18 +50,18 @@ #import <qaccessible.h> -@class QT_MANGLE_NAMESPACE(QCocoaAccessibleElement); +@class QT_MANGLE_NAMESPACE(QMacAccessibilityElement); -@interface QT_MANGLE_NAMESPACE(QCocoaAccessibleElement) : NSObject { +@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : NSObject { NSString *role; QAccessible::Id axid; } - (id)initWithId:(QAccessible::Id)anId; -+ (QT_MANGLE_NAMESPACE(QCocoaAccessibleElement) *)elementWithId:(QAccessible::Id)anId; ++ (QT_MANGLE_NAMESPACE(QMacAccessibilityElement) *)elementWithId:(QAccessible::Id)anId; @end -QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaAccessibleElement); +QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement); #endif diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 078dc67cad..9f803e411d 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -43,12 +43,12 @@ #include "qcocoahelpers.h" #include "qcocoawindow.h" #include "private/qaccessiblecache_p.h" - +#include <QtPlatformSupport/private/qaccessiblebridgeutils_p.h> #include <QtGui/qaccessible.h> #import <AppKit/NSAccessibility.h> -@implementation QCocoaAccessibleElement +@implementation QMacAccessibilityElement - (id)initWithId:(QAccessible::Id)anId { @@ -72,7 +72,7 @@ QAccessibleCache *cache = QAccessibleCache::instance(); - QCocoaAccessibleElement *element = cache->elementForId(anId); + QMacAccessibilityElement *element = cache->elementForId(anId); if (!element) { QAccessibleInterface *iface = QAccessible::accessibleInterface(anId); Q_ASSERT(iface); @@ -95,8 +95,8 @@ } - (BOOL)isEqual:(id)object { - if ([object isKindOfClass:[QCocoaAccessibleElement class]]) { - QCocoaAccessibleElement *other = object; + if ([object isKindOfClass:[QMacAccessibilityElement class]]) { + QMacAccessibilityElement *other = object; return other->axid == axid; } else { return NO; @@ -196,7 +196,7 @@ } QAccessible::Id parentId = QAccessible::uniqueId(parent); - return [QCocoaAccessibleElement elementWithId: parentId]; + return [QMacAccessibilityElement elementWithId: parentId]; } @@ -345,7 +345,7 @@ } if ([attribute isEqualToString: NSAccessibilityLineForIndexParameterizedAttribute]) { int index = [parameter intValue]; - NSNumber *ln = [QCocoaAccessibleElement lineNumberForIndex: index forText: iface->text(QAccessible::Value)]; + NSNumber *ln = [QMacAccessibilityElement lineNumberForIndex: index forText: iface->text(QAccessible::Value)]; return ln; } if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) { @@ -430,15 +430,11 @@ if (!iface) return nsActions; - QAccessibleActionInterface *actionInterface = iface->actionInterface(); - if (actionInterface) { - QStringList supportedActionNames = actionInterface->actionNames(); - - foreach (const QString &qtAction, supportedActionNames) { - NSString *nsAction = QCocoaAccessible::getTranslatedAction(qtAction); - if (nsAction) - [nsActions addObject : nsAction]; - } + const QStringList &supportedActionNames = QAccessibleBridgeUtils::effectiveActionNames(iface); + foreach (const QString &qtAction, supportedActionNames) { + NSString *nsAction = QCocoaAccessible::getTranslatedAction(qtAction); + if (nsAction) + [nsActions addObject : nsAction]; } return nsActions; @@ -448,27 +444,25 @@ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); if (!iface) return nil; // FIXME is that the right return type?? - QAccessibleActionInterface *actionInterface = iface->actionInterface(); - if (actionInterface) { - QString qtAction = QCocoaAccessible::translateAction(action); - - // Return a description from the action interface if this action is not known to the OS. - if (qtAction.isEmpty()) { - QString description = actionInterface->localizedActionDescription(qtAction); - return QCFString::toNSString(description); + QString qtAction = QCocoaAccessible::translateAction(action); + QString description; + // Return a description from the action interface if this action is not known to the OS. + if (qtAction.isEmpty()) { + if (QAccessibleActionInterface *actionInterface = iface->actionInterface()) { + qtAction = QString::fromNSString((NSString *)action); + description = actionInterface->localizedActionDescription(qtAction); } + } else { + description = qAccessibleLocalizedActionDescription(qtAction); } - - return NSAccessibilityActionDescription(action); + return QCFString::toNSString(description); } - (void)accessibilityPerformAction:(NSString *)action { QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); if (iface) { - QAccessibleActionInterface *actionInterface = iface->actionInterface(); - if (actionInterface) { - actionInterface->doAction(QCocoaAccessible::translateAction(action)); - } + const QString qtAction = QCocoaAccessible::translateAction(action); + QAccessibleBridgeUtils::performEffectiveAction(iface, qtAction); } } @@ -504,7 +498,7 @@ QAccessible::Id childId = QAccessible::uniqueId(childInterface); // hit a child, forward to child accessible interface. - QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithId:childId]; + QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithId:childId]; if (accessibleElement) return NSAccessibilityUnignoredAncestor(accessibleElement); return NSAccessibilityUnignoredAncestor(self); @@ -521,7 +515,7 @@ QAccessibleInterface *childInterface = iface->focusChild(); if (childInterface) { QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); - QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithId:childAxid]; + QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithId:childAxid]; return NSAccessibilityUnignoredAncestor(accessibleElement); } diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 92358ecc74..efe3269d42 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -340,6 +340,7 @@ static void cleanupCocoaApplicationDelegate() && [reflectionDelegate respondsToSelector:@selector(applicationDidBecomeActive:)]) [reflectionDelegate applicationDidBecomeActive:notification]; + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); /* onApplicationChangedActivation(true); @@ -363,6 +364,7 @@ static void cleanupCocoaApplicationDelegate() && [reflectionDelegate respondsToSelector:@selector(applicationDidResignActive:)]) [reflectionDelegate applicationDidResignActive:notification]; + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); /* onApplicationChangedActivation(false); @@ -374,6 +376,26 @@ static void cleanupCocoaApplicationDelegate() */ } +- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag +{ + Q_UNUSED(theApplication); + Q_UNUSED(flag); + if (reflectionDelegate + && [reflectionDelegate respondsToSelector:@selector(applicationShouldHandleReopen:hasVisibleWindows:)]) + return [reflectionDelegate applicationShouldHandleReopen:theApplication hasVisibleWindows:flag]; + + /* + true to force delivery of the event even if the application state is already active, + because rapp (handle reopen) events are sent each time the dock icon is clicked regardless + of the active state of the application or number of visible windows. For example, a browser + app that has no windows opened would need the event be to delivered even if it was already + active in order to create a new window as per OS X conventions. + */ + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive, true /*forcePropagate*/); + + return NO; +} + - (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate { [oldDelegate retain]; diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index a33373c4c1..8a4e2e68df 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -59,7 +59,9 @@ public: QPaintDevice *paintDevice(); void flush(QWindow *widget, const QRegion ®ion, const QPoint &offset); +#ifndef QT_NO_OPENGL QImage toImage() const Q_DECL_OVERRIDE; +#endif void resize (const QSize &size, const QRegion &); bool scroll(const QRegion &area, int dx, int dy); CGImageRef getBackingStoreCGImage(); diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index d76645c668..e13e295511 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -96,10 +96,12 @@ void QCocoaBackingStore::flush(QWindow *win, const QRegion ®ion, const QPoint } } +#ifndef QT_NO_OPENGL QImage QCocoaBackingStore::toImage() const { return m_qImage; } +#endif void QCocoaBackingStore::resize(const QSize &size, const QRegion &) { diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index 30f1cdc278..2aa22ea759 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE class QCocoaGLContext : public QPlatformOpenGLContext { public: - QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share); + QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, const QVariant &nativeHandle); ~QCocoaGLContext(); QSurfaceFormat format() const; @@ -77,6 +77,8 @@ public: void windowWasHidden(); + QVariant nativeHandle() const; + private: void setActiveWindow(QWindow *window); void updateSurfaceFormat(); diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 3f61bd81ee..7b70fbb4bb 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -46,6 +46,7 @@ #include <qdebug.h> #include <QtCore/private/qcore_mac_p.h> #include <QtPlatformSupport/private/cglconvenience_p.h> +#include <QtPlatformHeaders/qcocoanativecontext.h> #import <Cocoa/Cocoa.h> @@ -117,11 +118,33 @@ static void updateFormatFromContext(QSurfaceFormat *format) format->setProfile(QSurfaceFormat::CompatibilityProfile); } -QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share) +QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, + const QVariant &nativeHandle) : m_context(nil), m_shareContext(nil), m_format(format) { + if (!nativeHandle.isNull()) { + if (!nativeHandle.canConvert<QCocoaNativeContext>()) { + qWarning("QCocoaGLContext: Requires a QCocoaNativeContext"); + return; + } + QCocoaNativeContext handle = nativeHandle.value<QCocoaNativeContext>(); + NSOpenGLContext *context = handle.context(); + if (!context) { + qWarning("QCocoaGLContext: No NSOpenGLContext given"); + return; + } + m_context = context; + [m_context retain]; + m_shareContext = share ? static_cast<QCocoaGLContext *>(share)->nsOpenGLContext() : nil; + // OpenGL surfaces can be ordered either above(default) or below the NSWindow. + const GLint order = qt_mac_resolveOption(1, "QT_MAC_OPENGL_SURFACE_ORDER"); + [m_context setValues:&order forParameter:NSOpenGLCPSurfaceOrder]; + updateSurfaceFormat(); + return; + } + // we only support OpenGL contexts under Cocoa if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType) m_format.setRenderableType(QSurfaceFormat::OpenGL); @@ -168,6 +191,11 @@ QCocoaGLContext::~QCocoaGLContext() [m_context release]; } +QVariant QCocoaGLContext::nativeHandle() const +{ + return QVariant::fromValue<QCocoaNativeContext>(QCocoaNativeContext(m_context)); +} + // Match up with createNSOpenGLPixelFormat! QSurfaceFormat QCocoaGLContext::format() const { diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 3b72184d83..d692a179fd 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -80,6 +80,7 @@ NSRect qt_mac_toNSRect(const QRect &rect); QRect qt_mac_toQRect(const NSRect &rect); QColor qt_mac_toQColor(const NSColor *color); +QColor qt_mac_toQColor(CGColorRef color); // Creates a mutable shape, it's the caller's responsibility to release. diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 9850f83dea..526204a414 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -225,6 +225,24 @@ QColor qt_mac_toQColor(const NSColor *color) return qtColor; } +QColor qt_mac_toQColor(CGColorRef color) +{ + QColor qtColor; + CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color)); + const CGFloat *components = CGColorGetComponents(color); + if (model == kCGColorSpaceModelRGB) { + qtColor.setRgbF(components[0], components[1], components[2], components[3]); + } else if (model == kCGColorSpaceModelCMYK) { + qtColor.setCmykF(components[0], components[1], components[2], components[3]); + } else if (model == kCGColorSpaceModelMonochrome) { + qtColor.setRgbF(components[0], components[0], components[0], components[1]); + } else { + // Colorspace we can't deal with. + qWarning("Qt: qt_mac_toQColor: cannot convert from colorspace model: %d", model); + Q_ASSERT(false); + } + return qtColor; +} // Use this method to keep all the information in the TextSegment. As long as it is ordered // we are in OK shape, and we can influence that ourselves. diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 07b73c1a7a..5ca2ccc571 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -113,7 +113,9 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; +#ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; +#endif QPlatformBackingStore *createPlatformBackingStore(QWindow *widget) const; QAbstractEventDispatcher *createEventDispatcher() const; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index fca7fa042c..4be49ed68f 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -420,30 +420,37 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons { switch (cap) { case ThreadedPixmaps: +#ifndef QT_NO_OPENGL case OpenGL: case ThreadedOpenGL: case BufferQueueingOpenGL: +#endif case WindowMasks: case MultipleWindows: case ForeignWindows: case RasterGLSurface: + case ApplicationState: return true; default: return QPlatformIntegration::hasCapability(cap); } } - - QPlatformWindow *QCocoaIntegration::createPlatformWindow(QWindow *window) const { return new QCocoaWindow(window); } +#ifndef QT_NO_OPENGL QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - return new QCocoaGLContext(context->format(), context->shareHandle()); + QCocoaGLContext *glContext = new QCocoaGLContext(context->format(), + context->shareHandle(), + context->nativeHandle()); + context->setNativeHandle(glContext->nativeHandle()); + return glContext; } +#endif QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *window) const { diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h index 54e45a1d99..da60afd4e7 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h @@ -61,15 +61,19 @@ class QCocoaNativeInterface : public QPlatformNativeInterface public: QCocoaNativeInterface(); +#ifndef QT_NO_OPENGL void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context); +#endif void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); NativeResourceForIntegrationFunction nativeResourceFunctionForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; Q_INVOKABLE void beep(); +#ifndef QT_NO_OPENGL static void *cglContextForContext(QOpenGLContext *context); static void *nsOpenGLContextForContext(QOpenGLContext* context); +#endif public Q_SLOTS: void onAppFocusWindowChanged(QWindow *window); diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index e09c31231d..7b314665de 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -40,7 +40,6 @@ ****************************************************************************/ #include "qcocoanativeinterface.h" -#include "qcocoaglcontext.h" #include "qcocoawindow.h" #include "qcocoamenu.h" #include "qcocoamenubar.h" @@ -53,8 +52,11 @@ #include <qpixmap.h> #include <qpa/qplatformwindow.h> #include "qsurfaceformat.h" +#ifndef QT_NO_OPENGL #include <qpa/qplatformopenglcontext.h> #include "qopenglcontext.h" +#include "qcocoaglcontext.h" +#endif #include "qguiapplication.h" #include <qdebug.h> @@ -72,6 +74,7 @@ QCocoaNativeInterface::QCocoaNativeInterface() { } +#ifndef QT_NO_OPENGL void *QCocoaNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) { if (!context) @@ -83,16 +86,19 @@ void *QCocoaNativeInterface::nativeResourceForContext(const QByteArray &resource return 0; } +#endif void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) { if (!window->handle()) return 0; - if (resourceString == "nsopenglcontext") { - return static_cast<QCocoaWindow *>(window->handle())->currentContext()->nsOpenGLContext(); - } else if (resourceString == "nsview") { + if (resourceString == "nsview") { return static_cast<QCocoaWindow *>(window->handle())->m_contentView; +#ifndef QT_NO_OPENGL + } else if (resourceString == "nsopenglcontext") { + return static_cast<QCocoaWindow *>(window->handle())->currentContext()->nsOpenGLContext(); +#endif } else if (resourceString == "nswindow") { return static_cast<QCocoaWindow *>(window->handle())->m_nsWindow; } @@ -198,6 +204,7 @@ void QCocoaNativeInterface::onAppFocusWindowChanged(QWindow *window) QCocoaMenuBar::updateMenuBarImmediately(); } +#ifndef QT_NO_OPENGL void *QCocoaNativeInterface::cglContextForContext(QOpenGLContext* context) { NSOpenGLContext *nsOpenGLContext = static_cast<NSOpenGLContext*>(nsOpenGLContextForContext(context)); @@ -216,6 +223,7 @@ void *QCocoaNativeInterface::nsOpenGLContextForContext(QOpenGLContext* context) } return 0; } +#endif void QCocoaNativeInterface::addToMimeList(void *macPasteboardMime) { diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm index f18be8b69c..26aa871998 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -41,6 +41,8 @@ #include "qcocoasystemsettings.h" +#include "qcocoahelpers.h" + #include <QtCore/private/qcore_mac_p.h> #include <QtGui/qfont.h> @@ -48,30 +50,11 @@ QT_BEGIN_NAMESPACE -QColor qt_mac_colorFromCGColor(CGColorRef cgcolor) -{ - QColor pc; - CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(cgcolor)); - const CGFloat *components = CGColorGetComponents(cgcolor); - if (model == kCGColorSpaceModelRGB) { - pc.setRgbF(components[0], components[1], components[2], components[3]); - } else if (model == kCGColorSpaceModelCMYK) { - pc.setCmykF(components[0], components[1], components[2], components[3]); - } else if (model == kCGColorSpaceModelMonochrome) { - pc.setRgbF(components[0], components[0], components[0], components[1]); - } else { - // Colorspace we can't deal with. - qWarning("Qt: qcolorFromCGColor: cannot convert from colorspace model: %d", model); - Q_ASSERT(false); - } - return pc; -} - QColor qt_mac_colorForTheme(ThemeBrush brush) { QCFType<CGColorRef> cgClr = 0; HIThemeBrushCreateCGColor(brush, &cgClr); - return qt_mac_colorFromCGColor(cgClr); + return qt_mac_toQColor(cgClr); } QColor qt_mac_colorForThemeTextColor(ThemeTextColor themeColor) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 7a21f7a8d3..8f885ab5f3 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -47,7 +47,9 @@ #include <qpa/qplatformwindow.h> #include <QRect> +#ifndef QT_NO_OPENGL #include "qcocoaglcontext.h" +#endif #include "qnsview.h" #include "qt_mac_p.h" @@ -201,8 +203,10 @@ public: void setWindowShadow(Qt::WindowFlags flags); void setWindowZoomButton(Qt::WindowFlags flags); +#ifndef QT_NO_OPENGL void setCurrentContext(QCocoaGLContext *context); QCocoaGLContext *currentContext() const; +#endif bool setWindowModified(bool modified) Q_DECL_OVERRIDE; @@ -272,7 +276,9 @@ public: // for QNSView bool m_inConstructor; bool m_inSetVisible; +#ifndef QT_NO_OPENGL QCocoaGLContext *m_glContext; +#endif QCocoaMenuBar *m_menubar; NSCursor *m_windowCursor; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 4d0458a4aa..29b983cd89 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -43,7 +43,9 @@ #include "qnswindowdelegate.h" #include "qcocoaautoreleasepool.h" #include "qcocoaeventdispatcher.h" +#ifndef QT_NO_OPENGL #include "qcocoaglcontext.h" +#endif #include "qcocoahelpers.h" #include "qcocoanativeinterface.h" #include "qnsview.h" @@ -373,7 +375,9 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_windowUnderMouse(false) , m_inConstructor(true) , m_inSetVisible(false) +#ifndef QT_NO_OPENGL , m_glContext(0) +#endif , m_menubar(0) , m_windowCursor(0) , m_hasModalSession(false) @@ -712,8 +716,10 @@ void QCocoaWindow::setVisible(bool visible) [m_contentView setHidden:NO]; } else { // qDebug() << "close" << this; +#ifndef QT_NO_OPENGL if (m_glContext) m_glContext->windowWasHidden(); +#endif QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher()); QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = 0; if (cocoaEventDispatcher) @@ -1224,6 +1230,7 @@ bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const return ((type & Qt::Popup) == Qt::Popup); } +#ifndef QT_NO_OPENGL void QCocoaWindow::setCurrentContext(QCocoaGLContext *context) { m_glContext = context; @@ -1233,6 +1240,7 @@ QCocoaGLContext *QCocoaWindow::currentContext() const { return m_glContext; } +#endif void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) { diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 5387f2a825..a75e366a73 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -72,15 +72,19 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QNSViewMouseMoveHelper); bool m_sendUpAsRightButton; Qt::KeyboardModifiers currentWheelModifiers; bool m_subscribesForGlobalFrameNotifications; +#ifndef QT_NO_OPENGL QCocoaGLContext *m_glContext; bool m_shouldSetGLContextinDrawRect; +#endif NSString *m_inputSource; QNSViewMouseMoveHelper *m_mouseMoveHelper; } - (id)init; - (id)initWithQWindow:(QWindow *)window platformWindow:(QCocoaWindow *) platformWindow; +#ifndef QT_NO_OPENGL - (void)setQCocoaGLContext:(QCocoaGLContext *)context; +#endif - (void)flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset; - (void)setMaskRegion:(const QRegion *)region; - (void)invalidateWindowShadowIfNeeded; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index a18ee7ff71..011a9ba71a 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -57,13 +57,17 @@ #include <QtCore/QDebug> #include <private/qguiapplication_p.h> #include "qcocoabackingstore.h" +#ifndef QT_NO_OPENGL #include "qcocoaglcontext.h" +#endif #include "qcocoaintegration.h" #ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR #include <accessibilityinspector.h> #endif +Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.tabletsupport") + static QTouchDevice *touchDevice = 0; // ### HACK Remove once 10.8 is unsupported @@ -143,8 +147,10 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_frameStrutButtons = Qt::NoButton; m_sendKeyEvent = false; m_subscribesForGlobalFrameNotifications = false; +#ifndef QT_NO_OPENGL m_glContext = 0; m_shouldSetGLContextinDrawRect = false; +#endif currentCustomDragTypes = 0; m_sendUpAsRightButton = false; m_inputSource = 0; @@ -210,6 +216,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; return self; } +#ifndef QT_NO_OPENGL - (void) setQCocoaGLContext:(QCocoaGLContext *)context { m_glContext = context; @@ -231,6 +238,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; object:self]; } } +#endif - (void) globalFrameChanged:(NSNotification*)notification { @@ -516,10 +524,12 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; - (void) drawRect:(NSRect)dirtyRect { +#ifndef QT_NO_OPENGL if (m_glContext && m_shouldSetGLContextinDrawRect) { [m_glContext->nsOpenGLContext() setView:self]; m_shouldSetGLContextinDrawRect = false; } +#endif if (m_platformWindow->m_drawContentBorderGradient) NSDrawWindowBackground(dirtyRect); @@ -986,6 +996,7 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash) NSPoint tilt = [theEvent tilt]; int xTilt = qRound(tilt.x * 60.0); int yTilt = qRound(tilt.y * -60.0); + Qt::MouseButtons buttons = static_cast<Qt::MouseButtons>(static_cast<uint>([theEvent buttonMask])); qreal tangentialPressure = 0; qreal rotation = 0; int z = 0; @@ -993,14 +1004,21 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash) z = [theEvent absoluteZ]; if (deviceData.capabilityMask & 0x0800) - tangentialPressure = [theEvent tangentialPressure]; + tangentialPressure = ([theEvent tangentialPressure] * 2.0) - 1.0; - rotation = [theEvent rotation]; + rotation = 360.0 - [theEvent rotation]; + if (rotation > 180.0) + rotation -= 360.0; Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; - QWindowSystemInterface::handleTabletEvent(m_window, timestamp, down, windowPoint, screenPoint, - deviceData.device, deviceData.pointerType, pressure, xTilt, yTilt, + qCDebug(lcQpaTablet, "event on tablet %d with tool %d type %d unique ID %lld pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf", + deviceId, deviceData.device, deviceData.pointerType, deviceData.uid, + windowPoint.x(), windowPoint.y(), screenPoint.x(), screenPoint.y(), + static_cast<uint>(buttons), pressure, xTilt, yTilt, rotation); + + QWindowSystemInterface::handleTabletEvent(m_window, timestamp, windowPoint, screenPoint, + deviceData.device, deviceData.pointerType, buttons, pressure, xTilt, yTilt, tangentialPressure, rotation, z, deviceData.uid, keyboardModifiers); } @@ -1092,6 +1110,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) tabletDeviceDataHash->remove(deviceId); } + qCDebug(lcQpaTablet, "proximity change on tablet %d: current tool %d type %d unique ID %lld", + deviceId, deviceData.device, deviceData.pointerType, deviceData.uid); + if (entering) { QWindowSystemInterface::handleTabletEnterProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid); } else { diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm index d18a01b11c..a02b074771 100644 --- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -59,7 +59,7 @@ return nil; QAccessible::Id childId = QAccessible::uniqueId(m_window->accessibleRoot()); - return [QCocoaAccessibleElement elementWithId: childId]; + return [QMacAccessibilityElement elementWithId: childId]; } // The QNSView is a container that the user does not interact directly with: diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index f4cd071ab7..d48cbdfac8 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -1084,6 +1084,10 @@ void QCoreGraphicsPaintEngine::drawTextItem(const QPointF &pos, const QTextItem if (textAA != lineAA) CGContextSetShouldAntialias(d->hd, textAA); + const bool smoothing = textAA && !(fe->fontDef.styleStrategy & QFont::NoSubpixelAntialias); + if (d->disabledSmoothFonts == smoothing) + CGContextSetShouldSmoothFonts(d->hd, smoothing); + if (ti.glyphs.numGlyphs) { switch (fe->type()) { case QFontEngine::Mac: @@ -1100,6 +1104,9 @@ void QCoreGraphicsPaintEngine::drawTextItem(const QPointF &pos, const QTextItem if (textAA != lineAA) CGContextSetShouldAntialias(d->hd, !textAA); + if (smoothing == d->disabledSmoothFonts) + CGContextSetShouldSmoothFonts(d->hd, !d->disabledSmoothFonts); + updatePen(oldPen); updateBrush(oldBrush, oldBrushOrigin); } diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro index 03997f2737..8f2ccc3aa6 100644 --- a/src/plugins/platforms/direct2d/direct2d.pro +++ b/src/plugins/platforms/direct2d/direct2d.pro @@ -9,7 +9,7 @@ QT *= core-private QT *= gui-private QT *= platformsupport-private -LIBS *= -ld2d1 -ld3d11 -ldwrite -lVersion +LIBS *= -ld2d1 -ld3d11 -ldwrite -lVersion -lgdi32 include(../windows/windows.pri) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h index 1936ef0622..702ef7af92 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h @@ -60,22 +60,22 @@ public: QWindowsDirect2DPlatformPixmap(PixelType pixelType, QWindowsDirect2DBitmap *bitmap); ~QWindowsDirect2DPlatformPixmap(); - virtual void resize(int width, int height); + void resize(int width, int height) Q_DECL_OVERRIDE; virtual void fromImage(const QImage &image, Qt::ImageConversionFlags flags); - virtual int metric(QPaintDevice::PaintDeviceMetric metric) const; - virtual void fill(const QColor &color); + int metric(QPaintDevice::PaintDeviceMetric metric) const Q_DECL_OVERRIDE; + void fill(const QColor &color) Q_DECL_OVERRIDE; - virtual bool hasAlphaChannel() const; + bool hasAlphaChannel() const Q_DECL_OVERRIDE; - virtual QImage toImage() const; - virtual QImage toImage(const QRect &rect) const; + QImage toImage() const Q_DECL_OVERRIDE; + QImage toImage(const QRect &rect) const Q_DECL_OVERRIDE; - virtual QPaintEngine* paintEngine() const; + QPaintEngine* paintEngine() const Q_DECL_OVERRIDE; - virtual qreal devicePixelRatio() const; - virtual void setDevicePixelRatio(qreal scaleFactor); + qreal devicePixelRatio() const Q_DECL_OVERRIDE; + void setDevicePixelRatio(qreal scaleFactor) Q_DECL_OVERRIDE; QWindowsDirect2DBitmap *bitmap() const; diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp index 4d443b91e3..71c3c1e59b 100644 --- a/src/plugins/platforms/eglfs/qeglfscontext.cpp +++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp @@ -42,7 +42,6 @@ #include "qeglfscontext.h" #include "qeglfswindow.h" #include "qeglfshooks.h" -#include "qeglfsintegration.h" #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtPlatformSupport/private/qeglpbuffer_p.h> @@ -52,9 +51,9 @@ QT_BEGIN_NAMESPACE -QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display) - : QEGLPlatformContext(format, share, display, - QEglFSIntegration::chooseConfig(display, format)) +QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, + EGLConfig *config, const QVariant &nativeHandle) + : QEGLPlatformContext(format, share, display, config, nativeHandle) { } diff --git a/src/plugins/platforms/eglfs/qeglfscontext.h b/src/plugins/platforms/eglfs/qeglfscontext.h index 5d406f09f1..d378b7818b 100644 --- a/src/plugins/platforms/eglfs/qeglfscontext.h +++ b/src/plugins/platforms/eglfs/qeglfscontext.h @@ -43,13 +43,15 @@ #define QEGLFSCONTEXT_H #include <QtPlatformSupport/private/qeglplatformcontext_p.h> +#include <QtCore/QVariant> QT_BEGIN_NAMESPACE class QEglFSContext : public QEGLPlatformContext { public: - QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display); + QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, + EGLConfig *config, const QVariant &nativeHandle); EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) Q_DECL_OVERRIDE; void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; }; diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp index 2941806f17..d770ea763a 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -50,6 +50,7 @@ #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtPlatformSupport/private/qeglplatformcontext_p.h> #include <QtPlatformSupport/private/qeglpbuffer_p.h> +#include <QtPlatformHeaders/QEGLNativeContext> #include <qpa/qplatformwindow.h> #include <QtGui/QSurfaceFormat> @@ -115,9 +116,20 @@ QEGLPlatformWindow *QEglFSIntegration::createWindow(QWindow *window) const QEGLPlatformContext *QEglFSIntegration::createContext(const QSurfaceFormat &format, QPlatformOpenGLContext *shareContext, - EGLDisplay display) const + EGLDisplay display, + QVariant *nativeHandle) const { - return new QEglFSContext(QEglFSHooks::hooks()->surfaceFormatFor(format), shareContext, display); + QEglFSContext *ctx; + if (!nativeHandle || nativeHandle->isNull()) { + EGLConfig config = QEglFSIntegration::chooseConfig(display, format); + ctx = new QEglFSContext(QEglFSHooks::hooks()->surfaceFormatFor(format), shareContext, display, + &config, QVariant()); + } else { + ctx = new QEglFSContext(QEglFSHooks::hooks()->surfaceFormatFor(format), shareContext, display, + 0, *nativeHandle); + } + *nativeHandle = QVariant::fromValue<QEGLNativeContext>(QEGLNativeContext(ctx->eglContext(), display)); + return ctx; } QPlatformOffscreenSurface *QEglFSIntegration::createOffscreenSurface(EGLDisplay display, diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h index 99dda1ea96..fea05cd400 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsintegration.h @@ -66,7 +66,8 @@ protected: QEGLPlatformWindow *createWindow(QWindow *window) const Q_DECL_OVERRIDE; QEGLPlatformContext *createContext(const QSurfaceFormat &format, QPlatformOpenGLContext *shareContext, - EGLDisplay display) const Q_DECL_OVERRIDE; + EGLDisplay display, + QVariant *nativeHandle) const Q_DECL_OVERRIDE; QPlatformOffscreenSurface *createOffscreenSurface(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *surface) const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index 2d36c0b58e..a0150b7ade 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -82,8 +82,10 @@ void QEglFSWindow::create() // they will be composited onto the root window's surface. QEglFSScreen *screen = this->screen(); if (screen->primarySurface() != EGL_NO_SURFACE) { - if (isRaster() && screen->compositingWindow()) + if (isRaster() && screen->compositingWindow()) { + m_format = screen->compositingWindow()->format(); return; + } #if !defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK) // We can have either a single OpenGL window or multiple raster windows. diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro index ffc4ff9b12..ad9912a8d0 100644 --- a/src/plugins/platforms/ios/ios.pro +++ b/src/plugins/platforms/ios/ios.pro @@ -23,7 +23,10 @@ OBJECTIVE_SOURCES = \ qiostheme.mm \ qiosglobal.mm \ qiosservices.mm \ - qiosclipboard.mm + quiview.mm \ + qiosclipboard.mm \ + quiaccessibilityelement.mm \ + qiosplatformaccessibility.mm \ HEADERS = \ qiosintegration.h \ @@ -40,7 +43,10 @@ HEADERS = \ qiosglobal.h \ qiosservices.h \ quiview.h \ - qiosclipboard.h + qiosclipboard.h \ + quiaccessibilityelement.h \ + qiosplatformaccessibility.h \ OTHER_FILES = \ - quiview_textinput.mm + quiview_textinput.mm \ + quiview_accessibility.mm diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.h b/src/plugins/platforms/ios/qiosapplicationdelegate.h index 617b740d6e..f3c5c14502 100644 --- a/src/plugins/platforms/ios/qiosapplicationdelegate.h +++ b/src/plugins/platforms/ios/qiosapplicationdelegate.h @@ -45,7 +45,4 @@ #import "qiosviewcontroller.h" @interface QIOSApplicationDelegate : UIResponder <UIApplicationDelegate> - -@property (strong, nonatomic) UIWindow *window; - @end diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm index 9cf1047a6b..ef9f924384 100644 --- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm +++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm @@ -46,47 +46,12 @@ #include "qiosviewcontroller.h" #include "qioswindow.h" -#include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> #include <QtCore/QtCore> @implementation QIOSApplicationDelegate -@synthesize window; - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - Q_UNUSED(application); - Q_UNUSED(launchOptions); - - self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; - self.window.rootViewController = [[[QIOSViewController alloc] init] autorelease]; - -#if QT_IOS_DEPLOYMENT_TARGET_BELOW(__IPHONE_7_0) - QSysInfo::MacVersion iosVersion = QSysInfo::MacintoshVersion; - - // We prefer to keep the root viewcontroller in fullscreen layout, so that - // we don't have to compensate for the viewcontroller position. This also - // gives us the same behavior on iOS 5/6 as on iOS 7, where full screen layout - // is the only way. - if (iosVersion < QSysInfo::MV_IOS_7_0) - self.window.rootViewController.wantsFullScreenLayout = YES; - - // Use translucent statusbar by default on iOS6 iPhones (unless the user changed - // the default in the Info.plist), so that windows placed under the stausbar are - // still visible, just like on iOS7. - if (iosVersion >= QSysInfo::MV_IOS_6_0 && iosVersion < QSysInfo::MV_IOS_7_0 - && [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone - && [UIApplication sharedApplication].statusBarStyle == UIStatusBarStyleDefault) - [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent]; -#endif - - self.window.hidden = NO; - - return YES; -} - - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { Q_UNUSED(application); @@ -96,17 +61,13 @@ if (!QGuiApplication::instance()) return NO; - QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration()); + QIOSIntegration *iosIntegration = QIOSIntegration::instance(); + Q_ASSERT(iosIntegration); + QIOSServices *iosServices = static_cast<QIOSServices *>(iosIntegration->services()); return iosServices->handleUrl(QUrl::fromNSURL(url)); } -- (void)dealloc -{ - [window release]; - [super dealloc]; -} - @end diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm index ddee52196a..4083c2d5a9 100644 --- a/src/plugins/platforms/ios/qioscontext.mm +++ b/src/plugins/platforms/ios/qioscontext.mm @@ -47,6 +47,7 @@ #include <QtGui/QOpenGLContext> #import <OpenGLES/EAGL.h> +#import <OpenGLES/ES2/glext.h> #import <QuartzCore/CAEAGLLayer.h> QIOSContext::QIOSContext(QOpenGLContext *context) diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h index 956c112399..89ca0349d9 100644 --- a/src/plugins/platforms/ios/qiosintegration.h +++ b/src/plugins/platforms/ios/qiosintegration.h @@ -82,14 +82,20 @@ public: void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); QTouchDevice *touchDevice(); + QPlatformAccessibility *accessibility() const Q_DECL_OVERRIDE; + + void addScreen(QPlatformScreen *screen) { screenAdded(screen); } + + static QIOSIntegration *instance(); + private: QPlatformFontDatabase *m_fontDatabase; QPlatformClipboard *m_clipboard; QPlatformInputContext *m_inputContext; - QPlatformScreen *m_screen; QTouchDevice *m_touchDevice; QIOSApplicationState m_applicationState; QIOSServices *m_platformServices; + mutable QPlatformAccessibility *m_accessibility; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index 0fe7adff9f..9a722ead37 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -45,12 +45,15 @@ #include "qioswindow.h" #include "qiosbackingstore.h" #include "qiosscreen.h" +#include "qiosplatformaccessibility.h" #include "qioscontext.h" #include "qiosclipboard.h" #include "qiosinputcontext.h" #include "qiostheme.h" #include "qiosservices.h" +#include <QtGui/private/qguiapplication_p.h> + #include <qpa/qplatformoffscreensurface.h> #include <QtPlatformSupport/private/qcoretextfontdatabase_p.h> @@ -61,12 +64,17 @@ QT_BEGIN_NAMESPACE +QIOSIntegration *QIOSIntegration::instance() +{ + return static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration()); +} + QIOSIntegration::QIOSIntegration() : m_fontDatabase(new QCoreTextFontDatabase) , m_clipboard(new QIOSClipboard) - , m_inputContext(new QIOSInputContext) - , m_screen(new QIOSScreen(QIOSScreen::MainScreen)) + , m_inputContext(0) , m_platformServices(new QIOSServices) + , m_accessibility(0) { if (![UIApplication sharedApplication]) { qWarning() @@ -80,7 +88,11 @@ QIOSIntegration::QIOSIntegration() // Set current directory to app bundle folder QDir::setCurrent(QString::fromUtf8([[[NSBundle mainBundle] bundlePath] UTF8String])); - screenAdded(m_screen); + for (UIScreen *screen in [UIScreen screens]) + addScreen(new QIOSScreen(screen)); + + // Depends on a primary screen being present + m_inputContext = new QIOSInputContext; m_touchDevice = new QTouchDevice; m_touchDevice->setType(QTouchDevice::TouchScreen); @@ -101,11 +113,14 @@ QIOSIntegration::~QIOSIntegration() delete m_inputContext; m_inputContext = 0; - delete m_screen; - m_screen = 0; + foreach (QScreen *screen, QGuiApplication::screens()) + delete screen->handle(); delete m_platformServices; m_platformServices = 0; + + delete m_accessibility; + m_accessibility = 0; } bool QIOSIntegration::hasCapability(Capability cap) const @@ -229,4 +244,11 @@ QTouchDevice *QIOSIntegration::touchDevice() return m_touchDevice; } +QPlatformAccessibility *QIOSIntegration::accessibility() const +{ + if (!m_accessibility) + m_accessibility = new QIOSPlatformAccessibility; + return m_accessibility; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtplatformtheme.h b/src/plugins/platforms/ios/qiosplatformaccessibility.h index f4a61982b2..beb0d006e1 100644 --- a/src/plugins/platforms/winrt/qwinrtplatformtheme.h +++ b/src/plugins/platforms/ios/qiosplatformaccessibility.h @@ -39,22 +39,22 @@ ** ****************************************************************************/ -#ifndef QWINRTPLATFORMTHEME_H -#define QWINRTPLATFORMTHEME_H +#ifndef QIOSPLATFORMACCESSIBILITY_H +#define QIOSPLATFORMACCESSIBILITY_H -#include <qpa/qplatformtheme.h> +#include <qpa/qplatformaccessibility.h> QT_BEGIN_NAMESPACE -class QWinRTPlatformTheme : public QPlatformTheme +class QIOSPlatformAccessibility: public QPlatformAccessibility { public: - QWinRTPlatformTheme(); + QIOSPlatformAccessibility(); + ~QIOSPlatformAccessibility(); - bool usePlatformNativeDialog(DialogType type) const; - QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const; + virtual void notifyAccessibilityUpdate(QAccessibleEvent *event); }; QT_END_NAMESPACE -#endif // QWINRTPLATFORMTHEME_H +#endif diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.mm b/src/plugins/platforms/ios/qiosplatformaccessibility.mm new file mode 100644 index 0000000000..db579ba559 --- /dev/null +++ b/src/plugins/platforms/ios/qiosplatformaccessibility.mm @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 "qiosplatformaccessibility.h" + +#include <QtGui/QtGui> +#include "qioswindow.h" + +QIOSPlatformAccessibility::QIOSPlatformAccessibility() +{} + +QIOSPlatformAccessibility::~QIOSPlatformAccessibility() +{} + + +void invalidateCache(QAccessibleInterface *iface) +{ + if (!iface || !iface->isValid()) { + qWarning() << "invalid accessible interface: " << iface; + return; + } + + QWindow *win = 0; + QAccessibleInterface *parent = iface; + do { + win = parent->window(); + parent = parent->parent(); + } while (!win && parent); + Q_ASSERT(win && win->handle()); + QIOSWindow *window = static_cast<QIOSWindow*>(win->handle()); + window->clearAccessibleCache(); +} + + +void QIOSPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) +{ + switch (event->type()) { + case QAccessible::ObjectCreated: + case QAccessible::ObjectShow: + case QAccessible::ObjectHide: + case QAccessible::ObjectDestroyed: + invalidateCache(event->accessibleInterface()); + break; + default: + break; + } +} diff --git a/src/plugins/platforms/ios/qiosscreen.h b/src/plugins/platforms/ios/qiosscreen.h index 173bd11719..9c7d53dcd6 100644 --- a/src/plugins/platforms/ios/qiosscreen.h +++ b/src/plugins/platforms/ios/qiosscreen.h @@ -55,11 +55,9 @@ class QIOSScreen : public QObject, public QPlatformScreen Q_OBJECT public: - QIOSScreen(unsigned int screenIndex); + QIOSScreen(UIScreen *screen); ~QIOSScreen(); - enum ScreenIndex { MainScreen = 0 }; - QRect geometry() const; QRect availableGeometry() const; int depth() const; @@ -82,6 +80,7 @@ public slots: private: UIScreen *m_uiScreen; + UIWindow *m_uiWindow; QRect m_geometry; QRect m_availableGeometry; int m_depth; diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm index 5331d05ae9..e876665431 100644 --- a/src/plugins/platforms/ios/qiosscreen.mm +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qiosglobal.h" +#include "qiosintegration.h" #include "qiosscreen.h" #include "qioswindow.h" #include <qpa/qwindowsysteminterface.h> @@ -48,6 +49,63 @@ #include <sys/sysctl.h> +// ------------------------------------------------------------------------- + +static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) +{ + foreach (QScreen *screen, QGuiApplication::screens()) { + QIOSScreen *platformScreen = static_cast<QIOSScreen *>(screen->handle()); + if (platformScreen->uiScreen() == uiScreen) + return platformScreen; + } + + return 0; +} + +@interface QIOSScreenTracker : NSObject +@end + +@implementation QIOSScreenTracker + ++ (void)load +{ + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserver:self selector:@selector(screenConnected:) + name:UIScreenDidConnectNotification object:nil]; + [center addObserver:self selector:@selector(screenDisconnected:) + name:UIScreenDidDisconnectNotification object:nil]; + [center addObserver:self selector:@selector(screenModeChanged:) + name:UIScreenModeDidChangeNotification object:nil]; +} + ++ (void)screenConnected:(NSNotification*)notification +{ + QIOSIntegration *integration = QIOSIntegration::instance(); + Q_ASSERT_X(integration, Q_FUNC_INFO, "Screen connected before QIOSIntegration creation"); + + integration->addScreen(new QIOSScreen([notification object])); +} + ++ (void)screenDisconnected:(NSNotification*)notification +{ + QIOSScreen *screen = qtPlatformScreenFor([notification object]); + Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen disconnected that we didn't know about"); + + delete screen; +} + ++ (void)screenModeChanged:(NSNotification*)notification +{ + QIOSScreen *screen = qtPlatformScreenFor([notification object]); + Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen changed that we didn't know about"); + + screen->updateProperties(); +} + +@end + +// ------------------------------------------------------------------------- + @interface QIOSOrientationListener : NSObject { @public QIOSScreen *m_screen; @@ -99,6 +157,8 @@ @end +// ------------------------------------------------------------------------- + /*! Returns the model identifier of the device. @@ -118,27 +178,51 @@ static QString deviceModelIdentifier() return QString::fromLatin1(value); } -QIOSScreen::QIOSScreen(unsigned int screenIndex) +QIOSScreen::QIOSScreen(UIScreen *screen) : QPlatformScreen() - , m_uiScreen([[UIScreen screens] count] > screenIndex - ? [[UIScreen screens] objectAtIndex:screenIndex] - : [UIScreen mainScreen]) + , m_uiScreen(screen) + , m_uiWindow(0) , m_orientationListener(0) { - QString deviceIdentifier = deviceModelIdentifier(); + for (UIWindow *existingWindow in [[UIApplication sharedApplication] windows]) { + if (existingWindow.screen == m_uiScreen) { + m_uiWindow = [m_uiWindow retain]; + break; + } + } - if (deviceIdentifier == QStringLiteral("iPhone2,1") /* iPhone 3GS */ - || deviceIdentifier == QStringLiteral("iPod3,1") /* iPod touch 3G */) { - m_depth = 18; - } else { - m_depth = 24; + if (!m_uiWindow) { + // Create a window and associated view-controller that we can use + m_uiWindow = [[UIWindow alloc] initWithFrame:[m_uiScreen bounds]]; + m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease]; + + // FIXME: Only do once windows are added to the screen, and for any screen + if (screen == [UIScreen mainScreen]) { + m_uiWindow.screen = m_uiScreen; + m_uiWindow.hidden = NO; + } } - if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad - && !deviceIdentifier.contains(QRegularExpression("^iPad2,[567]$")) /* excluding iPad Mini */) { - m_unscaledDpi = 132; + if (screen == [UIScreen mainScreen]) { + QString deviceIdentifier = deviceModelIdentifier(); + + if (deviceIdentifier == QStringLiteral("iPhone2,1") /* iPhone 3GS */ + || deviceIdentifier == QStringLiteral("iPod3,1") /* iPod touch 3G */) { + m_depth = 18; + } else { + m_depth = 24; + } + + if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad + && !deviceIdentifier.contains(QRegularExpression("^iPad2,[567]$")) /* excluding iPad Mini */) { + m_unscaledDpi = 132; + } else { + m_unscaledDpi = 163; // Regular iPhone DPI + } } else { - m_unscaledDpi = 163; // Regular iPhone DPI + // External display, hard to say + m_depth = 24; + m_unscaledDpi = 96; } connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QIOSScreen::updateStatusBarVisibility); @@ -149,17 +233,12 @@ QIOSScreen::QIOSScreen(unsigned int screenIndex) QIOSScreen::~QIOSScreen() { [m_orientationListener release]; + [m_uiWindow release]; } void QIOSScreen::updateProperties() { - UIWindow *uiWindow = 0; - for (uiWindow in [[UIApplication sharedApplication] windows]) { - if (uiWindow.screen == m_uiScreen) - break; - } - - bool inPortrait = UIInterfaceOrientationIsPortrait(uiWindow.rootViewController.interfaceOrientation); + bool inPortrait = UIInterfaceOrientationIsPortrait(m_uiWindow.rootViewController.interfaceOrientation); QRect geometry = inPortrait ? fromCGRect(m_uiScreen.bounds).toRect() : QRect(m_uiScreen.bounds.origin.x, m_uiScreen.bounds.origin.y, m_uiScreen.bounds.size.height, m_uiScreen.bounds.size.width); diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h index a0017808d3..5e95cdd3ee 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.h +++ b/src/plugins/platforms/ios/qiosviewcontroller.h @@ -41,7 +41,13 @@ #import <UIKit/UIKit.h> -@interface QIOSViewController : UIViewController +class QIOSScreen; + +@interface QIOSViewController : UIViewController { + QIOSScreen *m_screen; +} + +- (id)initWithQIOSScreen:(QIOSScreen *)screen; - (BOOL)prefersStatusBarHidden; @end diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index 2fe679fc20..73f1b51b83 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -53,6 +53,35 @@ @implementation QIOSViewController +- (id)initWithQIOSScreen:(QIOSScreen *)screen +{ + if (self = [self init]) { + m_screen = screen; + +#if QT_IOS_DEPLOYMENT_TARGET_BELOW(__IPHONE_7_0) + QSysInfo::MacVersion iosVersion = QSysInfo::MacintoshVersion; + + // We prefer to keep the root viewcontroller in fullscreen layout, so that + // we don't have to compensate for the viewcontroller position. This also + // gives us the same behavior on iOS 5/6 as on iOS 7, where full screen layout + // is the only way. + if (iosVersion < QSysInfo::MV_IOS_7_0) + self.wantsFullScreenLayout = YES; + + // Use translucent statusbar by default on iOS6 iPhones (unless the user changed + // the default in the Info.plist), so that windows placed under the stausbar are + // still visible, just like on iOS7. + if (screen->uiScreen() == [UIScreen mainScreen] + && iosVersion >= QSysInfo::MV_IOS_6_0 && iosVersion < QSysInfo::MV_IOS_7_0 + && [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone + && [UIApplication sharedApplication].statusBarStyle == UIStatusBarStyleDefault) + [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent]; +#endif + } + + return self; +} + -(BOOL)shouldAutorotate { // Until a proper orientation and rotation API is in place, we always auto rotate. @@ -85,8 +114,7 @@ if (!QCoreApplication::instance()) return; // FIXME: Store orientation for later (?) - QIOSScreen *qiosScreen = static_cast<QIOSScreen *>(QGuiApplication::primaryScreen()->handle()); - qiosScreen->updateProperties(); + m_screen->updateProperties(); } #if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0) diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h index 6b6892e6e4..bcff3e202c 100644 --- a/src/plugins/platforms/ios/qioswindow.h +++ b/src/plugins/platforms/ios/qioswindow.h @@ -87,6 +87,8 @@ public: WId winId() const { return WId(m_view); }; + void clearAccessibleCache(); + private: void applicationStateChanged(Qt::ApplicationState state); void applyGeometry(const QRect &rect); diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 6f5c96cfc1..76bd9bb2b5 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -39,323 +39,23 @@ ** ****************************************************************************/ -#include "qiosglobal.h" #include "qioswindow.h" -#include "quiview.h" + +#include "qiosapplicationdelegate.h" #include "qioscontext.h" -#include "qiosinputcontext.h" +#include "qiosglobal.h" +#include "qiosintegration.h" #include "qiosscreen.h" -#include "qiosapplicationdelegate.h" #include "qiosviewcontroller.h" -#include "qiosintegration.h" -#include <QtGui/private/qguiapplication_p.h> +#include "quiview.h" + #include <QtGui/private/qwindow_p.h> #include <qpa/qplatformintegration.h> #import <QuartzCore/CAEAGLLayer.h> -#include <QtGui/QKeyEvent> -#include <qpa/qwindowsysteminterface.h> - #include <QtDebug> -// Include category as an alternative to using -ObjC (Apple QA1490) -#include "quiview_textinput.mm" - -@implementation QUIView - -@synthesize autocapitalizationType; -@synthesize autocorrectionType; -@synthesize enablesReturnKeyAutomatically; -@synthesize keyboardAppearance; -@synthesize keyboardType; -@synthesize returnKeyType; -@synthesize secureTextEntry; - -+ (Class)layerClass -{ - return [CAEAGLLayer class]; -} - --(id)initWithQIOSWindow:(QIOSWindow *)window -{ - if (self = [self initWithFrame:toCGRect(window->geometry())]) - m_qioswindow = window; - - return self; -} - -- (id)initWithFrame:(CGRect)frame -{ - if ((self = [super initWithFrame:frame])) { - // Set up EAGL layer - CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer); - eaglLayer.opaque = TRUE; - eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking, - kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; - - if (isQtApplication()) - self.hidden = YES; - - self.multipleTouchEnabled = YES; - m_inSendEventToFocusObject = NO; - } - - return self; -} - -- (void)willMoveToWindow:(UIWindow *)newWindow -{ - // UIKIt will normally set the scale factor of a view to match the corresponding - // screen scale factor, but views backed by CAEAGLLayers need to do this manually. - self.contentScaleFactor = newWindow && newWindow.screen ? - newWindow.screen.scale : [[UIScreen mainScreen] scale]; - - // FIXME: Allow the scale factor to be customized through QSurfaceFormat. -} - -- (void)didAddSubview:(UIView *)subview -{ - if ([subview isKindOfClass:[QUIView class]]) - self.clipsToBounds = YES; -} - -- (void)willRemoveSubview:(UIView *)subview -{ - for (UIView *view in self.subviews) { - if (view != subview && [view isKindOfClass:[QUIView class]]) - return; - } - - self.clipsToBounds = NO; -} - -- (void)setNeedsDisplay -{ - [super setNeedsDisplay]; - - // We didn't implement drawRect: so we have to manually - // mark the layer as needing display. - [self.layer setNeedsDisplay]; -} - -- (void)layoutSubviews -{ - // This method is the de facto way to know that view has been resized, - // or otherwise needs invalidation of its buffers. Note though that we - // do not get this callback when the view just changes its position, so - // the position of our QWindow (and platform window) will only get updated - // when the size is also changed. - - if (!CGAffineTransformIsIdentity(self.transform)) - qWarning() << m_qioswindow->window() - << "is backed by a UIView that has a transform set. This is not supported."; - - // The original geometry requested by setGeometry() might be different - // from what we end up with after applying window constraints. - QRect requestedGeometry = m_qioswindow->geometry(); - - QRect actualGeometry; - if (m_qioswindow->window()->isTopLevel()) { - UIWindow *uiWindow = self.window; - UIView *rootView = uiWindow.rootViewController.view; - CGRect rootViewPositionInRelationToRootViewController = - [rootView convertRect:uiWindow.bounds fromView:uiWindow]; - - actualGeometry = fromCGRect(CGRectOffset([self.superview convertRect:self.frame toView:rootView], - -rootViewPositionInRelationToRootViewController.origin.x, - -rootViewPositionInRelationToRootViewController.origin.y - + rootView.bounds.origin.y)).toRect(); - } else { - actualGeometry = fromCGRect(self.frame).toRect(); - } - - // Persist the actual/new geometry so that QWindow::geometry() can - // be queried on the resize event. - m_qioswindow->QPlatformWindow::setGeometry(actualGeometry); - - QRect previousGeometry = requestedGeometry != actualGeometry ? - requestedGeometry : qt_window_private(m_qioswindow->window())->geometry; - - QWindowSystemInterface::handleGeometryChange(m_qioswindow->window(), actualGeometry, previousGeometry); - QWindowSystemInterface::flushWindowSystemEvents(); - - if (actualGeometry.size() != previousGeometry.size()) { - // Trigger expose event on resize - [self setNeedsDisplay]; - - // A new size means we also need to resize the FBO's corresponding buffers, - // but we defer that to when the application calls makeCurrent. - } -} - -- (void)displayLayer:(CALayer *)layer -{ - Q_UNUSED(layer); - Q_ASSERT(layer == self.layer); - - [self sendUpdatedExposeEvent]; -} - -- (void)sendUpdatedExposeEvent -{ - QRegion region; - - if (m_qioswindow->isExposed()) { - QSize bounds = fromCGRect(self.layer.bounds).toRect().size(); - - Q_ASSERT(m_qioswindow->geometry().size() == bounds); - Q_ASSERT(self.hidden == !m_qioswindow->window()->isVisible()); - - region = QRect(QPoint(), bounds); - } - - QWindowSystemInterface::handleExposeEvent(m_qioswindow->window(), region); - QWindowSystemInterface::flushWindowSystemEvents(); -} - -- (void)updateTouchList:(NSSet *)touches withState:(Qt::TouchPointState)state -{ - // We deliver touch events in global coordinates. But global in this respect - // means the same coordinate system that we use for describing the geometry - // of the top level QWindow we're inside. And that would be the coordinate - // system of the superview of the UIView that backs that window: - QPlatformWindow *topLevel = m_qioswindow; - while (QPlatformWindow *topLevelParent = topLevel->parent()) - topLevel = topLevelParent; - UIView *rootView = reinterpret_cast<UIView *>(topLevel->winId()).superview; - CGSize rootViewSize = rootView.frame.size; - - foreach (UITouch *uiTouch, m_activeTouches.keys()) { - QWindowSystemInterface::TouchPoint &touchPoint = m_activeTouches[uiTouch]; - if (![touches containsObject:uiTouch]) { - touchPoint.state = Qt::TouchPointStationary; - } else { - touchPoint.state = state; - touchPoint.pressure = (state == Qt::TouchPointReleased) ? 0.0 : 1.0; - QPoint touchPos = fromCGPoint([uiTouch locationInView:rootView]).toPoint(); - touchPoint.area = QRectF(touchPos, QSize(0, 0)); - touchPoint.normalPosition = QPointF(touchPos.x() / rootViewSize.width, touchPos.y() / rootViewSize.height); - } - } -} - -- (void) sendTouchEventWithTimestamp:(ulong)timeStamp -{ - // Send touch event synchronously - QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration()); - QWindowSystemInterface::handleTouchEvent(m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values()); - QWindowSystemInterface::flushWindowSystemEvents(); -} - -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event -{ - // 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 - // an id for use by Qt. - for (UITouch *touch in touches) { - Q_ASSERT(!m_activeTouches.contains(touch)); - m_activeTouches[touch].id = m_nextTouchId++; - } - - if (m_activeTouches.size() == 1) { - QPlatformWindow *topLevel = m_qioswindow; - while (QPlatformWindow *p = topLevel->parent()) - topLevel = p; - if (topLevel->window() != QGuiApplication::focusWindow()) - topLevel->requestActivateWindow(); - } - - [self updateTouchList:touches withState:Qt::TouchPointPressed]; - [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)]; -} - -- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event -{ - [self updateTouchList:touches withState:Qt::TouchPointMoved]; - [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)]; -} - -- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event -{ - [self updateTouchList:touches withState:Qt::TouchPointReleased]; - [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)]; - - // Remove ended touch points from the active set: - for (UITouch *touch in touches) - m_activeTouches.remove(touch); - if (m_activeTouches.isEmpty()) - m_nextTouchId = 0; -} - -- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event -{ - if (m_activeTouches.isEmpty()) - return; - - // When four-finger swiping, we get a touchesCancelled callback - // which includes all four touch points. The swipe gesture is - // then active until all four touches have been released, and - // we start getting touchesBegan events again. - - // When five-finger pinching, we also get a touchesCancelled - // callback with all five touch points, but the pinch gesture - // ends when the second to last finger is released from the - // screen. The last finger will not emit any more touch - // events, _but_, will contribute to starting another pinch - // gesture. That second pinch gesture will _not_ trigger a - // touchesCancelled event when starting, but as each finger - // is released, and we may get touchesMoved events for the - // remaining fingers. [event allTouches] also contains one - // less touch point than it should, so this behavior is - // likely a bug in the iOS system gesture recognizer, but we - // have to take it into account when maintaining the Qt state. - // We do this by assuming that there are no cases where a - // sub-set of the active touch events are intentionally cancelled. - - if (touches && (static_cast<NSInteger>([touches count]) != m_activeTouches.count())) - qWarning("Subset of active touches cancelled by UIKit"); - - m_activeTouches.clear(); - m_nextTouchId = 0; - - NSTimeInterval timestamp = event ? event.timestamp : [[NSProcessInfo processInfo] systemUptime]; - - // Send cancel touch event synchronously - QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration()); - QWindowSystemInterface::handleTouchCancelEvent(m_qioswindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice()); - QWindowSystemInterface::flushWindowSystemEvents(); -} - -@end - -@implementation UIView (QIOS) - -- (QWindow *)qwindow -{ - if ([self isKindOfClass:[QUIView class]]) { - if (QIOSWindow *w = static_cast<QUIView *>(self)->m_qioswindow) - return w->window(); - } - return nil; -} - -- (UIViewController *)viewController -{ - id responder = self; - while ((responder = [responder nextResponder])) { - if ([responder isKindOfClass:UIViewController.class]) - return responder; - } - return nil; -} - -@end - -QT_BEGIN_NAMESPACE - QIOSWindow::QIOSWindow(QWindow *window) : QPlatformWindow(window) , m_view([[QUIView alloc] initWithQIOSWindow:this]) @@ -634,6 +334,11 @@ qreal QIOSWindow::devicePixelRatio() const return m_view.contentScaleFactor; } +void QIOSWindow::clearAccessibleCache() +{ + [m_view clearAccessibleCache]; +} + #include "moc_qioswindow.cpp" QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.h b/src/plugins/platforms/ios/quiaccessibilityelement.h new file mode 100644 index 0000000000..7c5a930e86 --- /dev/null +++ b/src/plugins/platforms/ios/quiaccessibilityelement.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 QUIACCESSIBILITYELEMENT_H +#define QUIACCESSIBILITYELEMENT_H + +#import <UIKit/UIKit.h> +#import <QtGui/QtGui> + +@interface QMacAccessibilityElement : UIAccessibilityElement +{} + +@property (readonly) QAccessible::Id axid; + +- (id) initWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view; ++ (QMacAccessibilityElement *) elementWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view; + +@end + +#endif diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm new file mode 100644 index 0000000000..331c38460c --- /dev/null +++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 "quiaccessibilityelement.h" + +#include "private/qaccessiblecache_p.h" + +@implementation QMacAccessibilityElement + +- (id) initWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view +{ + Q_ASSERT((int)anId < 0); + self = [super initWithAccessibilityContainer: view]; + if (self) + _axid = anId; + + return self; +} + ++ (id) elementWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view +{ + Q_ASSERT(anId); + if (!anId) + return nil; + + QAccessibleCache *cache = QAccessibleCache::instance(); + + QMacAccessibilityElement *element = cache->elementForId(anId); + if (!element) { + Q_ASSERT(QAccessible::accessibleInterface(anId)); + element = [[self alloc] initWithId:anId withAccessibilityContainer: view]; + cache->insertElement(anId, element); + } + return element; +} + +- (void) invalidate +{ + [self release]; +} + +- (BOOL) isAccessibilityElement +{ + return YES; +} + +- (NSString*) accessibilityLabel +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return @""; + } + + return iface->text(QAccessible::Name).toNSString(); +} + +- (NSString*) accessibilityHint +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return @""; + } + return iface->text(QAccessible::Description).toNSString(); +} + +- (NSString*) accessibilityValue +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return @""; + } + + QAccessible::State state = iface->state(); + + if (state.checkable) + return state.checked ? @"checked" : @"unchecked"; // FIXME: translation + + QAccessibleValueInterface *val = iface->valueInterface(); + if (val) { + return val->currentValue().toString().toNSString(); + } else if (QAccessibleTextInterface *text = iface->textInterface()) { + // FIXME doesn't work? + return text->text(0, text->characterCount() - 1).toNSString(); + } + + return [super accessibilityHint]; +} + +- (CGRect) accessibilityFrame +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return CGRect(); + } + + QRect rect = iface->rect(); + return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()); +} + +- (UIAccessibilityTraits) accessibilityTraits +{ + UIAccessibilityTraits traits = UIAccessibilityTraitNone; + + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return traits; + } + QAccessible::State state = iface->state(); + if (state.disabled) + traits |= UIAccessibilityTraitNotEnabled; + + if (iface->role() == QAccessible::Button) + traits |= UIAccessibilityTraitButton; + + if (iface->valueInterface()) + traits |= UIAccessibilityTraitAdjustable; + + return traits; +} + +- (BOOL) accessibilityActivate +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (QAccessibleActionInterface *action = iface->actionInterface()) { + if (action->actionNames().contains(QAccessibleActionInterface::pressAction())) { + action->doAction(QAccessibleActionInterface::pressAction()); + return YES; + } else if (action->actionNames().contains(QAccessibleActionInterface::showMenuAction())) { + action->doAction(QAccessibleActionInterface::showMenuAction()); + return YES; + } + } + return NO; // fall back to sending mouse clicks +} + +- (void) accessibilityIncrement +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (QAccessibleActionInterface *action = iface->actionInterface()) + action->doAction(QAccessibleActionInterface::increaseAction()); +} + +- (void) accessibilityDecrement +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (QAccessibleActionInterface *action = iface->actionInterface()) + action->doAction(QAccessibleActionInterface::decreaseAction()); +} + +@end diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h index 122e7c604b..99c710ffee 100644 --- a/src/plugins/platforms/ios/quiview.h +++ b/src/plugins/platforms/ios/quiview.h @@ -40,11 +40,23 @@ ****************************************************************************/ #import <UIKit/UIKit.h> -#include "qioswindow.h" + +#include <qhash.h> +#include <qstring.h> + +#include <qpa/qwindowsysteminterface.h> + +class QIOSWindow; @interface QUIView : UIView { -@public + @public + QIOSWindow *m_qioswindow; + @private + QHash<UITouch *, QWindowSystemInterface::TouchPoint> m_activeTouches; + int m_nextTouchId; + + @public UITextAutocapitalizationType autocapitalizationType; UITextAutocorrectionType autocorrectionType; BOOL enablesReturnKeyAutomatically; @@ -52,11 +64,11 @@ UIKeyboardType keyboardType; UIReturnKeyType returnKeyType; BOOL secureTextEntry; - QIOSWindow *m_qioswindow; - QHash<UITouch *, QWindowSystemInterface::TouchPoint> m_activeTouches; - int m_nextTouchId; QString m_markedText; BOOL m_inSendEventToFocusObject; + + @private + NSMutableArray *m_accessibleElements; } @property(nonatomic, assign) id<UITextInputDelegate> inputDelegate; @@ -69,6 +81,8 @@ @property(nonatomic) UIReturnKeyType returnKeyType; @property(nonatomic, getter=isSecureTextEntry) BOOL secureTextEntry; +- (id)initWithQIOSWindow:(QIOSWindow *)window; +- (void)sendUpdatedExposeEvent; @end @interface QUIView (TextInput) <UITextInput> @@ -77,3 +91,7 @@ - (void)commit; + (bool)inUpdateKeyboardLayout; @end + +@interface QUIView (Accessibility) +- (void)clearAccessibleCache; +@end diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm new file mode 100644 index 0000000000..2726c6e3e0 --- /dev/null +++ b/src/plugins/platforms/ios/quiview.mm @@ -0,0 +1,345 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 "quiview.h" + +#include "qiosglobal.h" +#include "qiosintegration.h" +#include "qioswindow.h" + +#include <QtGui/private/qwindow_p.h> + +// Include category as an alternative to using -ObjC (Apple QA1490) +#include "quiview_textinput.mm" +#include "quiview_accessibility.mm" + +@implementation QUIView + +@synthesize autocapitalizationType; +@synthesize autocorrectionType; +@synthesize enablesReturnKeyAutomatically; +@synthesize keyboardAppearance; +@synthesize keyboardType; +@synthesize returnKeyType; +@synthesize secureTextEntry; + ++ (Class)layerClass +{ + return [CAEAGLLayer class]; +} + +-(id)initWithQIOSWindow:(QIOSWindow *)window +{ + if (self = [self initWithFrame:toCGRect(window->geometry())]) + m_qioswindow = window; + + m_accessibleElements = [[NSMutableArray alloc] init]; + return self; +} + +- (id)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) { + // Set up EAGL layer + CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer); + eaglLayer.opaque = TRUE; + eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking, + kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; + + if (isQtApplication()) + self.hidden = YES; + + self.multipleTouchEnabled = YES; + m_inSendEventToFocusObject = NO; + } + + return self; +} + +- (void)willMoveToWindow:(UIWindow *)newWindow +{ + // UIKIt will normally set the scale factor of a view to match the corresponding + // screen scale factor, but views backed by CAEAGLLayers need to do this manually. + self.contentScaleFactor = newWindow && newWindow.screen ? + newWindow.screen.scale : [[UIScreen mainScreen] scale]; + + // FIXME: Allow the scale factor to be customized through QSurfaceFormat. +} + +- (void)didAddSubview:(UIView *)subview +{ + if ([subview isKindOfClass:[QUIView class]]) + self.clipsToBounds = YES; +} + +- (void)willRemoveSubview:(UIView *)subview +{ + for (UIView *view in self.subviews) { + if (view != subview && [view isKindOfClass:[QUIView class]]) + return; + } + + self.clipsToBounds = NO; +} + +- (void)setNeedsDisplay +{ + [super setNeedsDisplay]; + + // We didn't implement drawRect: so we have to manually + // mark the layer as needing display. + [self.layer setNeedsDisplay]; +} + +- (void)layoutSubviews +{ + // This method is the de facto way to know that view has been resized, + // or otherwise needs invalidation of its buffers. Note though that we + // do not get this callback when the view just changes its position, so + // the position of our QWindow (and platform window) will only get updated + // when the size is also changed. + + if (!CGAffineTransformIsIdentity(self.transform)) + qWarning() << m_qioswindow->window() + << "is backed by a UIView that has a transform set. This is not supported."; + + // The original geometry requested by setGeometry() might be different + // from what we end up with after applying window constraints. + QRect requestedGeometry = m_qioswindow->geometry(); + + QRect actualGeometry; + if (m_qioswindow->window()->isTopLevel()) { + UIWindow *uiWindow = self.window; + UIView *rootView = uiWindow.rootViewController.view; + CGRect rootViewPositionInRelationToRootViewController = + [rootView convertRect:uiWindow.bounds fromView:uiWindow]; + + actualGeometry = fromCGRect(CGRectOffset([self.superview convertRect:self.frame toView:rootView], + -rootViewPositionInRelationToRootViewController.origin.x, + -rootViewPositionInRelationToRootViewController.origin.y + + rootView.bounds.origin.y)).toRect(); + } else { + actualGeometry = fromCGRect(self.frame).toRect(); + } + + // Persist the actual/new geometry so that QWindow::geometry() can + // be queried on the resize event. + m_qioswindow->QPlatformWindow::setGeometry(actualGeometry); + + QRect previousGeometry = requestedGeometry != actualGeometry ? + requestedGeometry : qt_window_private(m_qioswindow->window())->geometry; + + QWindowSystemInterface::handleGeometryChange(m_qioswindow->window(), actualGeometry, previousGeometry); + QWindowSystemInterface::flushWindowSystemEvents(); + + if (actualGeometry.size() != previousGeometry.size()) { + // Trigger expose event on resize + [self setNeedsDisplay]; + + // A new size means we also need to resize the FBO's corresponding buffers, + // but we defer that to when the application calls makeCurrent. + } +} + +- (void)displayLayer:(CALayer *)layer +{ + Q_UNUSED(layer); + Q_ASSERT(layer == self.layer); + + [self sendUpdatedExposeEvent]; +} + +- (void)sendUpdatedExposeEvent +{ + QRegion region; + + if (m_qioswindow->isExposed()) { + QSize bounds = fromCGRect(self.layer.bounds).toRect().size(); + + Q_ASSERT(m_qioswindow->geometry().size() == bounds); + Q_ASSERT(self.hidden == !m_qioswindow->window()->isVisible()); + + region = QRect(QPoint(), bounds); + } + + QWindowSystemInterface::handleExposeEvent(m_qioswindow->window(), region); + QWindowSystemInterface::flushWindowSystemEvents(); +} + +- (void)updateTouchList:(NSSet *)touches withState:(Qt::TouchPointState)state +{ + // We deliver touch events in global coordinates. But global in this respect + // means the same coordinate system that we use for describing the geometry + // of the top level QWindow we're inside. And that would be the coordinate + // system of the superview of the UIView that backs that window: + QPlatformWindow *topLevel = m_qioswindow; + while (QPlatformWindow *topLevelParent = topLevel->parent()) + topLevel = topLevelParent; + UIView *rootView = reinterpret_cast<UIView *>(topLevel->winId()).superview; + CGSize rootViewSize = rootView.frame.size; + + foreach (UITouch *uiTouch, m_activeTouches.keys()) { + QWindowSystemInterface::TouchPoint &touchPoint = m_activeTouches[uiTouch]; + if (![touches containsObject:uiTouch]) { + touchPoint.state = Qt::TouchPointStationary; + } else { + touchPoint.state = state; + touchPoint.pressure = (state == Qt::TouchPointReleased) ? 0.0 : 1.0; + QPoint touchPos = fromCGPoint([uiTouch locationInView:rootView]).toPoint(); + touchPoint.area = QRectF(touchPos, QSize(0, 0)); + touchPoint.normalPosition = QPointF(touchPos.x() / rootViewSize.width, touchPos.y() / rootViewSize.height); + } + } +} + +- (void) sendTouchEventWithTimestamp:(ulong)timeStamp +{ + // Send touch event synchronously + QIOSIntegration *iosIntegration = QIOSIntegration::instance(); + QWindowSystemInterface::handleTouchEvent(m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values()); + QWindowSystemInterface::flushWindowSystemEvents(); +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ + // 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 + // an id for use by Qt. + for (UITouch *touch in touches) { + Q_ASSERT(!m_activeTouches.contains(touch)); + m_activeTouches[touch].id = m_nextTouchId++; + } + + if (m_activeTouches.size() == 1) { + QPlatformWindow *topLevel = m_qioswindow; + while (QPlatformWindow *p = topLevel->parent()) + topLevel = p; + if (topLevel->window() != QGuiApplication::focusWindow()) + topLevel->requestActivateWindow(); + } + + [self updateTouchList:touches withState:Qt::TouchPointPressed]; + [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)]; +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + [self updateTouchList:touches withState:Qt::TouchPointMoved]; + [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)]; +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + [self updateTouchList:touches withState:Qt::TouchPointReleased]; + [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)]; + + // Remove ended touch points from the active set: + for (UITouch *touch in touches) + m_activeTouches.remove(touch); + if (m_activeTouches.isEmpty()) + m_nextTouchId = 0; +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event +{ + if (m_activeTouches.isEmpty()) + return; + + // When four-finger swiping, we get a touchesCancelled callback + // which includes all four touch points. The swipe gesture is + // then active until all four touches have been released, and + // we start getting touchesBegan events again. + + // When five-finger pinching, we also get a touchesCancelled + // callback with all five touch points, but the pinch gesture + // ends when the second to last finger is released from the + // screen. The last finger will not emit any more touch + // events, _but_, will contribute to starting another pinch + // gesture. That second pinch gesture will _not_ trigger a + // touchesCancelled event when starting, but as each finger + // is released, and we may get touchesMoved events for the + // remaining fingers. [event allTouches] also contains one + // less touch point than it should, so this behavior is + // likely a bug in the iOS system gesture recognizer, but we + // have to take it into account when maintaining the Qt state. + // We do this by assuming that there are no cases where a + // sub-set of the active touch events are intentionally cancelled. + + if (touches && (static_cast<NSInteger>([touches count]) != m_activeTouches.count())) + qWarning("Subset of active touches cancelled by UIKit"); + + m_activeTouches.clear(); + m_nextTouchId = 0; + + NSTimeInterval timestamp = event ? event.timestamp : [[NSProcessInfo processInfo] systemUptime]; + + // Send cancel touch event synchronously + QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration()); + QWindowSystemInterface::handleTouchCancelEvent(m_qioswindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice()); + QWindowSystemInterface::flushWindowSystemEvents(); +} + +@end + +@implementation UIView (QtHelpers) + +- (QWindow *)qwindow +{ + if ([self isKindOfClass:[QUIView class]]) { + if (QIOSWindow *w = static_cast<QUIView *>(self)->m_qioswindow) + return w->window(); + } + return nil; +} + +- (UIViewController *)viewController +{ + id responder = self; + while ((responder = [responder nextResponder])) { + if ([responder isKindOfClass:UIViewController.class]) + return responder; + } + return nil; +} + +@end diff --git a/src/plugins/platforms/ios/quiview_accessibility.mm b/src/plugins/platforms/ios/quiview_accessibility.mm new file mode 100644 index 0000000000..6565e08302 --- /dev/null +++ b/src/plugins/platforms/ios/quiview_accessibility.mm @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 "qiosplatformaccessibility.h" +#include "quiaccessibilityelement.h" + +#include <QtGui/private/qguiapplication_p.h> + +@implementation QUIView (Accessibility) + +- (void)createAccessibleElement:(QAccessibleInterface *)iface +{ + if (!iface || iface->state().invisible) + return; + QAccessible::Id accessibleId = QAccessible::uniqueId(iface); + UIAccessibilityElement *elem = [[QMacAccessibilityElement alloc] initWithId: accessibleId withAccessibilityContainer: self]; + [m_accessibleElements addObject: elem]; +} + +- (void)createAccessibleContainer:(QAccessibleInterface *)iface +{ + if (!iface) + return; + + if (iface->childCount() == 0) { + [self createAccessibleElement: iface]; + } else { + for (int i = 0; i < iface->childCount(); ++i) + [self createAccessibleContainer: iface->child(i)]; + } +} + +- (void)initAccessibility +{ + static bool init = false; + if (!init) + QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true); + init = true; + + if ([m_accessibleElements count]) + return; + + QWindow *win = m_qioswindow->window(); + QAccessibleInterface *iface = win->accessibleRoot(); + if (iface) + [self createAccessibleContainer: iface]; +} + +- (void)clearAccessibleCache +{ + [m_accessibleElements removeAllObjects]; + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, @""); +} + +// this is a container, returning yes here means the functions below will never be called +- (BOOL)isAccessibilityElement +{ + return NO; +} + +- (NSInteger)accessibilityElementCount +{ + [self initAccessibility]; + return [m_accessibleElements count]; +} + +- (id)accessibilityElementAtIndex:(NSInteger)index +{ + [self initAccessibility]; + return m_accessibleElements[index]; +} + +- (NSInteger)indexOfAccessibilityElement:(id)element +{ + [self initAccessibility]; + return [m_accessibleElements indexOfObject:element]; +} + +@end diff --git a/src/plugins/platforms/ios/quiview_textinput.mm b/src/plugins/platforms/ios/quiview_textinput.mm index e65ac1cc46..861c8151c6 100644 --- a/src/plugins/platforms/ios/quiview_textinput.mm +++ b/src/plugins/platforms/ios/quiview_textinput.mm @@ -39,7 +39,10 @@ ** ****************************************************************************/ +#include "qiosinputcontext.h" + #include <QtGui/qtextformat.h> +#include <QtGui/private/qguiapplication_p.h> class StaticVariables { diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp index 6c6c516a4e..3f959b859c 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp @@ -179,7 +179,7 @@ QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGL // Get the basic surface format details if (d->context) - qglx_surfaceFormatFromGLXFBConfig(&d->format, x11->display(), config, d->context); + qglx_surfaceFormatFromGLXFBConfig(&d->format, x11->display(), config); // Create a temporary window so that we can make the new context current d->window = createDummyWindow(x11, config); diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp index add45ecbe5..59dc84ebc8 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.cpp +++ b/src/plugins/platforms/qnx/qqnxscreen.cpp @@ -209,6 +209,103 @@ QQnxScreen::~QQnxScreen() delete m_cursor; } +QPixmap QQnxScreen::grabWindow(WId window, int x, int y, int width, int height) const +{ + QQnxWindow *qnxWin = findWindow(reinterpret_cast<screen_window_t>(window)); + if (!qnxWin) { + qWarning("grabWindow: unknown window"); + return QPixmap(); + } + + QRect bound = qnxWin->geometry(); + + if (width < 0) + width = bound.width(); + if (height < 0) + height = bound.height(); + + bound &= QRect(x + bound.x(), y + bound.y(), width, height); + + if (bound.width() <= 0 || bound.height() <= 0) { + qWarning("grabWindow: size is null"); + return QPixmap(); + } + + // Create new context, only SCREEN_DISPLAY_MANAGER_CONTEXT can read from screen + screen_context_t context; + if (screen_create_context(&context, SCREEN_DISPLAY_MANAGER_CONTEXT)) { + if (errno == EPERM) + qWarning("grabWindow: root privileges required"); + else + qWarning("grabWindow: cannot create context"); + return QPixmap(); + } + + // Find corresponding display in SCREEN_DISPLAY_MANAGER_CONTEXT + int count = 0; + screen_display_t display = 0; + screen_get_context_property_iv(context, SCREEN_PROPERTY_DISPLAY_COUNT, &count); + if (count > 0) { + const size_t idLen = 30; + char matchId[idLen]; + char id[idLen]; + bool found = false; + + screen_display_t *displays = static_cast<screen_display_t*> + (calloc(count, sizeof(screen_display_t))); + screen_get_context_property_pv(context, SCREEN_PROPERTY_DISPLAYS, (void **)displays); + screen_get_display_property_cv(m_display, SCREEN_PROPERTY_ID_STRING, idLen, matchId); + + while (count && !found) { + --count; + screen_get_display_property_cv(displays[count], SCREEN_PROPERTY_ID_STRING, idLen, id); + found = !strncmp(id, matchId, idLen); + } + + if (found) + display = displays[count]; + + free(displays); + } + + // Create screen and Qt pixmap + screen_pixmap_t pixmap; + QPixmap result; + if (display && !screen_create_pixmap(&pixmap, context)) { + screen_buffer_t buffer; + void *pointer; + int stride; + const int rect[4] = { bound.x(), bound.y(), bound.width(), bound.height() }; + + int val = SCREEN_USAGE_READ | SCREEN_USAGE_NATIVE; + screen_set_pixmap_property_iv(pixmap, SCREEN_PROPERTY_USAGE, &val); + val = SCREEN_FORMAT_RGBA8888; + screen_set_pixmap_property_iv(pixmap, SCREEN_PROPERTY_FORMAT, &val); + + int err = screen_set_pixmap_property_iv(pixmap, SCREEN_PROPERTY_BUFFER_SIZE, rect+2); + err = err || screen_create_pixmap_buffer(pixmap); + err = err || screen_get_pixmap_property_pv(pixmap, SCREEN_PROPERTY_RENDER_BUFFERS, + reinterpret_cast<void**>(&buffer)); + err = err || screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, &pointer); + err = err || screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE, &stride); + err = err || screen_read_display(display, buffer, 1, rect, 0); + + if (!err) { + const QImage img(static_cast<unsigned char*>(pointer), + bound.width(), bound.height(), stride, QImage::Format_ARGB32); + result = QPixmap::fromImage(img); + } else { + qWarning("grabWindow: capture error"); + } + screen_destroy_pixmap(pixmap); + } else { + qWarning("grabWindow: display/pixmap error "); + } + screen_destroy_context(context); + + return result; +} + static int defaultDepth() { qScreenDebug() << Q_FUNC_INFO; @@ -463,7 +560,7 @@ void QQnxScreen::resizeWindows(const QRect &previousScreenGeometry) } } -QQnxWindow *QQnxScreen::findWindow(screen_window_t windowHandle) +QQnxWindow *QQnxScreen::findWindow(screen_window_t windowHandle) const { Q_FOREACH (QQnxWindow *window, m_childWindows) { QQnxWindow * const result = window->findWindow(windowHandle); diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h index 6b2281f7b9..a8a18c6240 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.h +++ b/src/plugins/platforms/qnx/qqnxscreen.h @@ -62,6 +62,8 @@ public: QQnxScreen(screen_context_t context, screen_display_t display, bool primaryScreen); ~QQnxScreen(); + QPixmap grabWindow(WId window, int x, int y, int width, int height) const; + QRect geometry() const { return m_currentGeometry; } QRect availableGeometry() const; int depth() const; @@ -86,7 +88,7 @@ public: screen_context_t nativeContext() const { return m_screenContext; } const char *windowGroupName() const { return m_rootWindow ? m_rootWindow->groupName().constData() : 0; } - QQnxWindow *findWindow(screen_window_t windowHandle); + QQnxWindow *findWindow(screen_window_t windowHandle) const; /* Window hierarchy management */ void addWindow(QQnxWindow *child); diff --git a/src/plugins/platforms/windows/accessible/comutils.cpp b/src/plugins/platforms/windows/accessible/comutils.cpp index 6c67345e05..366adb9059 100644 --- a/src/plugins/platforms/windows/accessible/comutils.cpp +++ b/src/plugins/platforms/windows/accessible/comutils.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. diff --git a/src/plugins/platforms/windows/accessible/comutils.h b/src/plugins/platforms/windows/accessible/comutils.h index ebf16dfdf8..2ef11ec0dd 100644 --- a/src/plugins/platforms/windows/accessible/comutils.h +++ b/src/plugins/platforms/windows/accessible/comutils.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp index 032f33163a..20658f9cad 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp +++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -43,7 +43,7 @@ #include "iaccessible2.h" #include "qwindowsaccessibility.h" - +#include <QtPlatformSupport/private/qaccessiblebridgeutils_p.h> #include <QtGui/qaccessible.h> #include <QtGui/qclipboard.h> #include <QtWidgets/qapplication.h> @@ -358,6 +358,8 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::role(long *ia2role) case QAccessible::LayeredPane: r = IA2_ROLE_LAYERED_PANE; break; case QAccessible::Terminal: r = IA2_ROLE_TERMINAL; break; case QAccessible::Desktop: r = IA2_ROLE_DESKTOP_PANE; break; + case QAccessible::Paragraph: r = IA2_ROLE_PARAGRAPH; break; + case QAccessible::Section: r = IA2_ROLE_SECTION; break; default: break; } @@ -545,10 +547,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::nActions(long *nActions) accessibleDebugClientCalls(accessible); if (!accessible) return E_FAIL; - *nActions = 0; - - if (QAccessibleActionInterface *actionIface = actionInterface()) - *nActions = actionIface->actionNames().count(); + *nActions = QAccessibleBridgeUtils::effectiveActionNames(accessible).count(); return S_OK; } @@ -558,15 +557,11 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::doAction(long actionIndex) accessibleDebugClientCalls(accessible); if (!accessible) return E_FAIL; - if (QAccessibleActionInterface *actionIface = actionInterface()) { - const QStringList actionNames = actionIface->actionNames(); - if (actionIndex < 0 || actionIndex >= actionNames.count()) - return E_INVALIDARG; - const QString actionName = actionNames.at(actionIndex); - actionIface->doAction(actionName); - return S_OK; - } - return S_FALSE; + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(accessible); + if (actionIndex < 0 || actionIndex >= actionNames.count()) + return E_INVALIDARG; + const QString actionName = actionNames.at(actionIndex); + return QAccessibleBridgeUtils::performEffectiveAction(accessible, actionName) ? S_OK : S_FALSE; } HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionIndex, BSTR *description) @@ -576,13 +571,15 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionInde if (!accessible) return E_FAIL; *description = 0; - if (QAccessibleActionInterface *actionIface = actionInterface()) { - const QStringList actionNames = actionIface->actionNames(); - if (actionIndex < 0 || actionIndex >= actionNames.count()) - return E_INVALIDARG; - const QString actionName = actionNames.at(actionIndex); + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(accessible); + if (actionIndex < 0 || actionIndex >= actionNames.count()) + return E_INVALIDARG; + const QString actionName = actionNames.at(actionIndex); + if (QAccessibleActionInterface *actionIface = actionInterface()) *description = QStringToBSTR(actionIface->localizedActionDescription(actionName)); - } + else + *description = QStringToBSTR(qAccessibleLocalizedActionDescription(actionName)); + return *description ? S_OK : S_FALSE; } @@ -622,13 +619,11 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_name(long actionIndex, BSTR if (!accessible) return E_FAIL; *name = 0; - if (QAccessibleActionInterface *actionIface = actionInterface()) { - const QStringList actionNames = actionIface->actionNames(); - if (actionIndex < 0 || actionIndex >= actionNames.count()) - return E_INVALIDARG; - const QString actionName = actionNames.at(actionIndex); - *name = QStringToBSTR(actionName); - } + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(accessible); + if (actionIndex < 0 || actionIndex >= actionNames.count()) + return E_INVALIDARG; + const QString actionName = actionNames.at(actionIndex); + *name = QStringToBSTR(actionName); return *name ? S_OK : S_FALSE; } @@ -639,14 +634,16 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedName(long actionIn if (!accessible) return E_FAIL; *localizedName = 0; - if (QAccessibleActionInterface *actionIface = actionInterface()) { - const QStringList actionNames = actionIface->actionNames(); - if (actionIndex < 0 || actionIndex >= actionNames.count()) - return E_INVALIDARG; + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(accessible); + if (actionIndex < 0 || actionIndex >= actionNames.count()) + return E_INVALIDARG; - const QString actionName = actionNames.at(actionIndex); + const QString actionName = actionNames.at(actionIndex); + if (QAccessibleActionInterface *actionIface = actionInterface()) *localizedName = QStringToBSTR(actionIface->localizedActionName(actionName)); - } + else + *localizedName = QStringToBSTR(QAccessibleActionInterface::tr(qPrintable(actionName))); + return *localizedName ? S_OK : S_FALSE; } diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.h b/src/plugins/platforms/windows/accessible/iaccessible2.h index 9c42fdc631..fd92fb25bf 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.h +++ b/src/plugins/platforms/windows/accessible/iaccessible2.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp index 307f2fc3bb..f5b0f2f166 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h index f25e2281a0..9e14868415 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h +++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp index bda806d102..d606ecb6a5 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -890,6 +890,11 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BST } } } + + QString shortcut = accessible->text(QAccessible::Accelerator); + if (!shortcut.isEmpty()) + name.append(QLatin1Char(' ') + shortcut); + if (name.size()) { *pszName = QStringToBSTR(name); return S_OK; @@ -930,6 +935,8 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accRole(VARIANT varID, VAR // does not support IAccessible2, since it should prefer IA2::role() then. if (role == QAccessible::LayeredPane) role = QAccessible::Pane; + else if (role == QAccessible::WebDocument) + role = QAccessible::Document; else role = QAccessible::Client; } @@ -1034,7 +1041,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accValue(VARIANT varID, BS QString value; if (accessible->valueInterface()) { - value = QString::number(accessible->valueInterface()->currentValue().toDouble()); + value = accessible->valueInterface()->currentValue().toString(); } else { value = accessible->text(QAccessible::Value); } diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h index 43482da4be..b9cc2ccb44 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. diff --git a/src/plugins/platforms/windows/cursors.qrc b/src/plugins/platforms/windows/cursors.qrc new file mode 100644 index 0000000000..fded527aac --- /dev/null +++ b/src/plugins/platforms/windows/cursors.qrc @@ -0,0 +1,25 @@ +<RCC> + <qresource prefix="/qt-project.org/windows/cursors"> + <file>images/closedhandcursor_32.png</file> + <file>images/closedhandcursor_48.png</file> + <file>images/closedhandcursor_64.png</file> + <file>images/dragcopycursor_32.png</file> + <file>images/dragcopycursor_48.png</file> + <file>images/dragcopycursor_64.png</file> + <file>images/draglinkcursor_32.png</file> + <file>images/draglinkcursor_48.png</file> + <file>images/draglinkcursor_64.png</file> + <file>images/dragmovecursor_32.png</file> + <file>images/dragmovecursor_48.png</file> + <file>images/dragmovecursor_64.png</file> + <file>images/openhandcursor_32.png</file> + <file>images/openhandcursor_48.png</file> + <file>images/openhandcursor_64.png</file> + <file>images/splithcursor_32.png</file> + <file>images/splithcursor_48.png</file> + <file>images/splithcursor_64.png</file> + <file>images/splitvcursor_32.png</file> + <file>images/splitvcursor_48.png</file> + <file>images/splitvcursor_64.png</file> + </qresource> +</RCC> diff --git a/src/plugins/platforms/windows/images/closedhandcursor_32.png b/src/plugins/platforms/windows/images/closedhandcursor_32.png Binary files differnew file mode 100644 index 0000000000..7b3cba1965 --- /dev/null +++ b/src/plugins/platforms/windows/images/closedhandcursor_32.png diff --git a/src/plugins/platforms/windows/images/closedhandcursor_48.png b/src/plugins/platforms/windows/images/closedhandcursor_48.png Binary files differnew file mode 100644 index 0000000000..e63031605e --- /dev/null +++ b/src/plugins/platforms/windows/images/closedhandcursor_48.png diff --git a/src/plugins/platforms/windows/images/closedhandcursor_64.png b/src/plugins/platforms/windows/images/closedhandcursor_64.png Binary files differnew file mode 100644 index 0000000000..438680ed4e --- /dev/null +++ b/src/plugins/platforms/windows/images/closedhandcursor_64.png diff --git a/src/plugins/platforms/windows/images/dragcopycursor_32.png b/src/plugins/platforms/windows/images/dragcopycursor_32.png Binary files differnew file mode 100644 index 0000000000..f40ac6a600 --- /dev/null +++ b/src/plugins/platforms/windows/images/dragcopycursor_32.png diff --git a/src/plugins/platforms/windows/images/dragcopycursor_48.png b/src/plugins/platforms/windows/images/dragcopycursor_48.png Binary files differnew file mode 100644 index 0000000000..21ee467f46 --- /dev/null +++ b/src/plugins/platforms/windows/images/dragcopycursor_48.png diff --git a/src/plugins/platforms/windows/images/dragcopycursor_64.png b/src/plugins/platforms/windows/images/dragcopycursor_64.png Binary files differnew file mode 100644 index 0000000000..c49bcf33aa --- /dev/null +++ b/src/plugins/platforms/windows/images/dragcopycursor_64.png diff --git a/src/plugins/platforms/windows/images/draglinkcursor_32.png b/src/plugins/platforms/windows/images/draglinkcursor_32.png Binary files differnew file mode 100644 index 0000000000..5efbce90d3 --- /dev/null +++ b/src/plugins/platforms/windows/images/draglinkcursor_32.png diff --git a/src/plugins/platforms/windows/images/draglinkcursor_48.png b/src/plugins/platforms/windows/images/draglinkcursor_48.png Binary files differnew file mode 100644 index 0000000000..51205101b1 --- /dev/null +++ b/src/plugins/platforms/windows/images/draglinkcursor_48.png diff --git a/src/plugins/platforms/windows/images/draglinkcursor_64.png b/src/plugins/platforms/windows/images/draglinkcursor_64.png Binary files differnew file mode 100644 index 0000000000..55eb0e313a --- /dev/null +++ b/src/plugins/platforms/windows/images/draglinkcursor_64.png diff --git a/src/plugins/platforms/windows/images/dragmovecursor_32.png b/src/plugins/platforms/windows/images/dragmovecursor_32.png Binary files differnew file mode 100644 index 0000000000..32781a15ff --- /dev/null +++ b/src/plugins/platforms/windows/images/dragmovecursor_32.png diff --git a/src/plugins/platforms/windows/images/dragmovecursor_48.png b/src/plugins/platforms/windows/images/dragmovecursor_48.png Binary files differnew file mode 100644 index 0000000000..6b15af6e84 --- /dev/null +++ b/src/plugins/platforms/windows/images/dragmovecursor_48.png diff --git a/src/plugins/platforms/windows/images/dragmovecursor_64.png b/src/plugins/platforms/windows/images/dragmovecursor_64.png Binary files differnew file mode 100644 index 0000000000..e9e4ece29f --- /dev/null +++ b/src/plugins/platforms/windows/images/dragmovecursor_64.png diff --git a/src/plugins/platforms/windows/images/openhandcursor_32.png b/src/plugins/platforms/windows/images/openhandcursor_32.png Binary files differnew file mode 100644 index 0000000000..a6948d48f7 --- /dev/null +++ b/src/plugins/platforms/windows/images/openhandcursor_32.png diff --git a/src/plugins/platforms/windows/images/openhandcursor_48.png b/src/plugins/platforms/windows/images/openhandcursor_48.png Binary files differnew file mode 100644 index 0000000000..e8beb8d29d --- /dev/null +++ b/src/plugins/platforms/windows/images/openhandcursor_48.png diff --git a/src/plugins/platforms/windows/images/openhandcursor_64.png b/src/plugins/platforms/windows/images/openhandcursor_64.png Binary files differnew file mode 100644 index 0000000000..d12e3a7283 --- /dev/null +++ b/src/plugins/platforms/windows/images/openhandcursor_64.png diff --git a/src/plugins/platforms/windows/images/splithcursor_32.png b/src/plugins/platforms/windows/images/splithcursor_32.png Binary files differnew file mode 100644 index 0000000000..1ad479eddf --- /dev/null +++ b/src/plugins/platforms/windows/images/splithcursor_32.png diff --git a/src/plugins/platforms/windows/images/splithcursor_48.png b/src/plugins/platforms/windows/images/splithcursor_48.png Binary files differnew file mode 100644 index 0000000000..bf59b9cdca --- /dev/null +++ b/src/plugins/platforms/windows/images/splithcursor_48.png diff --git a/src/plugins/platforms/windows/images/splithcursor_64.png b/src/plugins/platforms/windows/images/splithcursor_64.png Binary files differnew file mode 100644 index 0000000000..b857458671 --- /dev/null +++ b/src/plugins/platforms/windows/images/splithcursor_64.png diff --git a/src/plugins/platforms/windows/images/splitvcursor_32.png b/src/plugins/platforms/windows/images/splitvcursor_32.png Binary files differnew file mode 100644 index 0000000000..ebb55ae2e1 --- /dev/null +++ b/src/plugins/platforms/windows/images/splitvcursor_32.png diff --git a/src/plugins/platforms/windows/images/splitvcursor_48.png b/src/plugins/platforms/windows/images/splitvcursor_48.png Binary files differnew file mode 100644 index 0000000000..5408920652 --- /dev/null +++ b/src/plugins/platforms/windows/images/splitvcursor_48.png diff --git a/src/plugins/platforms/windows/images/splitvcursor_64.png b/src/plugins/platforms/windows/images/splitvcursor_64.png Binary files differnew file mode 100644 index 0000000000..7f09a40c01 --- /dev/null +++ b/src/plugins/platforms/windows/images/splitvcursor_64.png diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index ee640224cf..1b2502af10 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch> -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -103,6 +103,7 @@ enum WindowsEventType // Simplify event types AccessibleObjectFromWindowRequest = ApplicationEventFlag + 3, QueryEndSessionApplicationEvent = ApplicationEventFlag + 4, EndSessionApplicationEvent = ApplicationEventFlag + 5, + AppCommandEvent = ApplicationEventFlag + 6, InputMethodStartCompositionEvent = InputMethodEventFlag + 1, InputMethodCompositionEvent = InputMethodEventFlag + 2, InputMethodEndCompositionEvent = InputMethodEventFlag + 3, @@ -117,6 +118,14 @@ enum WindowsEventType // Simplify event types UnknownEvent = 542 }; +// Matches Process_DPI_Awareness (Windows 8.1 onwards), used for SetProcessDpiAwareness() +enum ProcessDpiAwareness +{ + ProcessDpiUnaware, + ProcessSystemDpiAware, + ProcessPerMonitorDpiAware +}; + } // namespace QtWindows inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn) @@ -234,6 +243,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI case WM_ENDSESSION: return QtWindows::EndSessionApplicationEvent; #endif +#if defined(WM_APPCOMMAND) + case WM_APPCOMMAND: + return QtWindows::AppCommandEvent; +#endif default: break; } diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h index 758f6c941f..e19b8a4db1 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.h +++ b/src/plugins/platforms/windows/qwindowsbackingstore.h @@ -59,11 +59,11 @@ public: QWindowsBackingStore(QWindow *window); ~QWindowsBackingStore(); - virtual QPaintDevice *paintDevice(); - virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); - virtual void resize(const QSize &size, const QRegion &r); - virtual bool scroll(const QRegion &area, int dx, int dy); - virtual void beginPaint(const QRegion &); + QPaintDevice *paintDevice() Q_DECL_OVERRIDE; + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; + void resize(const QSize &size, const QRegion &r) Q_DECL_OVERRIDE; + bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE; + void beginPaint(const QRegion &) Q_DECL_OVERRIDE; HDC getDC() const; diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp index dcfeba12fa..e43b524aa8 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.cpp +++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -145,7 +145,7 @@ static void cleanClipboardPostRoutine() QWindowsClipboard *QWindowsClipboard::m_instance = 0; QWindowsClipboard::QWindowsClipboard() : - m_data(0), m_clipboardViewer(0), m_nextClipboardViewer(0) + m_data(0), m_clipboardViewer(0), m_nextClipboardViewer(0), m_formatListenerRegistered(false) { QWindowsClipboard::m_instance = this; qAddPostRoutine(cleanClipboardPostRoutine); @@ -178,20 +178,40 @@ void QWindowsClipboard::registerViewer() m_clipboardViewer = QWindowsContext::instance()-> createDummyWindow(QStringLiteral("Qt5ClipboardView"), L"Qt5ClipboardView", qClipboardViewerWndProc, WS_OVERLAPPED); - m_nextClipboardViewer = SetClipboardViewer(m_clipboardViewer); - qCDebug(lcQpaMime) << __FUNCTION__ << "m_clipboardViewer: " << m_clipboardViewer << "next: " << m_nextClipboardViewer; + // Try format listener API (Vista onwards) first. + if (QWindowsContext::user32dll.addClipboardFormatListener && QWindowsContext::user32dll.removeClipboardFormatListener) { + m_formatListenerRegistered = QWindowsContext::user32dll.addClipboardFormatListener(m_clipboardViewer); + if (!m_formatListenerRegistered) + qErrnoWarning("AddClipboardFormatListener() failed."); + } + + if (!m_formatListenerRegistered) + m_nextClipboardViewer = SetClipboardViewer(m_clipboardViewer); + + qCDebug(lcQpaMime) << __FUNCTION__ << "m_clipboardViewer:" << m_clipboardViewer + << "format listener:" << m_formatListenerRegistered + << "next:" << m_nextClipboardViewer; } void QWindowsClipboard::unregisterViewer() { if (m_clipboardViewer) { - ChangeClipboardChain(m_clipboardViewer, m_nextClipboardViewer); + if (m_formatListenerRegistered) { + QWindowsContext::user32dll.removeClipboardFormatListener(m_clipboardViewer); + m_formatListenerRegistered = false; + } else { + ChangeClipboardChain(m_clipboardViewer, m_nextClipboardViewer); + m_nextClipboardViewer = 0; + } DestroyWindow(m_clipboardViewer); - m_clipboardViewer = m_nextClipboardViewer = 0; + m_clipboardViewer = 0; } } +// ### FIXME: Qt 6: Remove the clipboard chain handling code and make the +// format listener the default. + static bool isProcessBeingDebugged(HWND hwnd) { DWORD pid = 0; @@ -232,6 +252,8 @@ void QWindowsClipboard::propagateClipboardMessage(UINT message, WPARAM wParam, L bool QWindowsClipboard::clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) { + enum { wMClipboardUpdate = 0x031D }; + *result = 0; if (QWindowsContext::verbose) qCDebug(lcQpaMime) << __FUNCTION__ << hwnd << message << QWindowsGuiEventDispatcher::windowsMessageName(message); @@ -246,14 +268,16 @@ bool QWindowsClipboard::clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM w } } return true; - case WM_DRAWCLIPBOARD: { + case wMClipboardUpdate: // Clipboard Format listener (Vista onwards) + case WM_DRAWCLIPBOARD: { // Clipboard Viewer Chain handling (up to XP) const bool owned = ownsClipboard(); qCDebug(lcQpaMime) << "Clipboard changed owned " << owned; emitChanged(QClipboard::Clipboard); // clean up the clipboard object if we no longer own the clipboard if (!owned && m_data) releaseIData(); - propagateClipboardMessage(message, wParam, lParam); + if (!m_formatListenerRegistered) + propagateClipboardMessage(message, wParam, lParam); } return true; case WM_DESTROY: diff --git a/src/plugins/platforms/windows/qwindowsclipboard.h b/src/plugins/platforms/windows/qwindowsclipboard.h index 30bc0143f4..a3e9da7f3f 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.h +++ b/src/plugins/platforms/windows/qwindowsclipboard.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -54,8 +54,8 @@ class QWindowsClipboardRetrievalMimeData : public QWindowsInternalMimeData { public: protected: - virtual IDataObject *retrieveDataObject() const; - virtual void releaseDataObject(IDataObject *) const; + IDataObject *retrieveDataObject() const Q_DECL_OVERRIDE; + void releaseDataObject(IDataObject *) const Q_DECL_OVERRIDE; }; class QWindowsClipboard : public QPlatformClipboard @@ -66,10 +66,10 @@ public: void registerViewer(); // Call in initialization, when context is up. void cleanup(); - virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard); - virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard); - virtual bool supportsMode(QClipboard::Mode mode) const; - virtual bool ownsMode(QClipboard::Mode mode) const; + QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE; + void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE; + bool supportsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE; + bool ownsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE; inline bool clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result); @@ -88,6 +88,7 @@ private: QWindowsOleDataObject *m_data; HWND m_clipboardViewer; HWND m_nextClipboardViewer; + bool m_formatListenerRegistered; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index f2f285f0f6..9706615047 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -191,7 +191,8 @@ QWindowsUser32DLL::QWindowsUser32DLL() : updateLayeredWindowIndirect(0), isHungAppWindow(0), registerTouchWindow(0), unregisterTouchWindow(0), - getTouchInputInfo(0), closeTouchInputHandle(0), setProcessDPIAware(0) + getTouchInputInfo(0), closeTouchInputHandle(0), setProcessDPIAware(0), + addClipboardFormatListener(0), removeClipboardFormatListener(0) { } @@ -207,6 +208,11 @@ void QWindowsUser32DLL::init() updateLayeredWindowIndirect = (UpdateLayeredWindowIndirect)(library.resolve("UpdateLayeredWindowIndirect")); isHungAppWindow = (IsHungAppWindow)library.resolve("IsHungAppWindow"); setProcessDPIAware = (SetProcessDPIAware)library.resolve("SetProcessDPIAware"); + + if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) { + addClipboardFormatListener = (AddClipboardFormatListener)library.resolve("AddClipboardFormatListener"); + removeClipboardFormatListener = (RemoveClipboardFormatListener)library.resolve("RemoveClipboardFormatListener"); + } } bool QWindowsUser32DLL::initTouch() @@ -247,8 +253,26 @@ void QWindowsShell32DLL::init() sHGetImageList = (SHGetImageList)library.resolve("SHGetImageList"); } +QWindowsShcoreDLL::QWindowsShcoreDLL() + : getProcessDpiAwareness(0) + , setProcessDpiAwareness(0) + , getDpiForMonitor(0) +{ +} + +void QWindowsShcoreDLL::init() +{ + if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS8_1) + return; + QSystemLibrary library(QStringLiteral("SHCore")); + getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness"); + setProcessDpiAwareness = (SetProcessDpiAwareness)library.resolve("SetProcessDpiAwareness"); + getDpiForMonitor = (GetDpiForMonitor)library.resolve("GetDpiForMonitor"); +} + QWindowsUser32DLL QWindowsContext::user32dll; QWindowsShell32DLL QWindowsContext::shell32dll; +QWindowsShcoreDLL QWindowsContext::shcoredll; #endif // !Q_OS_WINCE @@ -299,9 +323,7 @@ QWindowsContextPrivate::QWindowsContextPrivate() #ifndef Q_OS_WINCE QWindowsContext::user32dll.init(); QWindowsContext::shell32dll.init(); - // Ensure metrics functions report correct data, QTBUG-30063. - if (QWindowsContext::user32dll.setProcessDPIAware) - QWindowsContext::user32dll.setProcessDPIAware(); + QWindowsContext::shcoredll.init(); if (hasTouchSupport(ver) && QWindowsContext::user32dll.initTouch()) m_systemInfo |= QWindowsContext::SI_SupportsTouch; @@ -358,6 +380,25 @@ void QWindowsContext::setTabletAbsoluteRange(int a) #endif } +void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness) +{ +#ifndef Q_OS_WINCE + qCDebug(lcQpaWindows) << __FUNCTION__ << dpiAwareness; + if (QWindowsContext::shcoredll.isValid()) { + const HRESULT hr = QWindowsContext::shcoredll.setProcessDpiAwareness(dpiAwareness); + if (FAILED(hr)) + qWarning() << "SetProcessDpiAwareness failed:" << QWindowsContext::comErrorString(hr); + } else { + if (dpiAwareness != QtWindows::ProcessDpiUnaware && QWindowsContext::user32dll.setProcessDPIAware) { + if (!QWindowsContext::user32dll.setProcessDPIAware()) + qErrnoWarning("SetProcessDPIAware() failed"); + } + } +#else // !Q_OS_WINCE + Q_UNUSED(dpiAwareness) +#endif +} + QWindowsContext *QWindowsContext::instance() { return m_instance; @@ -419,9 +460,17 @@ QString QWindowsContext::registerWindowClass(const QWindow *w, bool isGL) && (type == Qt::Popup || w->property("_q_windowsDropShadow").toBool())) { style |= CS_DROPSHADOW; } - if (type == Qt::Tool || type == Qt::ToolTip || type == Qt::Popup) { + switch (type) { + case Qt::Tool: + case Qt::ToolTip: + case Qt::Popup: style |= CS_SAVEBITS; // Save/restore background icon = false; + break; + case Qt::Dialog: + if (!(flags & Qt::WindowSystemMenuHint)) + icon = false; // QTBUG-2027, dialogs without system menu. + break; } // Create a unique name for the flag combination QString cname = QStringLiteral("Qt5QWindow"); @@ -913,6 +962,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::InputMethodKeyEvent: case QtWindows::InputMethodKeyDownEvent: case QtWindows::KeyboardLayoutChangeEvent: + case QtWindows::AppCommandEvent: #if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER) return platformSessionManager()->isInteractionBlocked() ? true : d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result); #else diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index f5dbd072c7..086b968255 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -94,6 +94,8 @@ struct QWindowsUser32DLL typedef BOOL (WINAPI *UpdateLayeredWindowIndirect)(HWND, const UPDATELAYEREDWINDOWINFO *); typedef BOOL (WINAPI *IsHungAppWindow)(HWND); typedef BOOL (WINAPI *SetProcessDPIAware)(); + typedef BOOL (WINAPI *AddClipboardFormatListener)(HWND); + typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND); // Functions missing in Q_CC_GNU stub libraries. SetLayeredWindowAttributes setLayeredWindowAttributes; @@ -111,6 +113,10 @@ struct QWindowsUser32DLL // Windows Vista onwards SetProcessDPIAware setProcessDPIAware; + + // Clipboard listeners, Windows Vista onwards + AddClipboardFormatListener addClipboardFormatListener; + RemoveClipboardFormatListener removeClipboardFormatListener; }; struct QWindowsShell32DLL @@ -126,6 +132,22 @@ struct QWindowsShell32DLL SHGetStockIconInfo sHGetStockIconInfo; SHGetImageList sHGetImageList; }; + +// Shell scaling library (Windows 8.1 onwards) +struct QWindowsShcoreDLL { + QWindowsShcoreDLL(); + void init(); + inline bool isValid() const { return getProcessDpiAwareness && setProcessDpiAwareness && getDpiForMonitor; } + + typedef HRESULT (WINAPI *GetProcessDpiAwareness)(HANDLE,int); + typedef HRESULT (WINAPI *SetProcessDpiAwareness)(int); + typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *); + + GetProcessDpiAwareness getProcessDpiAwareness; + SetProcessDpiAwareness setProcessDpiAwareness; + GetDpiForMonitor getDpiForMonitor; +}; + #endif // Q_OS_WINCE class QWindowsContext @@ -184,6 +206,7 @@ public: void setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx); void setTabletAbsoluteRange(int a); + void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness); // Returns a combination of SystemInfoFlags unsigned systemInfo() const; @@ -197,6 +220,7 @@ public: #ifndef Q_OS_WINCE static QWindowsUser32DLL user32dll; static QWindowsShell32DLL shell32dll; + static QWindowsShcoreDLL shcoredll; #endif static QByteArray comErrorString(HRESULT hr); diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index d8fb104b3c..8352dac0b6 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -98,7 +98,7 @@ QWindowsCursorCacheKey::QWindowsCursorCacheKey(const QCursor &c) \sa QWindowsWindowCursor */ -HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY) +HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, const QPoint &hotSpot) { HCURSOR cur = 0; QBitmap mask = pixmap.mask(); @@ -112,8 +112,8 @@ HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int ICONINFO ii; ii.fIcon = 0; - ii.xHotspot = hotX; - ii.yHotspot = hotY; + ii.xHotspot = hotSpot.x(); + ii.yHotspot = hotSpot.y(); ii.hbmMask = im; ii.hbmColor = ic; @@ -124,20 +124,120 @@ HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int return cur; } -HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) +// Create a cursor from image and mask of the format QImage::Format_Mono. +static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits, + QPoint hotSpot = QPoint(), + bool invb = false, bool invm = false) { - int hx = c.hotSpot().x(); - int hy = c.hotSpot().y(); - const Qt::CursorShape cshape = c.shape(); - if (cshape == Qt::BitmapCursor) { - const QPixmap pixmap = c.pixmap(); - if (!pixmap.isNull()) - if (const HCURSOR hc = createPixmapCursor(pixmap, hx, hy)) - return hc; + const int width = bbits.width(); + const int height = bbits.height(); + if (hotSpot.isNull()) + hotSpot = QPoint(width / 2, height / 2); + const int n = qMax(1, width / 8); +#if !defined(Q_OS_WINCE) + QScopedArrayPointer<uchar> xBits(new uchar[height * n]); + QScopedArrayPointer<uchar> xMask(new uchar[height * n]); + int x = 0; + for (int i = 0; i < height; ++i) { + const uchar *bits = bbits.scanLine(i); + const uchar *mask = mbits.scanLine(i); + for (int j = 0; j < n; ++j) { + uchar b = bits[j]; + uchar m = mask[j]; + if (invb) + b ^= 0xff; + if (invm) + m ^= 0xff; + xBits[x] = ~m; + xMask[x] = b ^ m; + ++x; + } + } + return CreateCursor(GetModuleHandle(0), hotSpot.x(), hotSpot.y(), width, height, + xBits.data(), xMask.data()); +#elif defined(GWES_ICONCURS) // Q_OS_WINCE + // Windows CE only supports fixed cursor size. + int sysW = GetSystemMetrics(SM_CXCURSOR); + int sysH = GetSystemMetrics(SM_CYCURSOR); + int sysN = qMax(1, sysW / 8); + uchar* xBits = new uchar[sysH * sysN]; + uchar* xMask = new uchar[sysH * sysN]; + int x = 0; + for (int i = 0; i < sysH; ++i) { + if (i >= height) { + memset(&xBits[x] , 255, sysN); + memset(&xMask[x] , 0, sysN); + x += sysN; + } else { + int fillWidth = n > sysN ? sysN : n; + const uchar *bits = bbits.scanLine(i); + const uchar *mask = mbits.scanLine(i); + for (int j = 0; j < fillWidth; ++j) { + uchar b = bits[j]; + uchar m = mask[j]; + if (invb) + b ^= 0xFF; + if (invm) + m ^= 0xFF; + xBits[x] = ~m; + xMask[x] = b ^ m; + ++x; + } + for (int j = fillWidth; j < sysN; ++j ) { + xBits[x] = 255; + xMask[x] = 0; + ++x; + } + } } - // Non-standard Windows cursors are created from bitmaps + HCURSOR hcurs = CreateCursor(qWinAppInst(), hotSpot.x(), hotSpot.y(), sysW, sysH, + xBits, xMask); + delete [] xBits; + delete [] xMask; + return hcurs; +#else + Q_UNUSED(n); + Q_UNUSED(invm); + Q_UNUSED(invb); + Q_UNUSED(mbits); + return 0; +#endif +} +static inline QSize systemCursorSize() { return QSize(GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR)); } +static inline QSize standardCursorSize() { return QSize(32, 32); } + +#if defined (Q_OS_WINCE) || defined (QT_NO_IMAGEFORMAT_PNG) +// Create pixmap cursors from data and scale the image if the cursor size is +// higher than the standard 32. Note that bitmap cursors as produced by +// createBitmapCursor() only work for standard sizes (32,48,64...), which does +// not work when scaling the 16x16 openhand cursor bitmaps to 150% (resulting +// in a non-standard 24x24 size). +static QCursor createPixmapCursorFromData(const QSize &systemCursorSize, + // The cursor size the bitmap is targeted for + const QSize &bitmapTargetCursorSize, + // The actual size of the bitmap data + int bitmapSize, const uchar *bits, + const uchar *maskBits) +{ + QPixmap rawImage = QPixmap::fromImage(QBitmap::fromData(QSize(bitmapSize, bitmapSize), bits).toImage()); + rawImage.setMask(QBitmap::fromData(QSize(bitmapSize, bitmapSize), maskBits)); + + const qreal factor = qreal(systemCursorSize.width()) / qreal(bitmapTargetCursorSize.width()); + // Scale images if the cursor size is significantly different, starting with 150% where the system cursor + // size is 48. + if (qAbs(factor - 1.0) > 0.4) { + const QTransform transform = QTransform::fromScale(factor, factor); + rawImage = rawImage.transformed(transform, Qt::SmoothTransformation); + } + const QPoint hotSpot(rawImage.width() / 2, rawImage.height() / 2); + return QCursor(rawImage, hotSpot.x(), hotSpot.y()); +} + +QCursor QWindowsCursor::customCursor(Qt::CursorShape cursorShape) +{ + // Non-standard Windows cursors are created from bitmaps static const uchar vsplit_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -203,171 +303,250 @@ HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f, 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00}; - wchar_t *sh = 0; - switch (c.shape()) { // map to windows cursor - case Qt::ArrowCursor: - sh = IDC_ARROW; - break; - case Qt::UpArrowCursor: - sh = IDC_UPARROW; - break; - case Qt::CrossCursor: - sh = IDC_CROSS; - break; - case Qt::WaitCursor: - sh = IDC_WAIT; - break; - case Qt::IBeamCursor: - sh = IDC_IBEAM; - break; - case Qt::SizeVerCursor: - sh = IDC_SIZENS; - break; - case Qt::SizeHorCursor: - sh = IDC_SIZEWE; - break; - case Qt::SizeBDiagCursor: - sh = IDC_SIZENESW; - break; - case Qt::SizeFDiagCursor: - sh = IDC_SIZENWSE; - break; - case Qt::SizeAllCursor: - sh = IDC_SIZEALL; - break; - case Qt::ForbiddenCursor: - sh = IDC_NO; - break; - case Qt::WhatsThisCursor: - sh = IDC_HELP; - break; - case Qt::BusyCursor: - sh = IDC_APPSTARTING; - break; - case Qt::PointingHandCursor: - sh = IDC_HAND; - break; - case Qt::BlankCursor: + static const char * const moveDragCursorXpmC[] = { + "11 20 3 1", + ". c None", + "a c #FFFFFF", + "X c #000000", // X11 cursor is traditionally black + "aa.........", + "aXa........", + "aXXa.......", + "aXXXa......", + "aXXXXa.....", + "aXXXXXa....", + "aXXXXXXa...", + "aXXXXXXXa..", + "aXXXXXXXXa.", + "aXXXXXXXXXa", + "aXXXXXXaaaa", + "aXXXaXXa...", + "aXXaaXXa...", + "aXa..aXXa..", + "aa...aXXa..", + "a.....aXXa.", + "......aXXa.", + ".......aXXa", + ".......aXXa", + "........aa."}; + + static const char * const copyDragCursorXpmC[] = { + "24 30 3 1", + ". c None", + "a c #000000", + "X c #FFFFFF", + "XX......................", + "XaX.....................", + "XaaX....................", + "XaaaX...................", + "XaaaaX..................", + "XaaaaaX.................", + "XaaaaaaX................", + "XaaaaaaaX...............", + "XaaaaaaaaX..............", + "XaaaaaaaaaX.............", + "XaaaaaaXXXX.............", + "XaaaXaaX................", + "XaaXXaaX................", + "XaX..XaaX...............", + "XX...XaaX...............", + "X.....XaaX..............", + "......XaaX..............", + ".......XaaX.............", + ".......XaaX.............", + "........XX...aaaaaaaaaaa", + ".............aXXXXXXXXXa", + ".............aXXXXXXXXXa", + ".............aXXXXaXXXXa", + ".............aXXXXaXXXXa", + ".............aXXaaaaaXXa", + ".............aXXXXaXXXXa", + ".............aXXXXaXXXXa", + ".............aXXXXXXXXXa", + ".............aXXXXXXXXXa", + ".............aaaaaaaaaaa"}; + + static const char * const linkDragCursorXpmC[] = { + "24 30 3 1", + ". c None", + "a c #000000", + "X c #FFFFFF", + "XX......................", + "XaX.....................", + "XaaX....................", + "XaaaX...................", + "XaaaaX..................", + "XaaaaaX.................", + "XaaaaaaX................", + "XaaaaaaaX...............", + "XaaaaaaaaX..............", + "XaaaaaaaaaX.............", + "XaaaaaaXXXX.............", + "XaaaXaaX................", + "XaaXXaaX................", + "XaX..XaaX...............", + "XX...XaaX...............", + "X.....XaaX..............", + "......XaaX..............", + ".......XaaX.............", + ".......XaaX.............", + "........XX...aaaaaaaaaaa", + ".............aXXXXXXXXXa", + ".............aXXXaaaaXXa", + ".............aXXXXaaaXXa", + ".............aXXXaaaaXXa", + ".............aXXaaaXaXXa", + ".............aXXaaXXXXXa", + ".............aXXaXXXXXXa", + ".............aXXXaXXXXXa", + ".............aXXXXXXXXXa", + ".............aaaaaaaaaaa"}; + + switch (cursorShape) { case Qt::SplitVCursor: + return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 32, vsplit_bits, vsplitm_bits); case Qt::SplitHCursor: + return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 32, hsplit_bits, hsplitm_bits); case Qt::OpenHandCursor: + return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 16, openhand_bits, openhandm_bits); case Qt::ClosedHandCursor: - case Qt::BitmapCursor: { - QImage bbits, mbits; - bool invb, invm; - if (cshape == Qt::BlankCursor) { - bbits = QImage(32, 32, QImage::Format_Mono); - bbits.fill(0); // ignore color table - mbits = bbits.copy(); - hx = hy = 16; - invb = invm = false; - } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) { - bool open = cshape == Qt::OpenHandCursor; - QBitmap cb = QBitmap::fromData(QSize(16, 16), open ? openhand_bits : closedhand_bits); - QBitmap cm = QBitmap::fromData(QSize(16, 16), open ? openhandm_bits : closedhandm_bits); - bbits = cb.toImage().convertToFormat(QImage::Format_Mono); - mbits = cm.toImage().convertToFormat(QImage::Format_Mono); - hx = hy = 8; - invb = invm = false; - } else if (cshape == Qt::BitmapCursor) { - bbits = c.bitmap()->toImage().convertToFormat(QImage::Format_Mono); - mbits = c.mask()->toImage().convertToFormat(QImage::Format_Mono); - invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1)); - invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1)); - } else { // Qt::SplitVCursor, Qt::SplitHCursor - const QBitmap cb = QBitmap::fromData(QSize(32, 32), cshape == Qt::SplitVCursor ? vsplit_bits : hsplit_bits); - const QBitmap cm = QBitmap::fromData(QSize(32, 32), cshape == Qt::SplitVCursor ? vsplitm_bits : hsplitm_bits); - bbits = cb.toImage().convertToFormat(QImage::Format_Mono); - mbits = cm.toImage().convertToFormat(QImage::Format_Mono); - hx = hy = 16; - invb = invm = false; - } - const int n = qMax(1, bbits.width() / 8); - const int h = bbits.height(); -#if !defined(Q_OS_WINCE) - QScopedArrayPointer<uchar> xBits(new uchar[h * n]); - QScopedArrayPointer<uchar> xMask(new uchar[h * n]); - int x = 0; - for (int i = 0; i < h; ++i) { - uchar *bits = bbits.scanLine(i); - uchar *mask = mbits.scanLine(i); - for (int j = 0; j < n; ++j) { - uchar b = bits[j]; - uchar m = mask[j]; - if (invb) - b ^= 0xff; - if (invm) - m ^= 0xff; - xBits[x] = ~m; - xMask[x] = b ^ m; - ++x; - } - } - return CreateCursor(GetModuleHandle(0), hx, hy, bbits.width(), bbits.height(), - xBits.data(), xMask.data()); -#elif defined(GWES_ICONCURS) // Q_WS_WINCE - // Windows CE only supports fixed cursor size. - int sysW = GetSystemMetrics(SM_CXCURSOR); - int sysH = GetSystemMetrics(SM_CYCURSOR); - int sysN = qMax(1, sysW / 8); - uchar* xBits = new uchar[sysH * sysN]; - uchar* xMask = new uchar[sysH * sysN]; - int x = 0; - for (int i = 0; i < sysH; ++i) { - if (i >= h) { - memset(&xBits[x] , 255, sysN); - memset(&xMask[x] , 0, sysN); - x += sysN; - } else { - int fillWidth = n > sysN ? sysN : n; - uchar *bits = bbits.scanLine(i); - uchar *mask = mbits.scanLine(i); - for (int j = 0; j < fillWidth; ++j) { - uchar b = bits[j]; - uchar m = mask[j]; - if (invb) - b ^= 0xFF; - if (invm) - m ^= 0xFF; - xBits[x] = ~m; - xMask[x] = b ^ m; - ++x; - } - for (int j = fillWidth; j < sysN; ++j ) { - xBits[x] = 255; - xMask[x] = 0; - ++x; - } - } + return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 16, closedhand_bits, closedhandm_bits); + case Qt::DragCopyCursor: + return QCursor(QPixmap(copyDragCursorXpmC), 0, 0); + case Qt::DragMoveCursor: + return QCursor(QPixmap(moveDragCursorXpmC), 0, 0); + case Qt::DragLinkCursor: + return QCursor(QPixmap(linkDragCursorXpmC), 0, 0); + } + + return QCursor(); +} +#else // Q_OS_WINCE || QT_NO_IMAGEFORMAT_PNG +struct QWindowsCustomPngCursor { + Qt::CursorShape shape; + int size; + const char *fileName; + int hotSpotX; + int hotSpotY; +}; + +QCursor QWindowsCursor::customCursor(Qt::CursorShape cursorShape) +{ + static const QWindowsCustomPngCursor pngCursors[] = { + { Qt::SplitVCursor, 32, "splitvcursor_32.png", 11, 11 }, + { Qt::SplitVCursor, 48, "splitvcursor_48.png", 16, 17 }, + { Qt::SplitVCursor, 64, "splitvcursor_64.png", 22, 22 }, + { Qt::SplitHCursor, 32, "splithcursor_32.png", 11, 11 }, + { Qt::SplitHCursor, 48, "splithcursor_48.png", 16, 17 }, + { Qt::SplitHCursor, 64, "splithcursor_64.png", 22, 22 }, + { Qt::OpenHandCursor, 32, "openhandcursor_32.png", 10, 12 }, + { Qt::OpenHandCursor, 48, "openhandcursor_48.png", 15, 16 }, + { Qt::OpenHandCursor, 64, "openhandcursor_64.png", 20, 24 }, + { Qt::ClosedHandCursor, 32, "closedhandcursor_32.png", 10, 12 }, + { Qt::ClosedHandCursor, 48, "closedhandcursor_48.png", 15, 16 }, + { Qt::ClosedHandCursor, 64, "closedhandcursor_64.png", 20, 24 }, + { Qt::DragCopyCursor, 32, "dragcopycursor_32.png", 0, 0 }, + { Qt::DragCopyCursor, 48, "dragcopycursor_48.png", 0, 0 }, + { Qt::DragCopyCursor, 64, "dragcopycursor_64.png", 0, 0 }, + { Qt::DragMoveCursor, 32, "dragmovecursor_32.png", 0, 0 }, + { Qt::DragMoveCursor, 48, "dragmovecursor_48.png", 0, 0 }, + { Qt::DragMoveCursor, 64, "dragmovecursor_64.png", 0, 0 }, + { Qt::DragLinkCursor, 32, "draglinkcursor_32.png", 0, 0 }, + { Qt::DragLinkCursor, 48, "draglinkcursor_48.png", 0, 0 }, + { Qt::DragLinkCursor, 64, "draglinkcursor_64.png", 0, 0 } + }; + + const int cursorSize = GetSystemMetrics(SM_CXCURSOR); + const QWindowsCustomPngCursor *sEnd = pngCursors + sizeof(pngCursors) / sizeof(pngCursors[0]); + const QWindowsCustomPngCursor *bestFit = 0; + int sizeDelta = INT_MAX; + for (const QWindowsCustomPngCursor *s = pngCursors; s < sEnd; ++s) { + if (s->shape != cursorShape) + continue; + const int currentSizeDelta = qMax(s->size, cursorSize) - qMin(s->size, cursorSize); + if (currentSizeDelta < sizeDelta) { + bestFit = s; + if (currentSizeDelta == 0) + break; // Perfect match found + sizeDelta = currentSizeDelta; } + } - HCURSOR hcurs = CreateCursor(qWinAppInst(), hx, hy, sysW, sysH, - xBits, xMask); - delete [] xBits; - delete [] xMask; - return hcurs; -#else - Q_UNUSED(n); - Q_UNUSED(h); - return 0; -#endif + if (!bestFit) + return QCursor(); + const QPixmap rawImage(QStringLiteral(":/qt-project.org/windows/cursors/images/") + + QString::fromLatin1(bestFit->fileName)); + return QCursor(rawImage, bestFit->hotSpotX, bestFit->hotSpotY); +} +#endif // Q_OS_WINCE || QT_NO_IMAGEFORMAT_PNG + +struct QWindowsStandardCursorMapping { + Qt::CursorShape shape; + LPCWSTR resource; +}; + +HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) +{ + static const QWindowsStandardCursorMapping standardCursors[] = { + { Qt::ArrowCursor, IDC_ARROW}, + { Qt::UpArrowCursor, IDC_UPARROW }, + { Qt::CrossCursor, IDC_CROSS }, + { Qt::WaitCursor, IDC_WAIT }, + { Qt::IBeamCursor, IDC_IBEAM }, + { Qt::SizeVerCursor, IDC_SIZENS }, + { Qt::SizeHorCursor, IDC_SIZEWE }, + { Qt::SizeBDiagCursor, IDC_SIZENESW }, + { Qt::SizeFDiagCursor, IDC_SIZENWSE }, + { Qt::SizeAllCursor, IDC_SIZEALL }, + { Qt::ForbiddenCursor, IDC_NO }, + { Qt::WhatsThisCursor, IDC_HELP }, + { Qt::BusyCursor, IDC_APPSTARTING }, + { Qt::PointingHandCursor, IDC_HAND } + }; + + const Qt::CursorShape cursorShape = c.shape(); + switch (cursorShape) { + case Qt::BitmapCursor: { + const QPixmap pixmap = c.pixmap(); + if (!pixmap.isNull()) + return QWindowsCursor::createPixmapCursor(pixmap, c.hotSpot()); + const QImage bbits = c.bitmap()->toImage().convertToFormat(QImage::Format_Mono); + const QImage mbits = c.mask()->toImage().convertToFormat(QImage::Format_Mono); + const bool invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1)); + const bool invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1)); + return createBitmapCursor(bbits, mbits, c.hotSpot(), invb, invm); } + case Qt::BlankCursor: { + QImage blank = QImage(systemCursorSize(), QImage::Format_Mono); + blank.fill(0); // ignore color table + return createBitmapCursor(blank, blank); + } + case Qt::SplitVCursor: + case Qt::SplitHCursor: + case Qt::OpenHandCursor: + case Qt::ClosedHandCursor: case Qt::DragCopyCursor: case Qt::DragMoveCursor: - case Qt::DragLinkCursor: { - const QPixmap pixmap = QGuiApplicationPrivate::instance()->getPixmapCursor(cshape); - return createPixmapCursor(pixmap, hx, hy); - } + case Qt::DragLinkCursor: + return createSystemCursor(customCursor(cursorShape)); default: - qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cshape); - return 0; + break; } -#ifdef Q_OS_WINCE - return LoadCursor(0, sh); + + // Load available standard cursors from resources + const QWindowsStandardCursorMapping *sEnd = standardCursors + sizeof(standardCursors) / sizeof(standardCursors[0]); + for (const QWindowsStandardCursorMapping *s = standardCursors; s < sEnd; ++s) { + if (s->shape == cursorShape) { +#ifndef Q_OS_WINCE + return (HCURSOR)LoadImage(0, s->resource, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); #else - return (HCURSOR)LoadImage(0, sh, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + return LoadCursor(0, s->resource); #endif + } + } + + qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cursorShape); + return 0; } /*! diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index 31da4e367d..34cb668856 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -101,12 +101,13 @@ public: QWindowsCursor() {} - virtual void changeCursor(QCursor * widgetCursor, QWindow * widget); - virtual QPoint pos() const { return mousePosition(); } - virtual void setPos(const QPoint &pos); + void changeCursor(QCursor * widgetCursor, QWindow * widget) Q_DECL_OVERRIDE; + QPoint pos() const Q_DECL_OVERRIDE { return mousePosition(); } + void setPos(const QPoint &pos) Q_DECL_OVERRIDE; - static HCURSOR createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY); + static HCURSOR createPixmapCursor(const QPixmap &pixmap, const QPoint &hotSpot); static HCURSOR createSystemCursor(const QCursor &c); + static QCursor customCursor(Qt::CursorShape cursorShape); static QPoint mousePosition(); static CursorState cursorState(); diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h index bcf9f544b5..864c9e40f5 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h @@ -71,11 +71,11 @@ public: typedef QSharedPointer<QWindowsNativeDialogBase> QWindowsNativeDialogBasePtr; ~QWindowsDialogHelperBase() { cleanupThread(); } - virtual void exec(); + void exec() Q_DECL_OVERRIDE; virtual bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent); - virtual void hide(); + void hide() Q_DECL_OVERRIDE; virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; } diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 60c3daff23..861ddbe5b6 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -69,146 +69,6 @@ QT_BEGIN_NAMESPACE -// These pixmaps approximate the images in the Windows User Interface Guidelines. -// XPM - -static const char * const moveDragCursorXpmC[] = { -"11 20 3 1", -". c None", -"a c #FFFFFF", -"X c #000000", // X11 cursor is traditionally black -"aa.........", -"aXa........", -"aXXa.......", -"aXXXa......", -"aXXXXa.....", -"aXXXXXa....", -"aXXXXXXa...", -"aXXXXXXXa..", -"aXXXXXXXXa.", -"aXXXXXXXXXa", -"aXXXXXXaaaa", -"aXXXaXXa...", -"aXXaaXXa...", -"aXa..aXXa..", -"aa...aXXa..", -"a.....aXXa.", -"......aXXa.", -".......aXXa", -".......aXXa", -"........aa."}; - - -/* XPM */ -static const char * const copyDragCursorXpmC[] = { -"24 30 3 1", -". c None", -"a c #000000", -"X c #FFFFFF", -"XX......................", -"XaX.....................", -"XaaX....................", -"XaaaX...................", -"XaaaaX..................", -"XaaaaaX.................", -"XaaaaaaX................", -"XaaaaaaaX...............", -"XaaaaaaaaX..............", -"XaaaaaaaaaX.............", -"XaaaaaaXXXX.............", -"XaaaXaaX................", -"XaaXXaaX................", -"XaX..XaaX...............", -"XX...XaaX...............", -"X.....XaaX..............", -"......XaaX..............", -".......XaaX.............", -".......XaaX.............", -"........XX...aaaaaaaaaaa", -".............aXXXXXXXXXa", -".............aXXXXXXXXXa", -".............aXXXXaXXXXa", -".............aXXXXaXXXXa", -".............aXXaaaaaXXa", -".............aXXXXaXXXXa", -".............aXXXXaXXXXa", -".............aXXXXXXXXXa", -".............aXXXXXXXXXa", -".............aaaaaaaaaaa"}; - -/* XPM */ -static const char * const linkDragCursorXpmC[] = { -"24 30 3 1", -". c None", -"a c #000000", -"X c #FFFFFF", -"XX......................", -"XaX.....................", -"XaaX....................", -"XaaaX...................", -"XaaaaX..................", -"XaaaaaX.................", -"XaaaaaaX................", -"XaaaaaaaX...............", -"XaaaaaaaaX..............", -"XaaaaaaaaaX.............", -"XaaaaaaXXXX.............", -"XaaaXaaX................", -"XaaXXaaX................", -"XaX..XaaX...............", -"XX...XaaX...............", -"X.....XaaX..............", -"......XaaX..............", -".......XaaX.............", -".......XaaX.............", -"........XX...aaaaaaaaaaa", -".............aXXXXXXXXXa", -".............aXXXaaaaXXa", -".............aXXXXaaaXXa", -".............aXXXaaaaXXa", -".............aXXaaaXaXXa", -".............aXXaaXXXXXa", -".............aXXaXXXXXXa", -".............aXXXaXXXXXa", -".............aXXXXXXXXXa", -".............aaaaaaaaaaa"}; - -static const char * const ignoreDragCursorXpmC[] = { -"24 30 3 1", -". c None", -"a c #000000", -"X c #FFFFFF", -"aa......................", -"aXa.....................", -"aXXa....................", -"aXXXa...................", -"aXXXXa..................", -"aXXXXXa.................", -"aXXXXXXa................", -"aXXXXXXXa...............", -"aXXXXXXXXa..............", -"aXXXXXXXXXa.............", -"aXXXXXXaaaa.............", -"aXXXaXXa................", -"aXXaaXXa................", -"aXa..aXXa...............", -"aa...aXXa...............", -"a.....aXXa..............", -"......aXXa.....XXXX.....", -".......aXXa..XXaaaaXX...", -".......aXXa.XaaaaaaaaX..", -"........aa.XaaaXXXXaaaX.", -"...........XaaaaX..XaaX.", -"..........XaaXaaaX..XaaX", -"..........XaaXXaaaX.XaaX", -"..........XaaX.XaaaXXaaX", -"..........XaaX..XaaaXaaX", -"...........XaaX..XaaaaX.", -"...........XaaaXXXXaaaX.", -"............XaaaaaaaaX..", -".............XXaaaaXX...", -"...............XXXX....."}; - /*! \class QWindowsDragCursorWindow \brief A toplevel window showing the drag icon in case of touch drag. @@ -490,7 +350,7 @@ void QWindowsOleDropSource::createCursors() newHotSpot = QPoint(qMax(0, hotSpot.x()), qMax(0, hotSpot.y())); } - if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newPixmap, newHotSpot.x(), newHotSpot.y())) { + if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newPixmap, newHotSpot)) { const CursorEntry entry(newPixmap, cacheKey, DragCursorHandlePtr(new DragCursorHandle(sysCursor)), newHotSpot); if (it == m_cursors.end()) m_cursors.insert(action, entry); @@ -864,22 +724,86 @@ QPixmap QWindowsDrag::defaultCursor(Qt::DropAction action) const switch (action) { case Qt::CopyAction: if (m_copyDragCursor.isNull()) - m_copyDragCursor = QPixmap(copyDragCursorXpmC); + m_copyDragCursor = QWindowsCursor::customCursor(Qt::DragCopyCursor).pixmap(); return m_copyDragCursor; case Qt::TargetMoveAction: case Qt::MoveAction: if (m_moveDragCursor.isNull()) - m_moveDragCursor = QPixmap(moveDragCursorXpmC); + m_moveDragCursor = QWindowsCursor::customCursor(Qt::DragMoveCursor).pixmap(); return m_moveDragCursor; case Qt::LinkAction: if (m_linkDragCursor.isNull()) - m_linkDragCursor = QPixmap(linkDragCursorXpmC); + m_linkDragCursor = QWindowsCursor::customCursor(Qt::DragLinkCursor).pixmap(); return m_linkDragCursor; default: break; } - if (m_ignoreDragCursor.isNull()) + + static const char * const ignoreDragCursorXpmC[] = { + "24 30 3 1", + ". c None", + "a c #000000", + "X c #FFFFFF", + "aa......................", + "aXa.....................", + "aXXa....................", + "aXXXa...................", + "aXXXXa..................", + "aXXXXXa.................", + "aXXXXXXa................", + "aXXXXXXXa...............", + "aXXXXXXXXa..............", + "aXXXXXXXXXa.............", + "aXXXXXXaaaa.............", + "aXXXaXXa................", + "aXXaaXXa................", + "aXa..aXXa...............", + "aa...aXXa...............", + "a.....aXXa..............", + "......aXXa.....XXXX.....", + ".......aXXa..XXaaaaXX...", + ".......aXXa.XaaaaaaaaX..", + "........aa.XaaaXXXXaaaX.", + "...........XaaaaX..XaaX.", + "..........XaaXaaaX..XaaX", + "..........XaaXXaaaX.XaaX", + "..........XaaX.XaaaXXaaX", + "..........XaaX..XaaaXaaX", + "...........XaaX..XaaaaX.", + "...........XaaaXXXXaaaX.", + "............XaaaaaaaaX..", + ".............XXaaaaXX...", + "...............XXXX....."}; + + if (m_ignoreDragCursor.isNull()) { +#if !defined (Q_OS_WINCE) + HCURSOR cursor = LoadCursor(NULL, IDC_NO); + ICONINFO iconInfo = {0, 0, 0, 0, 0}; + GetIconInfo(cursor, &iconInfo); + BITMAP bmColor = {0, 0, 0, 0, 0, 0, 0}; + + if (iconInfo.hbmColor + && GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmColor) + && bmColor.bmWidth == bmColor.bmWidthBytes / 4) { + const int colorBitsLength = bmColor.bmHeight * bmColor.bmWidthBytes; + uchar *colorBits = new uchar[colorBitsLength]; + GetBitmapBits(iconInfo.hbmColor, colorBitsLength, colorBits); + const QImage colorImage(colorBits, bmColor.bmWidth, bmColor.bmHeight, + bmColor.bmWidthBytes, QImage::Format_ARGB32); + + m_ignoreDragCursor = QPixmap::fromImage(colorImage); + delete [] colorBits; + } else { + m_ignoreDragCursor = QPixmap(ignoreDragCursorXpmC); + } + + DeleteObject(iconInfo.hbmMask); + DeleteObject(iconInfo.hbmColor); + DestroyCursor(cursor); +#else // !Q_OS_WINCE m_ignoreDragCursor = QPixmap(ignoreDragCursorXpmC); +#endif // !Q_OS_WINCE + } return m_ignoreDragCursor; } diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h index 4f758fbf3f..b4d303a10f 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.h +++ b/src/plugins/platforms/windows/qwindowsdrag.h @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE class QWindowsDropMimeData : public QWindowsInternalMimeData { public: QWindowsDropMimeData() {} - virtual IDataObject *retrieveDataObject() const; + IDataObject *retrieveDataObject() const Q_DECL_OVERRIDE; }; class QWindowsOleDropTarget : public IDropTarget @@ -90,9 +90,9 @@ public: QWindowsDrag(); virtual ~QWindowsDrag(); - virtual QMimeData *platformDropData() { return &m_dropData; } + QMimeData *platformDropData() Q_DECL_OVERRIDE { return &m_dropData; } - virtual Qt::DropAction drag(QDrag *drag); + Qt::DropAction drag(QDrag *drag) Q_DECL_OVERRIDE; static QWindowsDrag *instance(); diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index d5ca06bb3f..c62875d0ef 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -46,23 +46,297 @@ #include <QtCore/QDebug> #include <QtGui/QOpenGLContext> -#include <QtPlatformSupport/private/qeglconvenience_p.h> - QT_BEGIN_NAMESPACE /*! \class QWindowsEGLStaticContext \brief Static data for QWindowsEGLContext. - Keeps the display. The class is shared via - QSharedPointer in the windows, the contexts - and in QWindowsIntegration. The display will - be closed if the last instance is deleted. + Keeps the display. The class is shared via QSharedPointer in the windows, the + contexts and in QWindowsIntegration. The display will be closed if the last instance + is deleted. + + No EGL or OpenGL functions are called directly. Instead, they are resolved + dynamically. This works even if the plugin links directly to libegl/libglesv2 so + there is no need to differentiate between dynamic or Angle-only builds in here. \internal \ingroup qt-lighthouse-win */ +QWindowsLibEGL QWindowsEGLStaticContext::libEGL; +QWindowsLibGLESv2 QWindowsEGLStaticContext::libGLESv2; + +#ifndef QT_STATIC + +#ifdef Q_CC_MINGW +static void *resolveFunc(HMODULE lib, const char *name) +{ + QString baseNameStr = QString::fromLatin1(name); + QString nameStr; + void *proc = 0; + + // Play nice with 32-bit mingw: Try func first, then func@0, func@4, + // func@8, func@12, ..., func@64. The def file does not provide any aliases + // in libEGL and libGLESv2 in these builds which results in exporting + // function names like eglInitialize@12. This cannot be fixed without + // breaking binary compatibility. So be flexible here instead. + + int argSize = -1; + while (!proc && argSize <= 64) { + nameStr = baseNameStr; + if (argSize >= 0) + nameStr += QLatin1Char('@') + QString::number(argSize); + argSize = argSize < 0 ? 0 : argSize + 4; + proc = (void *) ::GetProcAddress(lib, nameStr.toLatin1().constData()); + } + return proc; +} +#else +static void *resolveFunc(HMODULE lib, const char *name) +{ +# ifndef Q_OS_WINCE + return (void *) ::GetProcAddress(lib, name); +# else + return (void *) ::GetProcAddress(lib, (const wchar_t *) QString::fromLatin1(name).utf16()); +# endif // Q_OS_WINCE +} +#endif // Q_CC_MINGW + +void *QWindowsLibEGL::resolve(const char *name) +{ + void *proc = m_lib ? resolveFunc(m_lib, name) : 0; + if (!proc) + qErrnoWarning(::GetLastError(), "Failed to resolve EGL function %s", name); + + return proc; +} + +#endif // !QT_STATIC + +#ifndef QT_STATIC +# define RESOLVE(signature, name) signature(resolve( #name )); +#else +# define RESOLVE(signature, name) signature(&::name); +#endif + +bool QWindowsLibEGL::init() +{ +#ifdef QT_DEBUG + const char dllName[] = "libEGLd.dll"; +#else + const char dllName[] = "libEGL.dll"; +#endif + + qCDebug(lcQpaGl) << "Qt: Using EGL from" << dllName; + +#ifndef QT_STATIC + m_lib = ::LoadLibraryW((const wchar_t *) QString::fromLatin1(dllName).utf16()); + if (!m_lib) { + qErrnoWarning(::GetLastError(), "Failed to load %s", dllName); + return false; + } +#endif + + eglGetError = RESOLVE((EGLint (EGLAPIENTRY *)(void)), eglGetError); + eglGetDisplay = RESOLVE((EGLDisplay (EGLAPIENTRY *)(EGLNativeDisplayType)), eglGetDisplay); + eglInitialize = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLint *, EGLint *)), eglInitialize); + eglTerminate = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay)), eglTerminate); + eglChooseConfig = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)), eglChooseConfig); + eglGetConfigAttrib = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLConfig, EGLint, EGLint *)), eglGetConfigAttrib); + eglCreateWindowSurface = RESOLVE((EGLSurface (EGLAPIENTRY *)(EGLDisplay, EGLConfig, EGLNativeWindowType, const EGLint *)), eglCreateWindowSurface); + eglCreatePbufferSurface = RESOLVE((EGLSurface (EGLAPIENTRY *)(EGLDisplay , EGLConfig, const EGLint *)), eglCreatePbufferSurface); + eglDestroySurface = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface )), eglDestroySurface); + eglBindAPI = RESOLVE((EGLBoolean (EGLAPIENTRY * )(EGLenum )), eglBindAPI); + eglSwapInterval = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLint )), eglSwapInterval); + eglCreateContext = RESOLVE((EGLContext (EGLAPIENTRY *)(EGLDisplay , EGLConfig , EGLContext , const EGLint *)), eglCreateContext); + eglDestroyContext = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLContext)), eglDestroyContext); + eglMakeCurrent = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface , EGLSurface , EGLContext )), eglMakeCurrent); + eglGetCurrentContext = RESOLVE((EGLContext (EGLAPIENTRY *)(void)), eglGetCurrentContext); + eglGetCurrentSurface = RESOLVE((EGLSurface (EGLAPIENTRY *)(EGLint )), eglGetCurrentSurface); + eglGetCurrentDisplay = RESOLVE((EGLDisplay (EGLAPIENTRY *)(void)), eglGetCurrentDisplay); + eglSwapBuffers = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface)), eglSwapBuffers); + eglGetProcAddress = RESOLVE((__eglMustCastToProperFunctionPointerType (EGLAPIENTRY * )(const char *)), eglGetProcAddress); + + return eglGetError && eglGetDisplay && eglInitialize; +} + +#ifndef QT_STATIC +void *QWindowsLibGLESv2::resolve(const char *name) +{ + void *proc = m_lib ? resolveFunc(m_lib, name) : 0; + if (!proc) + qWarning() << "Failed to resolve OpenGL ES function" << name; + + return proc; +} +#endif // !QT_STATIC + +bool QWindowsLibGLESv2::init() +{ +#ifdef QT_DEBUG + const char dllName[] = "libGLESv2d.dll"; +#else + const char dllName[] = "libGLESv2.dll"; +#endif + + qCDebug(lcQpaGl) << "Qt: Using OpenGL ES 2.0 from" << dllName; +#ifndef QT_STATIC + m_lib = ::LoadLibraryW((const wchar_t *) QString::fromLatin1(dllName).utf16()); + if (!m_lib) { + qErrnoWarning(::GetLastError(), "Failed to load %s", dllName); + return false; + } +#endif // !QT_STATIC + + glBindTexture = RESOLVE((void (APIENTRY *)(GLenum , GLuint )), glBindTexture); + glBlendFunc = RESOLVE((void (APIENTRY *)(GLenum , GLenum )), glBlendFunc); + glClear = RESOLVE((void (APIENTRY *)(GLbitfield )), glClear); + glClearColor = RESOLVE((void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )), glClearColor); + glClearStencil = RESOLVE((void (APIENTRY *)(GLint )), glClearStencil); + glColorMask = RESOLVE((void (APIENTRY *)(GLboolean , GLboolean , GLboolean , GLboolean )), glColorMask); + glCopyTexImage2D = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLenum , GLint , GLint , GLsizei , GLsizei , GLint )), glCopyTexImage2D); + glCopyTexSubImage2D = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLint , GLint , GLsizei , GLsizei )), glCopyTexSubImage2D); + glCullFace = RESOLVE((void (APIENTRY *)(GLenum )), glCullFace); + glDeleteTextures = RESOLVE((void (APIENTRY *)(GLsizei , const GLuint *)), glDeleteTextures); + glDepthFunc = RESOLVE((void (APIENTRY *)(GLenum )), glDepthFunc); + glDepthMask = RESOLVE((void (APIENTRY *)(GLboolean )), glDepthMask); + glDisable = RESOLVE((void (APIENTRY *)(GLenum )), glDisable); + glDrawArrays = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLsizei )), glDrawArrays); + glDrawElements = RESOLVE((void (APIENTRY *)(GLenum , GLsizei , GLenum , const GLvoid *)), glDrawElements); + glEnable = RESOLVE((void (APIENTRY *)(GLenum )), glEnable); + glFinish = RESOLVE((void (APIENTRY *)()), glFinish); + glFlush = RESOLVE((void (APIENTRY *)()), glFlush); + glFrontFace = RESOLVE((void (APIENTRY *)(GLenum )), glFrontFace); + glGenTextures = RESOLVE((void (APIENTRY *)(GLsizei , GLuint *)), glGenTextures); + glGetBooleanv = RESOLVE((void (APIENTRY *)(GLenum , GLboolean *)), glGetBooleanv); + glGetError = RESOLVE((GLenum (APIENTRY *)()), glGetError); + glGetFloatv = RESOLVE((void (APIENTRY *)(GLenum , GLfloat *)), glGetFloatv); + glGetIntegerv = RESOLVE((void (APIENTRY *)(GLenum , GLint *)), glGetIntegerv); + glGetString = RESOLVE((const GLubyte * (APIENTRY *)(GLenum )), glGetString); + glGetTexParameterfv = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLfloat *)), glGetTexParameterfv); + glGetTexParameteriv = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLint *)), glGetTexParameteriv); + glHint = RESOLVE((void (APIENTRY *)(GLenum , GLenum )), glHint); + glIsEnabled = RESOLVE((GLboolean (APIENTRY *)(GLenum )), glIsEnabled); + glIsTexture = RESOLVE((GLboolean (APIENTRY *)(GLuint )), glIsTexture); + glLineWidth = RESOLVE((void (APIENTRY *)(GLfloat )), glLineWidth); + glPixelStorei = RESOLVE((void (APIENTRY *)(GLenum , GLint )), glPixelStorei); + glPolygonOffset = RESOLVE((void (APIENTRY *)(GLfloat , GLfloat )), glPolygonOffset); + glReadPixels = RESOLVE((void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , GLvoid *)), glReadPixels); + glScissor = RESOLVE((void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )), glScissor); + glStencilFunc = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLuint )), glStencilFunc); + glStencilMask = RESOLVE((void (APIENTRY *)(GLuint )), glStencilMask); + glStencilOp = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLenum )), glStencilOp); + glTexImage2D = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLint , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)), glTexImage2D); + glTexParameterf = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLfloat )), glTexParameterf); + glTexParameterfv = RESOLVE((void (APIENTRY *)(GLenum , GLenum , const GLfloat *)), glTexParameterfv); + glTexParameteri = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLint )), glTexParameteri); + glTexParameteriv = RESOLVE((void (APIENTRY *)(GLenum , GLenum , const GLint *)), glTexParameteriv); + glTexSubImage2D = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)), glTexSubImage2D); + glViewport = RESOLVE((void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )), glViewport); + + glActiveTexture = RESOLVE((void (APIENTRY *)(GLenum)), glActiveTexture); + glAttachShader = RESOLVE((void (APIENTRY *)(GLuint , GLuint )), glAttachShader); + glBindAttribLocation = RESOLVE((void (APIENTRY *)(GLuint , GLuint , const GLchar* )), glBindAttribLocation); + glBindBuffer = RESOLVE((void (APIENTRY *)(GLenum , GLuint )), glBindBuffer); + glBindFramebuffer = RESOLVE((void (APIENTRY *)(GLenum , GLuint )), glBindFramebuffer); + glBindRenderbuffer = RESOLVE((void (APIENTRY *)(GLenum , GLuint )), glBindRenderbuffer); + glBlendColor = RESOLVE((void (APIENTRY *)(GLclampf , GLclampf , GLclampf , GLclampf )), glBlendColor); + glBlendEquation = RESOLVE((void (APIENTRY *)(GLenum )), glBlendEquation); + glBlendEquationSeparate = RESOLVE((void (APIENTRY *)(GLenum , GLenum )), glBlendEquationSeparate); + glBlendFuncSeparate = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLenum , GLenum )), glBlendFuncSeparate); + glBufferData = RESOLVE((void (APIENTRY *)(GLenum , qopengl_GLsizeiptr , const GLvoid* , GLenum )), glBufferData); + glBufferSubData = RESOLVE((void (APIENTRY *)(GLenum , qopengl_GLintptr , qopengl_GLsizeiptr , const GLvoid* )), glBufferSubData); + glCheckFramebufferStatus = RESOLVE((GLenum (APIENTRY *)(GLenum )), glCheckFramebufferStatus); + glCompileShader = RESOLVE((void (APIENTRY *)(GLuint )), glCompileShader); + glCompressedTexImage2D = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLenum , GLsizei , GLsizei, GLint, GLsizei, const GLvoid* )), glCompressedTexImage2D); + glCompressedTexSubImage2D = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLint , GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid* )), glCompressedTexSubImage2D); + glCreateProgram = RESOLVE((GLuint (APIENTRY *)(void)), glCreateProgram); + glCreateShader = RESOLVE((GLuint (APIENTRY *)(GLenum )), glCreateShader); + glDeleteBuffers = RESOLVE((void (APIENTRY *)(GLsizei , const GLuint*)), glDeleteBuffers); + glDeleteFramebuffers = RESOLVE((void (APIENTRY *)(GLsizei , const GLuint* )), glDeleteFramebuffers); + glDeleteProgram = RESOLVE((void (APIENTRY *)(GLuint )), glDeleteProgram); + glDeleteRenderbuffers = RESOLVE((void (APIENTRY *)(GLsizei , const GLuint* )), glDeleteRenderbuffers); + glDeleteShader = RESOLVE((void (APIENTRY *)(GLuint )), glDeleteShader); + glDetachShader = RESOLVE((void (APIENTRY *)(GLuint , GLuint )), glDetachShader); + glDisableVertexAttribArray = RESOLVE((void (APIENTRY *)(GLuint )), glDisableVertexAttribArray); + glEnableVertexAttribArray = RESOLVE((void (APIENTRY *)(GLuint )), glEnableVertexAttribArray); + glFramebufferRenderbuffer = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLenum , GLuint )), glFramebufferRenderbuffer); + glFramebufferTexture2D = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLenum , GLuint , GLint )), glFramebufferTexture2D); + glGenBuffers = RESOLVE((void (APIENTRY *)(GLsizei , GLuint* )), glGenBuffers); + glGenerateMipmap = RESOLVE((void (APIENTRY *)(GLenum )), glGenerateMipmap); + glGenFramebuffers = RESOLVE((void (APIENTRY *)(GLsizei , GLuint* )), glGenFramebuffers); + glGenRenderbuffers = RESOLVE((void (APIENTRY *)(GLsizei , GLuint* )), glGenRenderbuffers); + glGetActiveAttrib = RESOLVE((void (APIENTRY *)(GLuint , GLuint , GLsizei , GLsizei* , GLint* , GLenum* , GLchar* )), glGetActiveAttrib); + glGetActiveUniform = RESOLVE((void (APIENTRY *)(GLuint , GLuint , GLsizei , GLsizei* , GLint* , GLenum* , GLchar* )), glGetActiveUniform); + glGetAttachedShaders = RESOLVE((void (APIENTRY *)(GLuint , GLsizei , GLsizei*, GLuint* )), glGetAttachedShaders); + glGetAttribLocation = RESOLVE((int (APIENTRY *)(GLuint , const GLchar* )), glGetAttribLocation); + glGetBufferParameteriv = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLint* )), glGetBufferParameteriv); + glGetFramebufferAttachmentParameteriv = RESOLVE((void (APIENTRY *)(GLenum , GLenum, GLenum , GLint* )), glGetFramebufferAttachmentParameteriv); + glGetProgramiv = RESOLVE((void (APIENTRY *)(GLuint , GLenum , GLint* )), glGetProgramiv); + glGetProgramInfoLog = RESOLVE((void (APIENTRY *)(GLuint , GLsizei , GLsizei* , GLchar* )), glGetProgramInfoLog); + glGetRenderbufferParameteriv = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLint* )), glGetRenderbufferParameteriv); + glGetShaderiv = RESOLVE((void (APIENTRY *)(GLuint , GLenum , GLint* )), glGetShaderiv); + glGetShaderInfoLog = RESOLVE((void (APIENTRY *)(GLuint , GLsizei , GLsizei*, GLchar*)), glGetShaderInfoLog); + glGetShaderPrecisionFormat = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLint* , GLint* )), glGetShaderPrecisionFormat); + glGetShaderSource = RESOLVE((void (APIENTRY *)(GLuint , GLsizei , GLsizei* , GLchar* )), glGetShaderSource); + glGetUniformfv = RESOLVE((void (APIENTRY *)(GLuint , GLint , GLfloat*)), glGetUniformfv); + glGetUniformiv = RESOLVE((void (APIENTRY *)(GLuint , GLint , GLint*)), glGetUniformiv); + glGetUniformLocation = RESOLVE((int (APIENTRY *)(GLuint , const GLchar* )), glGetUniformLocation); + glGetVertexAttribfv = RESOLVE((void (APIENTRY *)(GLuint , GLenum , GLfloat* )), glGetVertexAttribfv); + glGetVertexAttribiv = RESOLVE((void (APIENTRY *)(GLuint , GLenum , GLint* )), glGetVertexAttribiv); + glGetVertexAttribPointerv = RESOLVE((void (APIENTRY *)(GLuint , GLenum , GLvoid** pointer)), glGetVertexAttribPointerv); + glIsBuffer = RESOLVE((GLboolean (APIENTRY *)(GLuint )), glIsBuffer); + glIsFramebuffer = RESOLVE((GLboolean (APIENTRY *)(GLuint )), glIsFramebuffer); + glIsProgram = RESOLVE((GLboolean (APIENTRY *)(GLuint )), glIsProgram); + glIsRenderbuffer = RESOLVE((GLboolean (APIENTRY *)(GLuint )), glIsRenderbuffer); + glIsShader = RESOLVE((GLboolean (APIENTRY *)(GLuint )), glIsShader); + glLinkProgram = RESOLVE((void (APIENTRY *)(GLuint )), glLinkProgram); + glReleaseShaderCompiler = RESOLVE((void (APIENTRY *)(void)), glReleaseShaderCompiler); + glRenderbufferStorage = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLsizei , GLsizei )), glRenderbufferStorage); + glSampleCoverage = RESOLVE((void (APIENTRY *)(GLclampf , GLboolean )), glSampleCoverage); + glShaderBinary = RESOLVE((void (APIENTRY *)(GLsizei , const GLuint*, GLenum , const GLvoid* , GLsizei )), glShaderBinary); + glShaderSource = RESOLVE((void (APIENTRY *)(GLuint , GLsizei , const GLchar* *, const GLint* )), glShaderSource); + glStencilFuncSeparate = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLint , GLuint )), glStencilFuncSeparate); + glStencilMaskSeparate = RESOLVE((void (APIENTRY *)(GLenum , GLuint )), glStencilMaskSeparate); + glStencilOpSeparate = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLenum , GLenum )), glStencilOpSeparate); + glUniform1f = RESOLVE((void (APIENTRY *)(GLint , GLfloat )), glUniform1f); + glUniform1fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLfloat* )), glUniform1fv); + glUniform1i = RESOLVE((void (APIENTRY *)(GLint , GLint )), glUniform1i); + glUniform1iv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLint* )), glUniform1iv); + glUniform2f = RESOLVE((void (APIENTRY *)(GLint , GLfloat , GLfloat )), glUniform2f); + glUniform2fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLfloat* )), glUniform2fv); + glUniform2i = RESOLVE((void (APIENTRY *)(GLint , GLint , GLint )), glUniform2i); + glUniform2iv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLint* )), glUniform2iv); + glUniform3f = RESOLVE((void (APIENTRY *)(GLint , GLfloat , GLfloat , GLfloat )), glUniform3f); + glUniform3fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLfloat* )), glUniform3fv); + glUniform3i = RESOLVE((void (APIENTRY *)(GLint , GLint , GLint , GLint )), glUniform3i); + glUniform3iv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLint* )), glUniform3iv); + glUniform4f = RESOLVE((void (APIENTRY *)(GLint , GLfloat , GLfloat , GLfloat , GLfloat )), glUniform4f); + glUniform4fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLfloat* )), glUniform4fv); + glUniform4i = RESOLVE((void (APIENTRY *)(GLint , GLint , GLint , GLint , GLint )), glUniform4i); + glUniform4iv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLint* )), glUniform4iv); + glUniformMatrix2fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , GLboolean , const GLfloat* )), glUniformMatrix2fv); + glUniformMatrix3fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , GLboolean , const GLfloat* )), glUniformMatrix3fv); + glUniformMatrix4fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , GLboolean , const GLfloat* )), glUniformMatrix4fv); + glUseProgram = RESOLVE((void (APIENTRY *)(GLuint )), glUseProgram); + glValidateProgram = RESOLVE((void (APIENTRY *)(GLuint )), glValidateProgram); + glVertexAttrib1f = RESOLVE((void (APIENTRY *)(GLuint , GLfloat )), glVertexAttrib1f); + glVertexAttrib1fv = RESOLVE((void (APIENTRY *)(GLuint , const GLfloat* )), glVertexAttrib1fv); + glVertexAttrib2f = RESOLVE((void (APIENTRY *)(GLuint , GLfloat , GLfloat )), glVertexAttrib2f); + glVertexAttrib2fv = RESOLVE((void (APIENTRY *)(GLuint , const GLfloat* )), glVertexAttrib2fv); + glVertexAttrib3f = RESOLVE((void (APIENTRY *)(GLuint , GLfloat , GLfloat , GLfloat )), glVertexAttrib3f); + glVertexAttrib3fv = RESOLVE((void (APIENTRY *)(GLuint , const GLfloat* )), glVertexAttrib3fv); + glVertexAttrib4f = RESOLVE((void (APIENTRY *)(GLuint , GLfloat , GLfloat , GLfloat , GLfloat )), glVertexAttrib4f); + glVertexAttrib4fv = RESOLVE((void (APIENTRY *)(GLuint , const GLfloat* )), glVertexAttrib4fv); + glVertexAttribPointer = RESOLVE((void (APIENTRY *)(GLuint , GLint, GLenum, GLboolean, GLsizei, const GLvoid* )), glVertexAttribPointer); + + glClearDepthf = RESOLVE((void (APIENTRY *)(GLclampf )), glClearDepthf); + glDepthRangef = RESOLVE((void (APIENTRY *)(GLclampf , GLclampf )), glDepthRangef); + + return glBindTexture && glCreateShader && glClearDepthf; +} + QWindowsEGLStaticContext::QWindowsEGLStaticContext(EGLDisplay display, int version) : m_display(display), m_version(version) { @@ -76,7 +350,16 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create() return 0; } - EGLDisplay display = eglGetDisplay((EGLNativeDisplayType)dc); + if (!libEGL.init()) { + qWarning("%s: Failed to load and resolve libEGL functions", Q_FUNC_INFO); + return 0; + } + if (!libGLESv2.init()) { + qWarning("%s: Failed to load and resolve libGLESv2 functions", Q_FUNC_INFO); + return 0; + } + + EGLDisplay display = libEGL.eglGetDisplay((EGLNativeDisplayType)dc); if (!display) { qWarning("%s: Could not obtain EGL display", Q_FUNC_INFO); return 0; @@ -84,9 +367,11 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create() EGLint major; EGLint minor; - if (!eglInitialize(display, &major, &minor)) { - qWarning("%s: Could not initialize egl display: error %d\n", - Q_FUNC_INFO, eglGetError()); + if (!libEGL.eglInitialize(display, &major, &minor)) { + int err = libEGL.eglGetError(); + qWarning("%s: Could not initialize EGL display: error 0x%x\n", Q_FUNC_INFO, err); + if (err == 0x3001) + qWarning("%s: When using ANGLE, check if d3dcompiler_4x.dll is available", Q_FUNC_INFO); return 0; } @@ -97,7 +382,70 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create() QWindowsEGLStaticContext::~QWindowsEGLStaticContext() { qCDebug(lcQpaGl) << __FUNCTION__ << "Releasing EGL display " << m_display; - eglTerminate(m_display); + libEGL.eglTerminate(m_display); +} + +QWindowsOpenGLContext *QWindowsEGLStaticContext::createContext(QOpenGLContext *context) +{ + return new QWindowsEGLContext(this, context->format(), context->shareHandle()); +} + +void *QWindowsEGLStaticContext::createWindowSurface(void *nativeWindow, void *nativeConfig) +{ + EGLSurface surface = libEGL.eglCreateWindowSurface(m_display, (EGLConfig) nativeConfig, + (EGLNativeWindowType) nativeWindow, 0); + if (surface == EGL_NO_SURFACE) + qWarning("%s: Could not create the EGL window surface: 0x%x\n", Q_FUNC_INFO, libEGL.eglGetError()); + + return surface; +} + +void QWindowsEGLStaticContext::destroyWindowSurface(void *nativeSurface) +{ + libEGL.eglDestroySurface(m_display, (EGLSurface) nativeSurface); +} + +QSurfaceFormat QWindowsEGLStaticContext::formatFromConfig(EGLDisplay display, EGLConfig config, + const QSurfaceFormat &referenceFormat) +{ + QSurfaceFormat format; + EGLint redSize = 0; + EGLint greenSize = 0; + EGLint blueSize = 0; + EGLint alphaSize = 0; + EGLint depthSize = 0; + EGLint stencilSize = 0; + EGLint sampleCount = 0; + + libEGL.eglGetConfigAttrib(display, config, EGL_RED_SIZE, &redSize); + libEGL.eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &greenSize); + libEGL.eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blueSize); + libEGL.eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaSize); + libEGL.eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depthSize); + libEGL.eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencilSize); + libEGL.eglGetConfigAttrib(display, config, EGL_SAMPLES, &sampleCount); + + format.setRenderableType(QSurfaceFormat::OpenGLES); + format.setVersion(referenceFormat.majorVersion(), referenceFormat.minorVersion()); + format.setProfile(referenceFormat.profile()); + format.setOptions(referenceFormat.options()); + + format.setRedBufferSize(redSize); + format.setGreenBufferSize(greenSize); + format.setBlueBufferSize(blueSize); + format.setAlphaBufferSize(alphaSize); + format.setDepthBufferSize(depthSize); + format.setStencilBufferSize(stencilSize); + format.setSamples(sampleCount); + format.setStereo(false); + format.setSwapInterval(referenceFormat.swapInterval()); + + // Clear the EGL error state because some of the above may + // have errored out because the attribute is not applicable + // to the surface type. Such errors don't matter. + libEGL.eglGetError(); + + return format; } /*! @@ -121,40 +469,465 @@ QWindowsEGLStaticContext::~QWindowsEGLStaticContext() \ingroup qt-lighthouse-win */ -QWindowsEGLContext::QWindowsEGLContext(const QWindowsEGLStaticContextPtr &staticContext, +QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext, const QSurfaceFormat &format, QPlatformOpenGLContext *share) - : QEGLPlatformContext(format, share, staticContext->display()) - , m_staticContext(staticContext) + : m_staticContext(staticContext) + , m_eglDisplay(staticContext->display()) + , m_api(EGL_OPENGL_ES_API) + , m_swapInterval(-1) { + if (!m_staticContext) + return; + + m_eglConfig = chooseConfig(format); + m_format = m_staticContext->formatFromConfig(m_eglDisplay, m_eglConfig, format); + m_shareContext = share ? static_cast<QWindowsEGLContext *>(share)->m_eglContext : 0; + + QVector<EGLint> contextAttrs; + contextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); + contextAttrs.append(m_format.majorVersion()); + contextAttrs.append(EGL_NONE); + + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); + m_eglContext = QWindowsEGLStaticContext::libEGL.eglCreateContext(m_eglDisplay, m_eglConfig, m_shareContext, contextAttrs.constData()); + if (m_eglContext == EGL_NO_CONTEXT && m_shareContext != EGL_NO_CONTEXT) { + m_shareContext = 0; + m_eglContext = QWindowsEGLStaticContext::libEGL.eglCreateContext(m_eglDisplay, m_eglConfig, 0, contextAttrs.constData()); + } + + if (m_eglContext == EGL_NO_CONTEXT) { + qWarning("QWindowsEGLContext: eglError: %x, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); + return; + } + + // Make the context current to ensure the GL version query works. This needs a surface too. + const EGLint pbufferAttributes[] = { + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_LARGEST_PBUFFER, EGL_FALSE, + EGL_NONE + }; + EGLSurface pbuffer = QWindowsEGLStaticContext::libEGL.eglCreatePbufferSurface(m_eglDisplay, m_eglConfig, pbufferAttributes); + if (pbuffer == EGL_NO_SURFACE) + return; + + if (QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, pbuffer, pbuffer, m_eglContext)) { + const GLubyte *s = QWindowsEGLStaticContext::libGLESv2.glGetString(GL_VERSION); + if (s) { + QByteArray version = QByteArray(reinterpret_cast<const char *>(s)); + int major, minor; + if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) { + m_format.setMajorVersion(major); + m_format.setMinorVersion(minor); + } + } + m_format.setProfile(QSurfaceFormat::NoProfile); + m_format.setOptions(QSurfaceFormat::FormatOptions()); + QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + QWindowsEGLStaticContext::libEGL.eglDestroySurface(m_eglDisplay, pbuffer); } QWindowsEGLContext::~QWindowsEGLContext() { + if (m_eglContext != EGL_NO_CONTEXT) { + QWindowsEGLStaticContext::libEGL.eglDestroyContext(m_eglDisplay, m_eglContext); + m_eglContext = EGL_NO_CONTEXT; + } } -bool QWindowsEGLContext::hasThreadedOpenGLCapability() +bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface) { - return false; + Q_ASSERT(surface->surface()->supportsOpenGL()); + + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); + + QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); + EGLSurface eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig)); + Q_ASSERT(eglSurface); + + // shortcut: on some GPUs, eglMakeCurrent is not a cheap operation + if (QWindowsEGLStaticContext::libEGL.eglGetCurrentContext() == m_eglContext && + QWindowsEGLStaticContext::libEGL.eglGetCurrentDisplay() == m_eglDisplay && + QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_READ) == eglSurface && + QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_DRAW) == eglSurface) { + return true; + } + + const bool ok = QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_eglContext); + if (ok) { + const int requestedSwapInterval = surface->format().swapInterval(); + if (requestedSwapInterval >= 0 && m_swapInterval != requestedSwapInterval) { + m_swapInterval = requestedSwapInterval; + QWindowsEGLStaticContext::libEGL.eglSwapInterval(m_staticContext->display(), m_swapInterval); + } + } else { + qWarning("QWindowsEGLContext::makeCurrent: eglError: %x, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); + } + + return ok; } -EGLSurface QWindowsEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) +void QWindowsEGLContext::doneCurrent() { - const QWindowsWindow *window = static_cast<const QWindowsWindow *>(surface); - return window->eglSurfaceHandle(); + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); + bool ok = QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!ok) + qWarning("QWindowsEGLContext::doneCurrent: eglError: %d, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); } -bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface) +void QWindowsEGLContext::swapBuffers(QPlatformSurface *surface) { - bool ok = false; + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); - if (EGLSurface eglSurface = window->ensureEglSurfaceHandle(m_staticContext, eglConfig())) { - ok = eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext()); - if (!ok) - qWarning("%s: eglMakeCurrent() failed, eglError: 0x%x, this: %p \n", - Q_FUNC_INFO, eglGetError(), this); + EGLSurface eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig)); + Q_ASSERT(eglSurface); + + bool ok = QWindowsEGLStaticContext::libEGL.eglSwapBuffers(m_eglDisplay, eglSurface); + if (!ok) + qWarning("QWindowsEGLContext::swapBuffers: eglError: %d, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); +} + +QFunctionPointer QWindowsEGLContext::getProcAddress(const QByteArray &procName) +{ + // We support AllGLFunctionsQueryable, which means this function must be able to + // return a function pointer for standard GLES2 functions too. These are not + // guaranteed to be queryable via eglGetProcAddress(). + static struct StdFunc { + const char *name; + void *func; + } standardFuncs[] = { + { "glBindTexture", (void *) QWindowsEGLStaticContext::libGLESv2.glBindTexture }, + { "glBlendFunc", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendFunc }, + { "glClear", (void *) QWindowsEGLStaticContext::libGLESv2.glClear }, + { "glClearColor", (void *) QWindowsEGLStaticContext::libGLESv2.glClearColor }, + { "glClearStencil", (void *) QWindowsEGLStaticContext::libGLESv2.glClearStencil }, + { "glColorMask", (void *) QWindowsEGLStaticContext::libGLESv2.glColorMask }, + { "glCopyTexImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glCopyTexImage2D }, + { "glCopyTexSubImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glCopyTexSubImage2D }, + { "glCullFace", (void *) QWindowsEGLStaticContext::libGLESv2.glCullFace }, + { "glDeleteTextures", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteTextures }, + { "glDepthFunc", (void *) QWindowsEGLStaticContext::libGLESv2.glDepthFunc }, + { "glDepthMask", (void *) QWindowsEGLStaticContext::libGLESv2.glDepthMask }, + { "glDisable", (void *) QWindowsEGLStaticContext::libGLESv2.glDisable }, + { "glDrawArrays", (void *) QWindowsEGLStaticContext::libGLESv2.glDrawArrays }, + { "glDrawElements", (void *) QWindowsEGLStaticContext::libGLESv2.glDrawElements }, + { "glEnable", (void *) QWindowsEGLStaticContext::libGLESv2.glEnable }, + { "glFinish", (void *) QWindowsEGLStaticContext::libGLESv2.glFinish }, + { "glFlush", (void *) QWindowsEGLStaticContext::libGLESv2.glFlush }, + { "glFrontFace", (void *) QWindowsEGLStaticContext::libGLESv2.glFrontFace }, + { "glGenTextures", (void *) QWindowsEGLStaticContext::libGLESv2.glGenTextures }, + { "glGetBooleanv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetBooleanv }, + { "glGetError", (void *) QWindowsEGLStaticContext::libGLESv2.glGetError }, + { "glGetFloatv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetFloatv }, + { "glGetIntegerv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetIntegerv }, + { "glGetString", (void *) QWindowsEGLStaticContext::libGLESv2.glGetString }, + { "glGetTexParameterfv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetTexParameterfv }, + { "glGetTexParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetTexParameteriv }, + { "glHint", (void *) QWindowsEGLStaticContext::libGLESv2.glHint }, + { "glIsEnabled", (void *) QWindowsEGLStaticContext::libGLESv2.glIsEnabled }, + { "glIsTexture", (void *) QWindowsEGLStaticContext::libGLESv2.glIsTexture }, + { "glLineWidth", (void *) QWindowsEGLStaticContext::libGLESv2.glLineWidth }, + { "glPixelStorei", (void *) QWindowsEGLStaticContext::libGLESv2.glPixelStorei }, + { "glPolygonOffset", (void *) QWindowsEGLStaticContext::libGLESv2.glPolygonOffset }, + { "glReadPixels", (void *) QWindowsEGLStaticContext::libGLESv2.glReadPixels }, + { "glScissor", (void *) QWindowsEGLStaticContext::libGLESv2.glScissor }, + { "glStencilFunc", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilFunc }, + { "glStencilMask", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilMask }, + { "glStencilOp", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilOp }, + { "glTexImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glTexImage2D }, + { "glTexParameterf", (void *) QWindowsEGLStaticContext::libGLESv2.glTexParameterf }, + { "glTexParameterfv", (void *) QWindowsEGLStaticContext::libGLESv2.glTexParameterfv }, + { "glTexParameteri", (void *) QWindowsEGLStaticContext::libGLESv2.glTexParameteri }, + { "glTexParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glTexParameteriv }, + { "glTexSubImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glTexSubImage2D }, + { "glViewport", (void *) QWindowsEGLStaticContext::libGLESv2.glViewport }, + + { "glActiveTexture", (void *) QWindowsEGLStaticContext::libGLESv2.glActiveTexture }, + { "glAttachShader", (void *) QWindowsEGLStaticContext::libGLESv2.glAttachShader }, + { "glBindAttribLocation", (void *) QWindowsEGLStaticContext::libGLESv2.glBindAttribLocation }, + { "glBindBuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glBindBuffer }, + { "glBindFramebuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glBindFramebuffer }, + { "glBindRenderbuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glBindRenderbuffer }, + { "glBlendColor", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendColor }, + { "glBlendEquation", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendEquation }, + { "glBlendEquationSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendEquationSeparate }, + { "glBlendFuncSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendFuncSeparate }, + { "glBufferData", (void *) QWindowsEGLStaticContext::libGLESv2.glBufferData }, + { "glBufferSubData", (void *) QWindowsEGLStaticContext::libGLESv2.glBufferSubData }, + { "glCheckFramebufferStatus", (void *) QWindowsEGLStaticContext::libGLESv2.glCheckFramebufferStatus }, + { "glCompileShader", (void *) QWindowsEGLStaticContext::libGLESv2.glCompileShader }, + { "glCompressedTexImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glCompressedTexImage2D }, + { "glCompressedTexSubImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glCompressedTexSubImage2D }, + { "glCreateProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glCreateProgram }, + { "glCreateShader", (void *) QWindowsEGLStaticContext::libGLESv2.glCreateShader }, + { "glDeleteBuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteBuffers }, + { "glDeleteFramebuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteFramebuffers }, + { "glDeleteProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteProgram }, + { "glDeleteRenderbuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteRenderbuffers }, + { "glDeleteShader", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteShader }, + { "glDetachShader", (void *) QWindowsEGLStaticContext::libGLESv2.glDetachShader }, + { "glDisableVertexAttribArray", (void *) QWindowsEGLStaticContext::libGLESv2.glDisableVertexAttribArray }, + { "glEnableVertexAttribArray", (void *) QWindowsEGLStaticContext::libGLESv2.glEnableVertexAttribArray }, + { "glFramebufferRenderbuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glFramebufferRenderbuffer }, + { "glFramebufferTexture2D", (void *) QWindowsEGLStaticContext::libGLESv2.glFramebufferTexture2D }, + { "glGenBuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glGenBuffers }, + { "glGenerateMipmap", (void *) QWindowsEGLStaticContext::libGLESv2.glGenerateMipmap }, + { "glGenFramebuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glGenFramebuffers }, + { "glGenRenderbuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glGenRenderbuffers }, + { "glGetActiveAttrib", (void *) QWindowsEGLStaticContext::libGLESv2.glGetActiveAttrib }, + { "glGetActiveUniform", (void *) QWindowsEGLStaticContext::libGLESv2.glGetActiveUniform }, + { "glGetAttachedShaders", (void *) QWindowsEGLStaticContext::libGLESv2.glGetAttachedShaders }, + { "glGetAttribLocation", (void *) QWindowsEGLStaticContext::libGLESv2.glGetAttribLocation }, + { "glGetBufferParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetBufferParameteriv }, + { "glGetFramebufferAttachmentParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetFramebufferAttachmentParameteriv }, + { "glGetProgramiv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetProgramiv }, + { "glGetProgramInfoLog", (void *) QWindowsEGLStaticContext::libGLESv2.glGetProgramInfoLog }, + { "glGetRenderbufferParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetRenderbufferParameteriv }, + { "glGetShaderiv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetShaderiv }, + { "glGetShaderInfoLog", (void *) QWindowsEGLStaticContext::libGLESv2.glGetShaderInfoLog }, + { "glGetShaderPrecisionFormat", (void *) QWindowsEGLStaticContext::libGLESv2.glGetShaderPrecisionFormat }, + { "glGetShaderSource", (void *) QWindowsEGLStaticContext::libGLESv2.glGetShaderSource }, + { "glGetUniformfv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetUniformfv }, + { "glGetUniformiv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetUniformiv }, + { "glGetUniformLocation", (void *) QWindowsEGLStaticContext::libGLESv2.glGetUniformLocation }, + { "glGetVertexAttribfv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetVertexAttribfv }, + { "glGetVertexAttribiv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetVertexAttribiv }, + { "glGetVertexAttribPointerv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetVertexAttribPointerv }, + { "glIsBuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glIsBuffer }, + { "glIsFramebuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glIsFramebuffer }, + { "glIsProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glIsProgram }, + { "glIsRenderbuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glIsRenderbuffer }, + { "glIsShader", (void *) QWindowsEGLStaticContext::libGLESv2.glIsShader }, + { "glLinkProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glLinkProgram }, + { "glReleaseShaderCompiler", (void *) QWindowsEGLStaticContext::libGLESv2.glReleaseShaderCompiler }, + { "glRenderbufferStorage", (void *) QWindowsEGLStaticContext::libGLESv2.glRenderbufferStorage }, + { "glSampleCoverage", (void *) QWindowsEGLStaticContext::libGLESv2.glSampleCoverage }, + { "glShaderBinary", (void *) QWindowsEGLStaticContext::libGLESv2.glShaderBinary }, + { "glShaderSource", (void *) QWindowsEGLStaticContext::libGLESv2.glShaderSource }, + { "glStencilFuncSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilFuncSeparate }, + { "glStencilMaskSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilMaskSeparate }, + { "glStencilOpSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilOpSeparate }, + { "glUniform1f", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform1f }, + { "glUniform1fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform1fv }, + { "glUniform1i", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform1i }, + { "glUniform1iv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform1iv }, + { "glUniform2f", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform2f }, + { "glUniform2fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform2fv }, + { "glUniform2i", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform2i }, + { "glUniform2iv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform2iv }, + { "glUniform3f", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform3f }, + { "glUniform3fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform3fv }, + { "glUniform3i", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform3i }, + { "glUniform3iv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform3iv }, + { "glUniform4f", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform4f }, + { "glUniform4fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform4fv }, + { "glUniform4i", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform4i }, + { "glUniform4iv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform4iv }, + { "glUniformMatrix2fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniformMatrix2fv }, + { "glUniformMatrix3fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniformMatrix3fv }, + { "glUniformMatrix4fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniformMatrix4fv }, + { "glUseProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glUseProgram }, + { "glValidateProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glValidateProgram }, + { "glVertexAttrib1f", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib1f }, + { "glVertexAttrib1fv", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib1fv }, + { "glVertexAttrib2f", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib2f }, + { "glVertexAttrib2fv", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib2fv }, + { "glVertexAttrib3f", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib3f }, + { "glVertexAttrib3fv", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib3fv }, + { "glVertexAttrib4f", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib4f }, + { "glVertexAttrib4fv", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib4fv }, + { "glVertexAttribPointer", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttribPointer }, + + { "glClearDepthf", (void *) QWindowsEGLStaticContext::libGLESv2.glClearDepthf }, + { "glDepthRangef", (void *) QWindowsEGLStaticContext::libGLESv2.glDepthRangef } + }; + for (size_t i = 0; i < sizeof(standardFuncs) / sizeof(StdFunc); ++i) + if (procName == standardFuncs[i].name) + return reinterpret_cast<QFunctionPointer>(standardFuncs[i].func); + + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); + QFunctionPointer procAddress = reinterpret_cast<QFunctionPointer>(QWindowsEGLStaticContext::libEGL.eglGetProcAddress(procName.constData())); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaGl) << __FUNCTION__ << procName << QWindowsEGLStaticContext::libEGL.eglGetCurrentContext() << "returns" << procAddress; + if (!procAddress && QWindowsContext::verbose) + qWarning("%s: Unable to resolve '%s'", __FUNCTION__, procName.constData()); + return procAddress; +} + +static QVector<EGLint> createConfigAttributesFromFormat(const QSurfaceFormat &format) +{ + int redSize = format.redBufferSize(); + int greenSize = format.greenBufferSize(); + int blueSize = format.blueBufferSize(); + int alphaSize = format.alphaBufferSize(); + int depthSize = format.depthBufferSize(); + int stencilSize = format.stencilBufferSize(); + int sampleCount = format.samples(); + + QVector<EGLint> configAttributes; + configAttributes.reserve(16); + + configAttributes.append(EGL_RED_SIZE); + configAttributes.append(redSize > 0 ? redSize : 0); + + configAttributes.append(EGL_GREEN_SIZE); + configAttributes.append(greenSize > 0 ? greenSize : 0); + + configAttributes.append(EGL_BLUE_SIZE); + configAttributes.append(blueSize > 0 ? blueSize : 0); + + configAttributes.append(EGL_ALPHA_SIZE); + configAttributes.append(alphaSize > 0 ? alphaSize : 0); + + configAttributes.append(EGL_DEPTH_SIZE); + configAttributes.append(depthSize > 0 ? depthSize : 0); + + configAttributes.append(EGL_STENCIL_SIZE); + configAttributes.append(stencilSize > 0 ? stencilSize : 0); + + configAttributes.append(EGL_SAMPLES); + configAttributes.append(sampleCount > 0 ? sampleCount : 0); + + configAttributes.append(EGL_SAMPLE_BUFFERS); + configAttributes.append(sampleCount > 0); + + return configAttributes; +} + +static bool reduceConfigAttributes(QVector<EGLint> *configAttributes) +{ + int i = -1; + + i = configAttributes->indexOf(EGL_SWAP_BEHAVIOR); + if (i >= 0) { + configAttributes->remove(i,2); } - return ok; + + i = configAttributes->indexOf(EGL_BUFFER_SIZE); + if (i >= 0) { + if (configAttributes->at(i+1) == 16) { + configAttributes->remove(i,2); + return true; + } + } + + i = configAttributes->indexOf(EGL_SAMPLES); + if (i >= 0) { + EGLint value = configAttributes->value(i+1, 0); + if (value > 1) + configAttributes->replace(i+1, qMin(EGLint(16), value / 2)); + else + configAttributes->remove(i, 2); + return true; + } + + i = configAttributes->indexOf(EGL_SAMPLE_BUFFERS); + if (i >= 0) { + configAttributes->remove(i,2); + return true; + } + + i = configAttributes->indexOf(EGL_ALPHA_SIZE); + if (i >= 0) { + configAttributes->remove(i,2); +#if defined(EGL_BIND_TO_TEXTURE_RGBA) && defined(EGL_BIND_TO_TEXTURE_RGB) + i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGBA); + if (i >= 0) { + configAttributes->replace(i,EGL_BIND_TO_TEXTURE_RGB); + configAttributes->replace(i+1,true); + + } +#endif + return true; + } + + i = configAttributes->indexOf(EGL_STENCIL_SIZE); + if (i >= 0) { + if (configAttributes->at(i + 1) > 1) + configAttributes->replace(i + 1, 1); + else + configAttributes->remove(i, 2); + return true; + } + + i = configAttributes->indexOf(EGL_DEPTH_SIZE); + if (i >= 0) { + if (configAttributes->at(i + 1) > 1) + configAttributes->replace(i + 1, 1); + else + configAttributes->remove(i, 2); + return true; + } +#ifdef EGL_BIND_TO_TEXTURE_RGB + i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGB); + if (i >= 0) { + configAttributes->remove(i,2); + return true; + } +#endif + + return false; +} + +EGLConfig QWindowsEGLContext::chooseConfig(const QSurfaceFormat &format) +{ + QVector<EGLint> configureAttributes = createConfigAttributesFromFormat(format); + configureAttributes.append(EGL_SURFACE_TYPE); + configureAttributes.append(EGL_WINDOW_BIT); + configureAttributes.append(EGL_RENDERABLE_TYPE); + configureAttributes.append(EGL_OPENGL_ES2_BIT); + configureAttributes.append(EGL_NONE); + + EGLDisplay display = m_staticContext->display(); + EGLConfig cfg = 0; + do { + // Get the number of matching configurations for this set of properties. + EGLint matching = 0; + if (!QWindowsEGLStaticContext::libEGL.eglChooseConfig(display, configureAttributes.constData(), 0, 0, &matching) || !matching) + continue; + + // Fetch all of the matching configurations and find the + // first that matches the pixel format we wanted. + int i = configureAttributes.indexOf(EGL_RED_SIZE); + int confAttrRed = configureAttributes.at(i+1); + i = configureAttributes.indexOf(EGL_GREEN_SIZE); + int confAttrGreen = configureAttributes.at(i+1); + i = configureAttributes.indexOf(EGL_BLUE_SIZE); + int confAttrBlue = configureAttributes.at(i+1); + i = configureAttributes.indexOf(EGL_ALPHA_SIZE); + int confAttrAlpha = i == -1 ? 0 : configureAttributes.at(i+1); + + QVector<EGLConfig> configs(matching); + QWindowsEGLStaticContext::libEGL.eglChooseConfig(display, configureAttributes.constData(), configs.data(), configs.size(), &matching); + if (!cfg && matching > 0) + cfg = configs.first(); + + EGLint red = 0; + EGLint green = 0; + EGLint blue = 0; + EGLint alpha = 0; + for (int i = 0; i < configs.size(); ++i) { + if (confAttrRed) + QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &red); + if (confAttrGreen) + QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &green); + if (confAttrBlue) + QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &blue); + if (confAttrAlpha) + QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &alpha); + + if (red == confAttrRed && green == confAttrGreen + && blue == confAttrBlue && alpha == confAttrAlpha) + return configs[i]; + } + } while (reduceConfigAttributes(&configureAttributes)); + + if (!cfg) + qWarning("Cannot find EGLConfig, returning null config"); + + return cfg; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h index 33653b2f2e..6c4ac08da1 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.h +++ b/src/plugins/platforms/windows/qwindowseglcontext.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -42,20 +42,237 @@ #ifndef QWINDOWSEGLCONTEXT_H #define QWINDOWSEGLCONTEXT_H -#include <QtPlatformSupport/private/qeglplatformcontext_p.h> -#include <QSharedPointer> +#include "qwindowsopenglcontext.h" +#include <EGL/egl.h> QT_BEGIN_NAMESPACE -class QWindowsEGLStaticContext +struct QWindowsLibEGL +{ + bool init(); + + EGLint (EGLAPIENTRY * eglGetError)(void); + EGLDisplay (EGLAPIENTRY * eglGetDisplay)(EGLNativeDisplayType display_id); + EGLBoolean (EGLAPIENTRY * eglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor); + EGLBoolean (EGLAPIENTRY * eglTerminate)(EGLDisplay dpy); + EGLBoolean (EGLAPIENTRY * eglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, + EGLint *num_config); + EGLBoolean (EGLAPIENTRY * eglGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value); + EGLSurface (EGLAPIENTRY * eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list); + EGLSurface (EGLAPIENTRY * eglCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list); + EGLBoolean (EGLAPIENTRY * eglDestroySurface)(EGLDisplay dpy, EGLSurface surface); + EGLBoolean (EGLAPIENTRY * eglBindAPI)(EGLenum api); + EGLBoolean (EGLAPIENTRY * eglSwapInterval)(EGLDisplay dpy, EGLint interval); + EGLContext (EGLAPIENTRY * eglCreateContext)(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint *attrib_list); + EGLBoolean (EGLAPIENTRY * eglDestroyContext)(EGLDisplay dpy, EGLContext ctx); + EGLBoolean (EGLAPIENTRY * eglMakeCurrent)(EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx); + EGLContext (EGLAPIENTRY * eglGetCurrentContext)(void); + EGLSurface (EGLAPIENTRY * eglGetCurrentSurface)(EGLint readdraw); + EGLDisplay (EGLAPIENTRY * eglGetCurrentDisplay)(void); + EGLBoolean (EGLAPIENTRY * eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface); + __eglMustCastToProperFunctionPointerType (EGLAPIENTRY * eglGetProcAddress)(const char *procname); + +private: +#ifndef QT_STATIC + void *resolve(const char *name); + HMODULE m_lib; +#endif +}; + +struct QWindowsLibGLESv2 +{ + bool init(); +#ifndef QT_STATIC + void *moduleHandle() const { return m_lib; } +#else + void *moduleHandle() const { return Q_NULLPTR; } +#endif + + // GL1+GLES2 common + void (APIENTRY * glBindTexture)(GLenum target, GLuint texture); + void (APIENTRY * glBlendFunc)(GLenum sfactor, GLenum dfactor); + void (APIENTRY * glClear)(GLbitfield mask); + void (APIENTRY * glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY * glClearStencil)(GLint s); + void (APIENTRY * glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + void (APIENTRY * glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); + void (APIENTRY * glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * glCullFace)(GLenum mode); + void (APIENTRY * glDeleteTextures)(GLsizei n, const GLuint* textures); + void (APIENTRY * glDepthFunc)(GLenum func); + void (APIENTRY * glDepthMask)(GLboolean flag); + void (APIENTRY * glDisable)(GLenum cap); + void (APIENTRY * glDrawArrays)(GLenum mode, GLint first, GLsizei count); + void (APIENTRY * glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices); + void (APIENTRY * glEnable)(GLenum cap); + void (APIENTRY * glFinish)(); + void (APIENTRY * glFlush)(); + void (APIENTRY * glFrontFace)(GLenum mode); + void (APIENTRY * glGenTextures)(GLsizei n, GLuint* textures); + void (APIENTRY * glGetBooleanv)(GLenum pname, GLboolean* params); + GLenum (APIENTRY * glGetError)(); + void (APIENTRY * glGetFloatv)(GLenum pname, GLfloat* params); + void (APIENTRY * glGetIntegerv)(GLenum pname, GLint* params); + const GLubyte * (APIENTRY * glGetString)(GLenum name); + void (APIENTRY * glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params); + void (APIENTRY * glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * glHint)(GLenum target, GLenum mode); + GLboolean (APIENTRY * glIsEnabled)(GLenum cap); + GLboolean (APIENTRY * glIsTexture)(GLuint texture); + void (APIENTRY * glLineWidth)(GLfloat width); + void (APIENTRY * glPixelStorei)(GLenum pname, GLint param); + void (APIENTRY * glPolygonOffset)(GLfloat factor, GLfloat units); + void (APIENTRY * glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); + void (APIENTRY * glScissor)(GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * glStencilFunc)(GLenum func, GLint ref, GLuint mask); + void (APIENTRY * glStencilMask)(GLuint mask); + void (APIENTRY * glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass); + void (APIENTRY * glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels); + void (APIENTRY * glTexParameterf)(GLenum target, GLenum pname, GLfloat param); + void (APIENTRY * glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params); + void (APIENTRY * glTexParameteri)(GLenum target, GLenum pname, GLint param); + void (APIENTRY * glTexParameteriv)(GLenum target, GLenum pname, const GLint* params); + void (APIENTRY * glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels); + void (APIENTRY * glViewport)(GLint x, GLint y, GLsizei width, GLsizei height); + + // GLES2 + void (APIENTRY * glActiveTexture)(GLenum texture); + void (APIENTRY * glAttachShader)(GLuint program, GLuint shader); + void (APIENTRY * glBindAttribLocation)(GLuint program, GLuint index, const char* name); + void (APIENTRY * glBindBuffer)(GLenum target, GLuint buffer); + void (APIENTRY * glBindFramebuffer)(GLenum target, GLuint framebuffer); + void (APIENTRY * glBindRenderbuffer)(GLenum target, GLuint renderbuffer); + void (APIENTRY * glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY * glBlendEquation)(GLenum mode); + void (APIENTRY * glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha); + void (APIENTRY * glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); + void (APIENTRY * glBufferData)(GLenum target, qopengl_GLsizeiptr size, const void* data, GLenum usage); + void (APIENTRY * glBufferSubData)(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, const void* data); + GLenum (APIENTRY * glCheckFramebufferStatus)(GLenum target); + void (APIENTRY * glCompileShader)(GLuint shader); + void (APIENTRY * glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); + void (APIENTRY * glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); + GLuint (APIENTRY * glCreateProgram)(); + GLuint (APIENTRY * glCreateShader)(GLenum type); + void (APIENTRY * glDeleteBuffers)(GLsizei n, const GLuint* buffers); + void (APIENTRY * glDeleteFramebuffers)(GLsizei n, const GLuint* framebuffers); + void (APIENTRY * glDeleteProgram)(GLuint program); + void (APIENTRY * glDeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers); + void (APIENTRY * glDeleteShader)(GLuint shader); + void (APIENTRY * glDetachShader)(GLuint program, GLuint shader); + void (APIENTRY * glDisableVertexAttribArray)(GLuint index); + void (APIENTRY * glEnableVertexAttribArray)(GLuint index); + void (APIENTRY * glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); + void (APIENTRY * glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + void (APIENTRY * glGenBuffers)(GLsizei n, GLuint* buffers); + void (APIENTRY * glGenerateMipmap)(GLenum target); + void (APIENTRY * glGenFramebuffers)(GLsizei n, GLuint* framebuffers); + void (APIENTRY * glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers); + void (APIENTRY * glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); + void (APIENTRY * glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); + void (APIENTRY * glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); + GLint (APIENTRY * glGetAttribLocation)(GLuint program, const char* name); + void (APIENTRY * glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params); + void (APIENTRY * glGetProgramiv)(GLuint program, GLenum pname, GLint* params); + void (APIENTRY * glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog); + void (APIENTRY * glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * glGetShaderiv)(GLuint shader, GLenum pname, GLint* params); + void (APIENTRY * glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog); + void (APIENTRY * glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); + void (APIENTRY * glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, char* source); + void (APIENTRY * glGetUniformfv)(GLuint program, GLint location, GLfloat* params); + void (APIENTRY * glGetUniformiv)(GLuint program, GLint location, GLint* params); + GLint (APIENTRY * glGetUniformLocation)(GLuint program, const char* name); + void (APIENTRY * glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params); + void (APIENTRY * glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params); + void (APIENTRY * glGetVertexAttribPointerv)(GLuint index, GLenum pname, void** pointer); + GLboolean (APIENTRY * glIsBuffer)(GLuint buffer); + GLboolean (APIENTRY * glIsFramebuffer)(GLuint framebuffer); + GLboolean (APIENTRY * glIsProgram)(GLuint program); + GLboolean (APIENTRY * glIsRenderbuffer)(GLuint renderbuffer); + GLboolean (APIENTRY * glIsShader)(GLuint shader); + void (APIENTRY * glLinkProgram)(GLuint program); + void (APIENTRY * glReleaseShaderCompiler)(); + void (APIENTRY * glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); + void (APIENTRY * glSampleCoverage)(GLclampf value, GLboolean invert); + void (APIENTRY * glShaderBinary)(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length); + void (APIENTRY * glShaderSource)(GLuint shader, GLsizei count, const char** string, const GLint* length); + void (APIENTRY * glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask); + void (APIENTRY * glStencilMaskSeparate)(GLenum face, GLuint mask); + void (APIENTRY * glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); + void (APIENTRY * glUniform1f)(GLint location, GLfloat x); + void (APIENTRY * glUniform1fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * glUniform1i)(GLint location, GLint x); + void (APIENTRY * glUniform1iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * glUniform2f)(GLint location, GLfloat x, GLfloat y); + void (APIENTRY * glUniform2fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * glUniform2i)(GLint location, GLint x, GLint y); + void (APIENTRY * glUniform2iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * glUniform3fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * glUniform3i)(GLint location, GLint x, GLint y, GLint z); + void (APIENTRY * glUniform3iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY * glUniform4fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w); + void (APIENTRY * glUniform4iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (APIENTRY * glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (APIENTRY * glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (APIENTRY * glUseProgram)(GLuint program); + void (APIENTRY * glValidateProgram)(GLuint program); + void (APIENTRY * glVertexAttrib1f)(GLuint indx, GLfloat x); + void (APIENTRY * glVertexAttrib1fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y); + void (APIENTRY * glVertexAttrib2fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * glVertexAttrib3fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY * glVertexAttrib4fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); + + // ES only + void (APIENTRY * glClearDepthf)(GLclampf depth); + void (APIENTRY * glDepthRangef)(GLclampf nearVal, GLclampf farVal); + +private: +#ifndef QT_STATIC + void *resolve(const char *name); + HMODULE m_lib; +#endif +}; + +class QWindowsEGLStaticContext : public QWindowsStaticOpenGLContext { Q_DISABLE_COPY(QWindowsEGLStaticContext) + public: static QWindowsEGLStaticContext *create(); ~QWindowsEGLStaticContext(); EGLDisplay display() const { return m_display; } + QWindowsOpenGLContext *createContext(QOpenGLContext *context); + void *moduleHandle() const { return libGLESv2.moduleHandle(); } + QOpenGLContext::OpenGLModuleType moduleType() const { return QOpenGLContext::LibGLES; } + + void *createWindowSurface(void *nativeWindow, void *nativeConfig) Q_DECL_OVERRIDE; + void destroyWindowSurface(void *nativeSurface) Q_DECL_OVERRIDE; + + QSurfaceFormat formatFromConfig(EGLDisplay display, EGLConfig config, const QSurfaceFormat &referenceFormat); + + static QWindowsLibEGL libEGL; + static QWindowsLibGLESv2 libGLESv2; + private: QWindowsEGLStaticContext(EGLDisplay display, int version); @@ -63,26 +280,38 @@ private: const int m_version; //! majorVersion<<8 + minorVersion }; -class QWindowsEGLContext : public QEGLPlatformContext +class QWindowsEGLContext : public QWindowsOpenGLContext { public: - typedef QSharedPointer<QWindowsEGLStaticContext> QWindowsEGLStaticContextPtr; - - QWindowsEGLContext(const QWindowsEGLStaticContextPtr& staticContext, + QWindowsEGLContext(QWindowsEGLStaticContext *staticContext, const QSurfaceFormat &format, QPlatformOpenGLContext *share); - ~QWindowsEGLContext(); - static bool hasThreadedOpenGLCapability(); + bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE; + void doneCurrent() Q_DECL_OVERRIDE; + void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; + QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; - bool makeCurrent(QPlatformSurface *surface); + QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } + bool isSharing() const Q_DECL_OVERRIDE { return m_shareContext != EGL_NO_CONTEXT; } + bool isValid() const Q_DECL_OVERRIDE { return m_eglContext != EGL_NO_CONTEXT; } -protected: - EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface); + void *nativeContext() const Q_DECL_OVERRIDE { return m_eglContext; } + void *nativeDisplay() const Q_DECL_OVERRIDE { return m_eglDisplay; } + void *nativeConfig() const Q_DECL_OVERRIDE { return m_eglConfig; } private: - const QWindowsEGLStaticContextPtr m_staticContext; + EGLConfig chooseConfig(const QSurfaceFormat &format); + + QWindowsEGLStaticContext *m_staticContext; + EGLContext m_eglContext; + EGLContext m_shareContext; + EGLDisplay m_eglDisplay; + EGLConfig m_eglConfig; + QSurfaceFormat m_format; + EGLenum m_api; + int m_swapInterval; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 696dc06cee..b22c35137d 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -164,25 +164,24 @@ namespace { { Q_ASSERT(tagName.size() == 4); quint32 tagId = *(reinterpret_cast<const quint32 *>(tagName.constData())); - if (Q_UNLIKELY(m_fontData.size() < sizeof(OffsetSubTable))) + const size_t fontDataSize = m_fontData.size(); + if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable))) return 0; OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data()); TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1); - quint16 tableCount = qFromBigEndian<quint16>(offsetSubTable->numTables); - if (Q_UNLIKELY(quint32(m_fontData.size()) < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount)) + const size_t tableCount = qFromBigEndian<quint16>(offsetSubTable->numTables); + if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount)) return 0; - TableDirectory *nameTableDirectoryEntry = 0; - for (int i = 0; i < tableCount; ++i, ++tableDirectory) { - if (tableDirectory->identifier == tagId) { - nameTableDirectoryEntry = tableDirectory; - break; - } + TableDirectory *tableDirectoryEnd = tableDirectory + tableCount; + for (TableDirectory *entry = tableDirectory; entry < tableDirectoryEnd; ++entry) { + if (entry->identifier == tagId) + return entry; } - return nameTableDirectoryEntry; + return 0; } QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry) @@ -1064,7 +1063,7 @@ QFontEngineMulti *QWindowsFontDatabase::fontEngineMulti(QFontEngine *fontEngine, if (script == QChar::Script_Common) return new QWindowsMultiFontEngine(fontEngine, script); // ### as long as fallbacksForFamily() does not take script parameter into account, - // prefer QFontEngineMultiQPA's loadEngine() implementation for complex scripts + // prefer QFontEngineMultiBasicImpl's loadEngine() implementation for complex scripts return QPlatformFontDatabase::fontEngineMulti(fontEngine, script); } @@ -1521,13 +1520,15 @@ LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request) #endif if (request.styleStrategy & QFont::PreferAntialias) { - if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP) { + if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && !(request.styleStrategy & QFont::NoSubpixelAntialias)) { qual = CLEARTYPE_QUALITY; } else { qual = ANTIALIASED_QUALITY; } } else if (request.styleStrategy & QFont::NoAntialias) { qual = NONANTIALIASED_QUALITY; + } else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && sharedFontData()->clearTypeEnabled) { + qual = ANTIALIASED_QUALITY; } lf.lfQuality = qual; @@ -1613,37 +1614,36 @@ QStringList QWindowsFontDatabase::extraTryFontsForFamily(const QString &family) return result; } +QString QWindowsFontDatabase::familyForStyleHint(QFont::StyleHint styleHint) +{ + switch (styleHint) { + case QFont::Times: + return QStringLiteral("Times New Roman"); + case QFont::Courier: + return QStringLiteral("Courier New"); + case QFont::Monospace: + return QStringLiteral("Courier New"); + case QFont::Cursive: + return QStringLiteral("Comic Sans MS"); + case QFont::Fantasy: + return QStringLiteral("Impact"); + case QFont::Decorative: + return QStringLiteral("Old English"); + case QFont::Helvetica: + return QStringLiteral("Arial"); + case QFont::System: + default: + break; + } + return QStringLiteral("MS Shell Dlg 2"); +} + QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { QStringList result = QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script); if (!result.isEmpty()) return result; - - switch (styleHint) { - case QFont::Times: - result << QString::fromLatin1("Times New Roman"); - break; - case QFont::Courier: - result << QString::fromLatin1("Courier New"); - break; - case QFont::Monospace: - result << QString::fromLatin1("Courier New"); - break; - case QFont::Cursive: - result << QString::fromLatin1("Comic Sans MS"); - break; - case QFont::Fantasy: - result << QString::fromLatin1("Impact"); - break; - case QFont::Decorative: - result << QString::fromLatin1("Old English"); - break; - case QFont::Helvetica: - case QFont::System: - default: - result << QString::fromLatin1("Arial"); - } - + result.append(QWindowsFontDatabase::familyForStyleHint(styleHint)); result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h index a2324544d2..1ef346a430 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h @@ -77,17 +77,17 @@ public: QWindowsFontDatabase(); ~QWindowsFontDatabase(); - virtual void populateFontDatabase(); - virtual QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script); - virtual QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); - virtual QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); - virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; - virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); - virtual void releaseHandle(void *handle); - virtual QString fontDir() const; - - virtual QFont defaultFont() const { return systemDefaultFont(); } - virtual bool fontsAlwaysScalable() const; + void populateFontDatabase() Q_DECL_OVERRIDE; + QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) Q_DECL_OVERRIDE; + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) Q_DECL_OVERRIDE; + QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) Q_DECL_OVERRIDE; + QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const Q_DECL_OVERRIDE; + QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName) Q_DECL_OVERRIDE; + void releaseHandle(void *handle) Q_DECL_OVERRIDE; + QString fontDir() const Q_DECL_OVERRIDE; + + QFont defaultFont() const Q_DECL_OVERRIDE { return systemDefaultFont(); } + bool fontsAlwaysScalable() const Q_DECL_OVERRIDE; void derefUniqueFont(const QString &uniqueFont); void refUniqueFont(const QString &uniqueFont); @@ -104,6 +104,7 @@ public: static LOGFONT fontDefToLOGFONT(const QFontDef &fontDef); static QStringList extraTryFontsForFamily(const QString &family); + static QString familyForStyleHint(QFont::StyleHint styleHint); private: void populate(const QString &family = QString()); diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 734f645e65..2f038106de 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -442,30 +442,7 @@ QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QF if (!result.isEmpty()) return result; - switch (styleHint) { - case QFont::Times: - result << QString::fromLatin1("Times New Roman"); - break; - case QFont::Courier: - result << QString::fromLatin1("Courier New"); - break; - case QFont::Monospace: - result << QString::fromLatin1("Courier New"); - break; - case QFont::Cursive: - result << QString::fromLatin1("Comic Sans MS"); - break; - case QFont::Fantasy: - result << QString::fromLatin1("Impact"); - break; - case QFont::Decorative: - result << QString::fromLatin1("Old English"); - break; - case QFont::Helvetica: - case QFont::System: - default: - result << QString::fromLatin1("Arial"); - } + result.append(QWindowsFontDatabase::familyForStyleHint(styleHint)); #ifdef Q_OS_WINCE QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\FontLink\\SystemLink"), QSettings::NativeFormat); diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h index bad6c54bf4..cf6108d87a 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h @@ -57,8 +57,8 @@ public: QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; - virtual QString fontDir() const; - virtual QFont defaultFont() const; + QString fontDir() const Q_DECL_OVERRIDE; + QFont defaultFont() const Q_DECL_OVERRIDE; private: void populate(const QString &family = QString()); diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index 6f97c8584b..d3cbea0b92 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -111,11 +111,6 @@ static void resolveGetCharWidthI() ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QStringLiteral("gdi32"), "GetCharWidthI"); } -// defined in qtextengine_win.cpp -typedef void *SCRIPT_CACHE; -typedef HRESULT (WINAPI *fScriptFreeCache)(SCRIPT_CACHE *); -extern fScriptFreeCache ScriptFreeCache; - static inline quint32 getUInt(unsigned char *p) { quint32 val; @@ -1300,7 +1295,7 @@ void QWindowsFontEngine::initFontInfo(const QFontDef &request, Will probably be superseded by a common Free Type font engine in Qt 5.X. */ QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *fe, int script) - : QFontEngineMultiQPA(fe, script) + : QFontEngineMultiBasicImpl(fe, script) { } diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h index 0ddf778fa0..8fe063121a 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.h +++ b/src/plugins/platforms/windows/qwindowsfontengine.h @@ -53,7 +53,7 @@ // We mean it. // -#include <QtGui/private/qfontengine_qpa_p.h> +#include <QtGui/private/qfontengine_p.h> #include <QtGui/QImage> #include <QtCore/QSharedPointer> @@ -78,48 +78,48 @@ public: void initFontInfo(const QFontDef &request, HDC fontHdc, int dpi); - virtual QFixed lineThickness() const; - virtual Properties properties() const; - virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics); - virtual FaceId faceId() const; - virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const; - virtual int synthesized() const; - virtual QFixed emSquareSize() const; + QFixed lineThickness() const Q_DECL_OVERRIDE; + Properties properties() const Q_DECL_OVERRIDE; + void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) Q_DECL_OVERRIDE; + FaceId faceId() const Q_DECL_OVERRIDE; + bool getSfntTableData(uint tag, uchar *buffer, uint *length) const Q_DECL_OVERRIDE; + int synthesized() const Q_DECL_OVERRIDE; + QFixed emSquareSize() const Q_DECL_OVERRIDE; - virtual glyph_t glyphIndex(uint ucs4) const; - virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const; - virtual void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const; + glyph_t glyphIndex(uint ucs4) const Q_DECL_OVERRIDE; + bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const Q_DECL_OVERRIDE; + void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const Q_DECL_OVERRIDE; - virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags); + void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) Q_DECL_OVERRIDE; virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags); HGDIOBJ selectDesignFont() const; - virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs); - virtual glyph_metrics_t boundingBox(glyph_t g) { return boundingBox(g, QTransform()); } - virtual glyph_metrics_t boundingBox(glyph_t g, const QTransform &t); + glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) Q_DECL_OVERRIDE; + glyph_metrics_t boundingBox(glyph_t g) Q_DECL_OVERRIDE { return boundingBox(g, QTransform()); } + glyph_metrics_t boundingBox(glyph_t g, const QTransform &t) Q_DECL_OVERRIDE; - virtual QFixed ascent() const; - virtual QFixed descent() const; - virtual QFixed leading() const; - virtual QFixed xHeight() const; - virtual QFixed averageCharWidth() const; - virtual qreal maxCharWidth() const; - virtual qreal minLeftBearing() const; - virtual qreal minRightBearing() const; + QFixed ascent() const Q_DECL_OVERRIDE; + QFixed descent() const Q_DECL_OVERRIDE; + QFixed leading() const Q_DECL_OVERRIDE; + QFixed xHeight() const Q_DECL_OVERRIDE; + QFixed averageCharWidth() const Q_DECL_OVERRIDE; + qreal maxCharWidth() const Q_DECL_OVERRIDE; + qreal minLeftBearing() const Q_DECL_OVERRIDE; + qreal minRightBearing() const Q_DECL_OVERRIDE; - 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); + QImage alphaMapForGlyph(glyph_t t) Q_DECL_OVERRIDE { return alphaMapForGlyph(t, QTransform()); } + QImage alphaMapForGlyph(glyph_t, const QTransform &xform) Q_DECL_OVERRIDE; + QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform) Q_DECL_OVERRIDE; + glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat) Q_DECL_OVERRIDE; - virtual QFontEngine *cloneWithSize(qreal pixelSize) const; - virtual bool supportsTransformation(const QTransform &transform) const; + QFontEngine *cloneWithSize(qreal pixelSize) const Q_DECL_OVERRIDE; + bool supportsTransformation(const QTransform &transform) const Q_DECL_OVERRIDE; #ifndef Q_CC_MINGW - virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0); + void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0) Q_DECL_OVERRIDE; #endif bool hasUnreliableGlyphOutline() const Q_DECL_OVERRIDE; @@ -172,7 +172,7 @@ private: }; -class QWindowsMultiFontEngine : public QFontEngineMultiQPA +class QWindowsMultiFontEngine : public QFontEngineMultiBasicImpl { public: explicit QWindowsMultiFontEngine(QFontEngine *fe, int script); diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index 2da014ddc3..9ee074b33e 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -74,7 +74,7 @@ public: bool getSfntTableData(uint tag, uchar *buffer, uint *length) const; QFixed emSquareSize() const; - virtual glyph_t glyphIndex(uint ucs4) const; + glyph_t glyphIndex(uint ucs4) const Q_DECL_OVERRIDE; bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const; void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const; diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index eaa4eca84e..e09018ef69 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -48,6 +48,7 @@ #include <QtCore/QSysInfo> #include <QtGui/QGuiApplication> #include <qpa/qplatformnativeinterface.h> +#include <QtPlatformHeaders/QWGLNativeContext> #include <algorithm> @@ -144,6 +145,131 @@ QT_BEGIN_NAMESPACE +QWindowsOpengl32DLL QOpenGLStaticContext::opengl32; + +void *QWindowsOpengl32DLL::resolve(const char *name) +{ +#ifndef Q_OS_WINCE + void *proc = m_lib ? (void *) ::GetProcAddress(m_lib, name) : 0; +#else + void *proc = m_lib ? (void *) ::GetProcAddress(m_lib, (const wchar_t *) QString::fromLatin1(name).utf16()) : 0; +#endif + if (!proc) + qErrnoWarning(::GetLastError(), "Failed to resolve OpenGL function %s", name); + + return proc; +} + +bool QWindowsOpengl32DLL::init(bool softwareRendering) +{ + const QByteArray opengl32 = QByteArrayLiteral("opengl32.dll"); + const QByteArray swopengl = QByteArrayLiteral("QtSoftwareOpenGL.dll"); + + QByteArray openglDll = qgetenv("QT_OPENGL_DLL"); + if (openglDll.isEmpty()) + openglDll = softwareRendering ? swopengl : opengl32; + + openglDll = openglDll.toLower(); + m_nonOpengl32 = openglDll != opengl32; + + qCDebug(lcQpaGl) << "Qt: Using WGL and OpenGL from" << openglDll; + + m_lib = ::LoadLibraryA(openglDll.constData()); + if (!m_lib) { + qErrnoWarning(::GetLastError(), "Failed to load %s", openglDll.constData()); + return false; + } + + if (moduleIsNotOpengl32()) { + // Load opengl32.dll always. GDI functions like ChoosePixelFormat do + // GetModuleHandle for opengl32.dll and behave differently (and call back into + // opengl32) when the module is present. This is fine for dummy contexts and windows. + ::LoadLibraryA("opengl32.dll"); + } + + wglCreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(resolve("wglCreateContext")); + wglDeleteContext = reinterpret_cast<BOOL (WINAPI *)(HGLRC)>(resolve("wglDeleteContext")); + wglGetCurrentContext = reinterpret_cast<HGLRC (WINAPI *)()>(resolve("wglGetCurrentContext")); + wglGetCurrentDC = reinterpret_cast<HDC (WINAPI *)()>(resolve("wglGetCurrentDC")); + wglGetProcAddress = reinterpret_cast<PROC (WINAPI *)(LPCSTR)>(resolve("wglGetProcAddress")); + wglMakeCurrent = reinterpret_cast<BOOL (WINAPI *)(HDC, HGLRC)>(resolve("wglMakeCurrent")); + wglShareLists = reinterpret_cast<BOOL (WINAPI *)(HGLRC, HGLRC)>(resolve("wglShareLists")); + wglSwapBuffers = reinterpret_cast<BOOL (WINAPI *)(HDC)>(resolve("wglSwapBuffers")); + wglSetPixelFormat = reinterpret_cast<BOOL (WINAPI *)(HDC, int, const PIXELFORMATDESCRIPTOR *)>(resolve("wglSetPixelFormat")); + + glBindTexture = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolve("glBindTexture")); + glBlendFunc = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolve("glBlendFunc")); + glClear = reinterpret_cast<void (APIENTRY *)(GLbitfield )>(resolve("glClear")); + glClearColor = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )>(resolve("glClearColor")); + glClearStencil = reinterpret_cast<void (APIENTRY *)(GLint )>(resolve("glClearStencil")); + glColorMask = reinterpret_cast<void (APIENTRY *)(GLboolean , GLboolean , GLboolean , GLboolean )>(resolve("glColorMask")); + glCopyTexImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLenum , GLint , GLint , GLsizei , GLsizei , GLint )>(resolve("glCopyTexImage2D")); + glCopyTexSubImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLint , GLint , GLsizei , GLsizei )>(resolve("glCopyTexSubImage2D")); + glCullFace = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glCullFace")); + glDeleteTextures = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint *)>(resolve("glDeleteTextures")); + glDepthFunc = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glDepthFunc")); + glDepthMask = reinterpret_cast<void (APIENTRY *)(GLboolean )>(resolve("glDepthMask")); + glDisable = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glDisable")); + glDrawArrays = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLsizei )>(resolve("glDrawArrays")); + glDrawElements = reinterpret_cast<void (APIENTRY *)(GLenum , GLsizei , GLenum , const GLvoid *)>(resolve("glDrawElements")); + glEnable = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glEnable")); + glFinish = reinterpret_cast<void (APIENTRY *)()>(resolve("glFinish")); + glFlush = reinterpret_cast<void (APIENTRY *)()>(resolve("glFlush")); + glFrontFace = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glFrontFace")); + glGenTextures = reinterpret_cast<void (APIENTRY *)(GLsizei , GLuint *)>(resolve("glGenTextures")); + glGetBooleanv = reinterpret_cast<void (APIENTRY *)(GLenum , GLboolean *)>(resolve("glGetBooleanv")); + glGetError = reinterpret_cast<GLenum (APIENTRY *)()>(resolve("glGetError")); + glGetFloatv = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat *)>(resolve("glGetFloatv")); + glGetIntegerv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint *)>(resolve("glGetIntegerv")); + glGetString = reinterpret_cast<const GLubyte * (APIENTRY *)(GLenum )>(resolve("glGetString")); + glGetTexParameterfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat *)>(resolve("glGetTexParameterfv")); + glGetTexParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint *)>(resolve("glGetTexParameteriv")); + glHint = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolve("glHint")); + glIsEnabled = reinterpret_cast<GLboolean (APIENTRY *)(GLenum )>(resolve("glIsEnabled")); + glIsTexture = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolve("glIsTexture")); + glLineWidth = reinterpret_cast<void (APIENTRY *)(GLfloat )>(resolve("glLineWidth")); + glPixelStorei = reinterpret_cast<void (APIENTRY *)(GLenum , GLint )>(resolve("glPixelStorei")); + glPolygonOffset = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat )>(resolve("glPolygonOffset")); + glReadPixels = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , GLvoid *)>(resolve("glReadPixels")); + glScissor = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )>(resolve("glScissor")); + glStencilFunc = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLuint )>(resolve("glStencilFunc")); + glStencilMask = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolve("glStencilMask")); + glStencilOp = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum )>(resolve("glStencilOp")); + glTexImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(resolve("glTexImage2D")); + glTexParameterf = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat )>(resolve("glTexParameterf")); + glTexParameterfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLfloat *)>(resolve("glTexParameterfv")); + glTexParameteri = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint )>(resolve("glTexParameteri")); + glTexParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLint *)>(resolve("glTexParameteriv")); + glTexSubImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(resolve("glTexSubImage2D")); + glViewport = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )>(resolve("glViewport")); + + glClearDepth = reinterpret_cast<void (APIENTRY *)(GLdouble )>(resolve("glClearDepth")); + glDepthRange = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble )>(resolve("glDepthRange")); + + return wglCreateContext && glBindTexture && glClearDepth; +} + +BOOL QWindowsOpengl32DLL::swapBuffers(HDC dc) +{ + if (moduleIsNotOpengl32()) + return wglSwapBuffers(dc); + else + return SwapBuffers(dc); +} + +BOOL QWindowsOpengl32DLL::setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd) +{ + if (moduleIsNotOpengl32()) + return wglSetPixelFormat(dc, pf, pfd); + else + return SetPixelFormat(dc, pf, pfd); +} + +QWindowsOpenGLContext *QOpenGLStaticContext::createContext(QOpenGLContext *context) +{ + return new QWindowsGLContext(this, context); +} + template <class MaskType, class FlagType> inline bool testFlag(MaskType mask, FlagType flag) { return (mask & MaskType(flag)) != 0; @@ -210,10 +336,11 @@ static inline bool bool ignoreGLSupport = false) // ARB format may not contain it. { const bool pixmapRequested = testFlag(additional.formatFlags, QWindowsGLRenderToPixmap); - return (ignoreGLSupport || testFlag(pfd.dwFlags, PFD_SUPPORT_OPENGL)) - && testFlag(pfd.dwFlags, PFD_DRAW_TO_BITMAP) == pixmapRequested - && hasGLOverlay(pfd) == testFlag(additional.formatFlags, QWindowsGLOverlay) - && (!pixmapRequested || pfd.cColorBits == additional.pixmapDepth); + const bool pixmapOk = !pixmapRequested || testFlag(pfd.dwFlags, PFD_DRAW_TO_BITMAP); + const bool colorOk = !pixmapRequested || pfd.cColorBits == additional.pixmapDepth; + const bool glOk = ignoreGLSupport || testFlag(pfd.dwFlags, PFD_SUPPORT_OPENGL); + const bool overlayOk = hasGLOverlay(pfd) == testFlag(additional.formatFlags, QWindowsGLOverlay); + return pixmapOk && glOk && overlayOk && colorOk; } static void describeFormats(HDC hdc) @@ -299,10 +426,23 @@ static PIXELFORMATDESCRIPTOR // over the available formats to find the best one. // Note: As of Windows 7, it seems direct-rendering is handled, so, // the code might be obsolete? +// +// NB! When using an implementation with a name different than opengl32.dll +// this code path should not be used since it will result in a mess due to GDI +// relying on and possibly calling back into functions in opengl32.dll (and not +// the one we are using). This is not a problem usually since for Mesa, which +// we are most likely to ship with a name other than opengl32.dll, the ARB code +// path should work. Hence the early bail out below. +// static int choosePixelFormat(HDC hdc, const QSurfaceFormat &format, const QWindowsOpenGLAdditionalFormat &additional, PIXELFORMATDESCRIPTOR *obtainedPfd) { + if (QOpenGLStaticContext::opengl32.moduleIsNotOpengl32()) { + qWarning("%s: Attempted to use GDI functions with a non-opengl32.dll library", Q_FUNC_INFO); + return 0; + } + // 1) Try ChoosePixelFormat(). PIXELFORMATDESCRIPTOR requestedPfd = qPixelFormatFromSurfaceFormat(format, QWindowsGLDirectRendering); initPixelFormatDescriptor(obtainedPfd); @@ -352,12 +492,12 @@ static int choosePixelFormat(HDC hdc, const QSurfaceFormat &format, static inline HGLRC createContext(HDC hdc, HGLRC shared) { - HGLRC result = wglCreateContext(hdc); + HGLRC result = QOpenGLStaticContext::opengl32.wglCreateContext(hdc); if (!result) { qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__); return 0; } - if (shared && !wglShareLists(shared, result)) + if (shared && !QOpenGLStaticContext::opengl32.wglShareLists(shared, result)) qErrnoWarning("%s: wglShareLists() failed.", __FUNCTION__); return result; } @@ -623,7 +763,7 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, if (!result) { QString message; QDebug(&message).nospace() << __FUNCTION__ << ": wglCreateContextAttribsARB() failed (GL error code: 0x" - << hex << glGetError() << dec << ") for format: " << format << ", shared context: " << shared; + << hex << staticContext.opengl32.glGetError() << dec << ") for format: " << format << ", shared context: " << shared; qErrnoWarning("%s", qPrintable(message)); } return result; @@ -648,16 +788,17 @@ static inline HGLRC createDummyGLContext(HDC dc) initPixelFormatDescriptor(&pixelFormDescriptor); pixelFormDescriptor.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT; pixelFormDescriptor.iPixelType = PFD_TYPE_RGBA; + // Use the GDI variant, for the dummy this is fine, even when using something other than opengl32.dll. const int pixelFormat = ChoosePixelFormat(dc, &pixelFormDescriptor); if (!pixelFormat) { qErrnoWarning("%s: ChoosePixelFormat failed.", __FUNCTION__); return 0; } - if (!SetPixelFormat(dc, pixelFormat, &pixelFormDescriptor)) { + if (!QOpenGLStaticContext::opengl32.setPixelFormat(dc, pixelFormat, &pixelFormDescriptor)) { qErrnoWarning("%s: SetPixelFormat failed.", __FUNCTION__); return 0; } - HGLRC rc = wglCreateContext(dc); + HGLRC rc = QOpenGLStaticContext::opengl32.wglCreateContext(dc); if (!rc) { qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__); return 0; @@ -668,8 +809,8 @@ static inline HGLRC createDummyGLContext(HDC dc) static inline QOpenGLContextData currentOpenGLContextData() { QOpenGLContextData result; - result.hdc = wglGetCurrentDC(); - result.renderingContext = wglGetCurrentContext(); + result.hdc = QOpenGLStaticContext::opengl32.wglGetCurrentDC(); + result.renderingContext = QOpenGLStaticContext::opengl32.wglGetCurrentContext(); return result; } @@ -721,7 +862,7 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current() } // v3 onwards GLint value = 0; - glGetIntegerv(GL_CONTEXT_FLAGS, &value); + QOpenGLStaticContext::opengl32.glGetIntegerv(GL_CONTEXT_FLAGS, &value); if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)) result.options |= QSurfaceFormat::DeprecatedFunctions; if (value & GL_CONTEXT_FLAG_DEBUG_BIT) @@ -730,7 +871,7 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current() return result; // v3.2 onwards: Profiles value = 0; - glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); + QOpenGLStaticContext::opengl32.glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); if (value & GL_CONTEXT_CORE_PROFILE_BIT) result.profile = QSurfaceFormat::CoreProfile; else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) @@ -784,15 +925,15 @@ QOpenGLTemporaryContext::QOpenGLTemporaryContext() : m_previous(currentOpenGLContextData()), m_current(createDummyWindowOpenGLContextData()) { - wglMakeCurrent(m_current.hdc, m_current.renderingContext); + QOpenGLStaticContext::opengl32.wglMakeCurrent(m_current.hdc, m_current.renderingContext); } QOpenGLTemporaryContext::~QOpenGLTemporaryContext() { - wglMakeCurrent(m_previous.hdc, m_previous.renderingContext); + QOpenGLStaticContext::opengl32.wglMakeCurrent(m_previous.hdc, m_previous.renderingContext); ReleaseDC(m_current.hwnd, m_current.hdc); DestroyWindow(m_current.hwnd); - wglDeleteContext(m_current.renderingContext); + QOpenGLStaticContext::opengl32.wglDeleteContext(m_current.renderingContext); } /*! @@ -807,6 +948,11 @@ QOpenGLTemporaryContext::~QOpenGLTemporaryContext() Functions pending integration in the next version of OpenGL are post-fixed ARB. + No WGL or OpenGL functions are called directly from the windows plugin. Instead, the + static context loads opengl32.dll and resolves the necessary functions. This allows + building the plugin without linking to opengl32 and enables QT_OPENGL_DYNAMIC builds + where both the EGL and WGL (this) based implementation of the context are built. + \note Initialization requires an active context (see create()). \sa QWindowsGLContext @@ -822,11 +968,11 @@ QOpenGLStaticContext::QOpenGLStaticContext() : extensionNames(QOpenGLStaticContext::getGlString(GL_EXTENSIONS)), extensions(0), defaultFormat(QWindowsOpenGLContextFormat::current()), - wglGetPixelFormatAttribIVARB((WglGetPixelFormatAttribIVARB)wglGetProcAddress("wglGetPixelFormatAttribivARB")), - wglChoosePixelFormatARB((WglChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB")), - wglCreateContextAttribsARB((WglCreateContextAttribsARB)wglGetProcAddress("wglCreateContextAttribsARB")), - wglSwapInternalExt((WglSwapInternalExt)wglGetProcAddress("wglSwapIntervalEXT")), - wglGetSwapInternalExt((WglGetSwapInternalExt)wglGetProcAddress("wglGetSwapIntervalEXT")) + wglGetPixelFormatAttribIVARB((WglGetPixelFormatAttribIVARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetPixelFormatAttribivARB")), + wglChoosePixelFormatARB((WglChoosePixelFormatARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglChoosePixelFormatARB")), + wglCreateContextAttribsARB((WglCreateContextAttribsARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglCreateContextAttribsARB")), + wglSwapInternalExt((WglSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglSwapIntervalEXT")), + wglGetSwapInternalExt((WglGetSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetSwapIntervalEXT")) { if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ") || extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1) @@ -835,16 +981,21 @@ QOpenGLStaticContext::QOpenGLStaticContext() : QByteArray QOpenGLStaticContext::getGlString(unsigned int which) { - if (const GLubyte *s = glGetString(which)) + if (const GLubyte *s = opengl32.glGetString(which)) return QByteArray((const char*)s); return QByteArray(); } -QOpenGLStaticContext *QOpenGLStaticContext::create() +QOpenGLStaticContext *QOpenGLStaticContext::create(bool softwareRendering) { + if (!opengl32.init(softwareRendering)) { + qWarning("%s: Failed to load and resolve WGL/OpenGL functions", Q_FUNC_INFO); + return 0; + } + // We need a current context for wglGetProcAdress()/getGLString() to work. QScopedPointer<QOpenGLTemporaryContext> temporaryContext; - if (!wglGetCurrentContext()) + if (!QOpenGLStaticContext::opengl32.wglGetCurrentContext()) temporaryContext.reset(new QOpenGLTemporaryContext); QOpenGLStaticContext *result = new QOpenGLStaticContext; qCDebug(lcQpaGl) << __FUNCTION__ << *result; @@ -881,15 +1032,61 @@ QDebug operator<<(QDebug d, const QOpenGLStaticContext &s) \ingroup qt-lighthouse-win */ -QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContext, +QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context) : m_staticContext(staticContext), m_context(context), m_renderingContext(0), m_pixelFormat(0), m_extensionsUsed(false), - m_swapInterval(-1) + m_swapInterval(-1), + m_ownsContext(true) { + if (!m_staticContext) // Something went very wrong. Stop here, isValid() will return false. + return; + + QVariant nativeHandle = context->nativeHandle(); + if (!nativeHandle.isNull()) { + // Adopt and existing context. + if (!nativeHandle.canConvert<QWGLNativeContext>()) { + qWarning("QWindowsGLContext: Requires a QWGLNativeContext"); + return; + } + QWGLNativeContext handle = nativeHandle.value<QWGLNativeContext>(); + HGLRC wglcontext = handle.context(); + HWND wnd = handle.window(); + if (!wglcontext || !wnd) { + qWarning("QWindowsGLContext: No context and window given"); + return; + } + + HDC dc = GetDC(wnd); + // A window with an associated pixel format is mandatory. + // When no SetPixelFormat() call has been made, the following will fail. + m_pixelFormat = GetPixelFormat(dc); + bool ok = m_pixelFormat != 0; + if (!ok) + qWarning("QWindowsGLContext: Failed to get pixel format"); + ok = DescribePixelFormat(dc, m_pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &m_obtainedPixelFormatDescriptor); + if (!ok) { + qWarning("QWindowsGLContext: Failed to describe pixel format"); + } else { + QWindowsOpenGLAdditionalFormat obtainedAdditional; + m_obtainedFormat = GDI::qSurfaceFormatFromPixelFormat(m_obtainedPixelFormatDescriptor, &obtainedAdditional); + m_renderingContext = wglcontext; + ok = updateObtainedParams(dc); + } + + ReleaseDC(wnd, dc); + + if (ok) + m_ownsContext = false; + else + m_renderingContext = 0; + + return; + } + QSurfaceFormat format = context->format(); if (format.renderableType() == QSurfaceFormat::DefaultRenderableType) format.setRenderableType(QSurfaceFormat::OpenGL); @@ -901,7 +1098,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex static bool opengl32dll = false; if (!opengl32dll) { GLint params; - glGetIntegerv(GL_DEPTH_BITS, ¶ms); + staticContext->opengl32.glGetIntegerv(GL_DEPTH_BITS, ¶ms); opengl32dll = true; } @@ -912,7 +1109,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex HWND dummyWindow = 0; HDC hdc = 0; bool tryExtensions = false; - int obtainedSwapInternal = -1; + int obtainedSwapInterval = -1; do { dummyWindow = createDummyGLWindow(); if (!dummyWindow) @@ -954,7 +1151,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex qWarning("%s: Unable find a suitable pixel format.", __FUNCTION__); break; } - if (!SetPixelFormat(hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { + if (!QOpenGLStaticContext::opengl32.setPixelFormat(hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { qErrnoWarning("SetPixelFormat failed."); break; } @@ -978,18 +1175,16 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex } // Query obtained parameters and apply swap interval. - if (!wglMakeCurrent(hdc, m_renderingContext)) { - qWarning("Failed to make context current."); + if (!updateObtainedParams(hdc, &obtainedSwapInterval)) break; - } - QWindowsOpenGLContextFormat::current().apply(&m_obtainedFormat); + } while (false); - if (m_staticContext->wglGetSwapInternalExt) - obtainedSwapInternal = m_staticContext->wglGetSwapInternalExt(); + // Make the HGLRC retrievable via QOpenGLContext::nativeHandle(). + // Do not provide the window since it is the dummy one and it is about to disappear. + if (m_renderingContext) + context->setNativeHandle(QVariant::fromValue<QWGLNativeContext>(QWGLNativeContext(m_renderingContext, 0))); - wglMakeCurrent(0, 0); - } while (false); if (hdc) ReleaseDC(dummyWindow, hdc); if (dummyWindow) @@ -998,18 +1193,34 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex qCDebug(lcQpaGl) << __FUNCTION__ << this << (tryExtensions ? "ARB" : "GDI") << " requested: " << context->format() << "\n obtained #" << m_pixelFormat << (m_extensionsUsed ? "ARB" : "GDI") << m_obtainedFormat - << "\n " << m_obtainedPixelFormatDescriptor << " swap interval: " << obtainedSwapInternal + << "\n " << m_obtainedPixelFormatDescriptor << " swap interval: " << obtainedSwapInterval << "\n default: " << m_staticContext->defaultFormat << "\n HGLRC=" << m_renderingContext; } QWindowsGLContext::~QWindowsGLContext() { - if (m_renderingContext) - wglDeleteContext(m_renderingContext); + if (m_renderingContext && m_ownsContext) + QOpenGLStaticContext::opengl32.wglDeleteContext(m_renderingContext); releaseDCs(); } +bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval) +{ + if (!QOpenGLStaticContext::opengl32.wglMakeCurrent(hdc, m_renderingContext)) { + qWarning("Failed to make context current."); + return false; + } + + QWindowsOpenGLContextFormat::current().apply(&m_obtainedFormat); + + if (m_staticContext->wglGetSwapInternalExt && obtainedSwapInterval) + *obtainedSwapInterval = m_staticContext->wglGetSwapInternalExt(); + + QOpenGLStaticContext::opengl32.wglMakeCurrent(0, 0); + return true; +} + void QWindowsGLContext::releaseDCs() { const QOpenGLContextData *end = m_windowContexts.end(); @@ -1043,11 +1254,11 @@ void QWindowsGLContext::swapBuffers(QPlatformSurface *surface) { if (QWindowsContext::verbose > 1) qCDebug(lcQpaGl) << __FUNCTION__ << surface; - if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, handleOf(surface))) { - SwapBuffers(contextData->hdc); - } else { + + if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, handleOf(surface))) + QOpenGLStaticContext::opengl32.swapBuffers(contextData->hdc); + else qWarning("%s: Cannot find window %p", __FUNCTION__, handleOf(surface)); - } } bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) @@ -1066,11 +1277,11 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) // Repeated calls to wglMakeCurrent when vsync is enabled in the driver will // often result in 100% cpuload. This check is cheap and avoids the problem. // This is reproducable on NVidia cards and Intel onboard chips. - if (wglGetCurrentContext() == contextData->renderingContext - && wglGetCurrentDC() == contextData->hdc) { + if (QOpenGLStaticContext::opengl32.wglGetCurrentContext() == contextData->renderingContext + && QOpenGLStaticContext::opengl32.wglGetCurrentDC() == contextData->hdc) { return true; } - return wglMakeCurrent(contextData->hdc, contextData->renderingContext); + return QOpenGLStaticContext::opengl32.wglMakeCurrent(contextData->hdc, contextData->renderingContext); } // Create a new entry. const QOpenGLContextData newContext(m_renderingContext, hwnd, GetDC(hwnd)); @@ -1079,7 +1290,7 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) // Initialize pixel format first time. This will apply to // the HWND as well and must be done only once. if (!window->testFlag(QWindowsWindow::OpenGlPixelFormatInitialized)) { - if (!SetPixelFormat(newContext.hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { + if (!QOpenGLStaticContext::opengl32.setPixelFormat(newContext.hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { qErrnoWarning("%s: SetPixelFormat() failed", __FUNCTION__); ReleaseDC(newContext.hwnd, newContext.hdc); return false; @@ -1090,7 +1301,7 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) } m_windowContexts.append(newContext); - bool success = wglMakeCurrent(newContext.hdc, newContext.renderingContext); + bool success = QOpenGLStaticContext::opengl32.wglMakeCurrent(newContext.hdc, newContext.renderingContext); // Set the swap interval if (m_staticContext->wglSwapInternalExt) { @@ -1110,17 +1321,83 @@ void QWindowsGLContext::doneCurrent() if (QWindowsContext::verbose > 1) qCDebug(lcQpaGl) << __FUNCTION__ << this << m_windowContexts.size() << "contexts"; #endif // DEBUG_GL - wglMakeCurrent(0, 0); + QOpenGLStaticContext::opengl32.wglMakeCurrent(0, 0); releaseDCs(); } -QWindowsGLContext::GL_Proc QWindowsGLContext::getProcAddress(const QByteArray &procName) +QFunctionPointer QWindowsGLContext::getProcAddress(const QByteArray &procName) { - // TODO: Will that work with the calling conventions? - GL_Proc procAddress = reinterpret_cast<GL_Proc>(wglGetProcAddress(procName.constData())); + // We support AllGLFunctionsQueryable, which means this function must be able to + // return a function pointer even for functions that are in GL.h and exported + // normally from opengl32.dll. wglGetProcAddress() is not guaranteed to work for such + // functions, however in QT_OPENGL_DYNAMIC builds QOpenGLFunctions will just blindly + // call into here for _any_ OpenGL function. Hence the need to handle these specially + // here. The list has to match QOpenGLFunctions. See + // QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *). + static struct StdFunc { + const char *name; + void *func; + } standardFuncs[] = { + { "glBindTexture", (void *) QOpenGLStaticContext::opengl32.glBindTexture }, + { "glBlendFunc", (void *) QOpenGLStaticContext::opengl32.glBlendFunc }, + { "glClear", (void *) QOpenGLStaticContext::opengl32.glClear }, + { "glClearColor", (void *) QOpenGLStaticContext::opengl32.glClearColor }, + { "glClearStencil", (void *) QOpenGLStaticContext::opengl32.glClearStencil }, + { "glColorMask", (void *) QOpenGLStaticContext::opengl32.glColorMask }, + { "glCopyTexImage2D", (void *) QOpenGLStaticContext::opengl32.glCopyTexImage2D }, + { "glCopyTexSubImage2D", (void *) QOpenGLStaticContext::opengl32.glCopyTexSubImage2D }, + { "glCullFace", (void *) QOpenGLStaticContext::opengl32.glCullFace }, + { "glDeleteTextures", (void *) QOpenGLStaticContext::opengl32.glDeleteTextures }, + { "glDepthFunc", (void *) QOpenGLStaticContext::opengl32.glDepthFunc }, + { "glDepthMask", (void *) QOpenGLStaticContext::opengl32.glDepthMask }, + { "glDisable", (void *) QOpenGLStaticContext::opengl32.glDisable }, + { "glDrawArrays", (void *) QOpenGLStaticContext::opengl32.glDrawArrays }, + { "glDrawElements", (void *) QOpenGLStaticContext::opengl32.glDrawElements }, + { "glEnable", (void *) QOpenGLStaticContext::opengl32.glEnable }, + { "glFinish", (void *) QOpenGLStaticContext::opengl32.glFinish }, + { "glFlush", (void *) QOpenGLStaticContext::opengl32.glFlush }, + { "glFrontFace", (void *) QOpenGLStaticContext::opengl32.glFrontFace }, + { "glGenTextures", (void *) QOpenGLStaticContext::opengl32.glGenTextures }, + { "glGetBooleanv", (void *) QOpenGLStaticContext::opengl32.glGetBooleanv }, + { "glGetError", (void *) QOpenGLStaticContext::opengl32.glGetError }, + { "glGetFloatv", (void *) QOpenGLStaticContext::opengl32.glGetFloatv }, + { "glGetIntegerv", (void *) QOpenGLStaticContext::opengl32.glGetIntegerv }, + { "glGetString", (void *) QOpenGLStaticContext::opengl32.glGetString }, + { "glGetTexParameterfv", (void *) QOpenGLStaticContext::opengl32.glGetTexParameterfv }, + { "glGetTexParameteriv", (void *) QOpenGLStaticContext::opengl32.glGetTexParameteriv }, + { "glHint", (void *) QOpenGLStaticContext::opengl32.glHint }, + { "glIsEnabled", (void *) QOpenGLStaticContext::opengl32.glIsEnabled }, + { "glIsTexture", (void *) QOpenGLStaticContext::opengl32.glIsTexture }, + { "glLineWidth", (void *) QOpenGLStaticContext::opengl32.glLineWidth }, + { "glPixelStorei", (void *) QOpenGLStaticContext::opengl32.glPixelStorei }, + { "glPolygonOffset", (void *) QOpenGLStaticContext::opengl32.glPolygonOffset }, + { "glReadPixels", (void *) QOpenGLStaticContext::opengl32.glReadPixels }, + { "glScissor", (void *) QOpenGLStaticContext::opengl32.glScissor }, + { "glStencilFunc", (void *) QOpenGLStaticContext::opengl32.glStencilFunc }, + { "glStencilMask", (void *) QOpenGLStaticContext::opengl32.glStencilMask }, + { "glStencilOp", (void *) QOpenGLStaticContext::opengl32.glStencilOp }, + { "glTexImage2D", (void *) QOpenGLStaticContext::opengl32.glTexImage2D }, + { "glTexParameterf", (void *) QOpenGLStaticContext::opengl32.glTexParameterf }, + { "glTexParameterfv", (void *) QOpenGLStaticContext::opengl32.glTexParameterfv }, + { "glTexParameteri", (void *) QOpenGLStaticContext::opengl32.glTexParameteri }, + { "glTexParameteriv", (void *) QOpenGLStaticContext::opengl32.glTexParameteriv }, + { "glTexSubImage2D", (void *) QOpenGLStaticContext::opengl32.glTexSubImage2D }, + { "glViewport", (void *) QOpenGLStaticContext::opengl32.glViewport }, + + { "glClearDepth", (void *) QOpenGLStaticContext::opengl32.glClearDepth }, + { "glDepthRange", (void *) QOpenGLStaticContext::opengl32.glDepthRange }, + }; + for (size_t i = 0; i < sizeof(standardFuncs) / sizeof(StdFunc); ++i) + if (procName == standardFuncs[i].name) + return reinterpret_cast<QFunctionPointer>(standardFuncs[i].func); + + // Even though we use QFunctionPointer, it does not mean the function can be called. + // It will need to be cast to the proper function type with the correct calling + // convention. QFunctionPointer is nothing more than a glorified void* here. + QFunctionPointer procAddress = reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress(procName.constData())); if (QWindowsContext::verbose > 1) - qCDebug(lcQpaGl) << __FUNCTION__ << procName << wglGetCurrentContext() << "returns" << procAddress; - if (!procAddress) + qCDebug(lcQpaGl) << __FUNCTION__ << procName << QOpenGLStaticContext::opengl32.wglGetCurrentContext() << "returns" << procAddress; + if (!procAddress && QWindowsContext::verbose) qWarning("%s: Unable to resolve '%s'", __FUNCTION__, procName.constData()); return procAddress; } diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index c6b477128a..0afeb67a65 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -44,10 +44,9 @@ #include "array.h" #include "qtwindows_additional.h" +#include "qwindowsopenglcontext.h" -#include <qpa/qplatformopenglcontext.h> #include <QtGui/QOpenGLContext> -#include <QtCore/QSharedPointer> QT_BEGIN_NAMESPACE @@ -81,6 +80,8 @@ struct QOpenGLContextData HDC hdc; }; +class QOpenGLStaticContext; + struct QWindowsOpenGLContextFormat { QWindowsOpenGLContextFormat(); @@ -94,7 +95,87 @@ struct QWindowsOpenGLContextFormat QDebug operator<<(QDebug d, const QWindowsOpenGLContextFormat &); -class QOpenGLStaticContext +struct QWindowsOpengl32DLL +{ + bool init(bool softwareRendering); + void *moduleHandle() const { return m_lib; } + bool moduleIsNotOpengl32() const { return m_nonOpengl32; } + + // Wrappers. Always use these instead of SwapBuffers/wglSwapBuffers/etc. + BOOL swapBuffers(HDC dc); + BOOL setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd); + + // WGL + HGLRC (WINAPI * wglCreateContext)(HDC dc); + BOOL (WINAPI * wglDeleteContext)(HGLRC context); + HGLRC (WINAPI * wglGetCurrentContext)(); + HDC (WINAPI * wglGetCurrentDC)(); + PROC (WINAPI * wglGetProcAddress)(LPCSTR name); + BOOL (WINAPI * wglMakeCurrent)(HDC dc, HGLRC context); + BOOL (WINAPI * wglShareLists)(HGLRC context1, HGLRC context2); + + // GL1+GLES2 common + void (APIENTRY * glBindTexture)(GLenum target, GLuint texture); + void (APIENTRY * glBlendFunc)(GLenum sfactor, GLenum dfactor); + void (APIENTRY * glClear)(GLbitfield mask); + void (APIENTRY * glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY * glClearStencil)(GLint s); + void (APIENTRY * glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + void (APIENTRY * glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); + void (APIENTRY * glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * glCullFace)(GLenum mode); + void (APIENTRY * glDeleteTextures)(GLsizei n, const GLuint* textures); + void (APIENTRY * glDepthFunc)(GLenum func); + void (APIENTRY * glDepthMask)(GLboolean flag); + void (APIENTRY * glDisable)(GLenum cap); + void (APIENTRY * glDrawArrays)(GLenum mode, GLint first, GLsizei count); + void (APIENTRY * glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices); + void (APIENTRY * glEnable)(GLenum cap); + void (APIENTRY * glFinish)(); + void (APIENTRY * glFlush)(); + void (APIENTRY * glFrontFace)(GLenum mode); + void (APIENTRY * glGenTextures)(GLsizei n, GLuint* textures); + void (APIENTRY * glGetBooleanv)(GLenum pname, GLboolean* params); + GLenum (APIENTRY * glGetError)(); + void (APIENTRY * glGetFloatv)(GLenum pname, GLfloat* params); + void (APIENTRY * glGetIntegerv)(GLenum pname, GLint* params); + const GLubyte * (APIENTRY * glGetString)(GLenum name); + void (APIENTRY * glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params); + void (APIENTRY * glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * glHint)(GLenum target, GLenum mode); + GLboolean (APIENTRY * glIsEnabled)(GLenum cap); + GLboolean (APIENTRY * glIsTexture)(GLuint texture); + void (APIENTRY * glLineWidth)(GLfloat width); + void (APIENTRY * glPixelStorei)(GLenum pname, GLint param); + void (APIENTRY * glPolygonOffset)(GLfloat factor, GLfloat units); + void (APIENTRY * glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); + void (APIENTRY * glScissor)(GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * glStencilFunc)(GLenum func, GLint ref, GLuint mask); + void (APIENTRY * glStencilMask)(GLuint mask); + void (APIENTRY * glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass); + void (APIENTRY * glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels); + void (APIENTRY * glTexParameterf)(GLenum target, GLenum pname, GLfloat param); + void (APIENTRY * glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params); + void (APIENTRY * glTexParameteri)(GLenum target, GLenum pname, GLint param); + void (APIENTRY * glTexParameteriv)(GLenum target, GLenum pname, const GLint* params); + void (APIENTRY * glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels); + void (APIENTRY * glViewport)(GLint x, GLint y, GLsizei width, GLsizei height); + + // GL only + void (APIENTRY * glClearDepth)(GLdouble depth); + void (APIENTRY * glDepthRange)(GLdouble zNear, GLdouble zFar); + +private: + void *resolve(const char *name); + HMODULE m_lib; + bool m_nonOpengl32; + + // For Mesa llvmpipe shipped with a name other than opengl32.dll + BOOL (WINAPI * wglSwapBuffers)(HDC dc); + BOOL (WINAPI * wglSetPixelFormat)(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd); +}; + +class QOpenGLStaticContext : public QWindowsStaticOpenGLContext { Q_DISABLE_COPY(QOpenGLStaticContext) QOpenGLStaticContext(); @@ -125,9 +206,17 @@ public: bool hasExtensions() const { return wglGetPixelFormatAttribIVARB && wglChoosePixelFormatARB && wglCreateContextAttribsARB; } - static QOpenGLStaticContext *create(); + static QOpenGLStaticContext *create(bool softwareRendering = false); static QByteArray getGlString(unsigned int which); + QWindowsOpenGLContext *createContext(QOpenGLContext *context); + void *moduleHandle() const { return opengl32.moduleHandle(); } + QOpenGLContext::OpenGLModuleType moduleType() const { return QOpenGLContext::LibGL; } + + // For a regular opengl32.dll report the ThreadedOpenGL capability. + // For others, which are likely to be software-only, don't. + bool supportsThreadedOpenGL() const { return !opengl32.moduleIsNotOpengl32(); } + const QByteArray vendor; const QByteArray renderer; const QByteArray extensionNames; @@ -139,37 +228,39 @@ public: WglCreateContextAttribsARB wglCreateContextAttribsARB; WglSwapInternalExt wglSwapInternalExt; WglGetSwapInternalExt wglGetSwapInternalExt; + + static QWindowsOpengl32DLL opengl32; }; QDebug operator<<(QDebug d, const QOpenGLStaticContext &); -class QWindowsGLContext : public QPlatformOpenGLContext +class QWindowsGLContext : public QWindowsOpenGLContext { public: - typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr; - - explicit QWindowsGLContext(const QOpenGLStaticContextPtr &staticContext, - QOpenGLContext *context); - virtual ~QWindowsGLContext(); - bool isSharing() const { return m_context->shareHandle(); } - bool isValid() const { return m_renderingContext; } - virtual QSurfaceFormat format() const { return m_obtainedFormat; } + explicit QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context); + ~QWindowsGLContext(); + bool isSharing() const Q_DECL_OVERRIDE { return m_context->shareHandle(); } + bool isValid() const Q_DECL_OVERRIDE { return m_renderingContext; } + QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_obtainedFormat; } - virtual void swapBuffers(QPlatformSurface *surface); + void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; - virtual bool makeCurrent(QPlatformSurface *surface); - virtual void doneCurrent(); + bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE; + void doneCurrent() Q_DECL_OVERRIDE; typedef void (*GL_Proc) (); - virtual GL_Proc getProcAddress(const QByteArray &procName); + QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; + + HGLRC renderingContext() const { return m_renderingContext; } - HGLRC renderingContext() const { return m_renderingContext; } + void *nativeContext() const Q_DECL_OVERRIDE { return m_renderingContext; } private: inline void releaseDCs(); + bool updateObtainedParams(HDC hdc, int *obtainedSwapInterval = 0); - const QOpenGLStaticContextPtr m_staticContext; + QOpenGLStaticContext *m_staticContext; QOpenGLContext *m_context; QSurfaceFormat m_obtainedFormat; HGLRC m_renderingContext; @@ -178,6 +269,7 @@ private: int m_pixelFormat; bool m_extensionsUsed; int m_swapInterval; + bool m_ownsContext; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp index 878db7185d..8a8306f01a 100644 --- a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp +++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp @@ -115,6 +115,9 @@ messageDebugEntries[] = { {WM_SYSCOMMAND, "WM_SYSCOMMAND", true}, {WM_KEYUP, "WM_KEYUP", true}, {WM_SYSKEYUP, "WM_SYSKEYUP", true}, +#if defined(WM_APPCOMMAND) + {WM_APPCOMMAND, "WM_APPCOMMAND", true}, +#endif {WM_IME_CHAR, "WM_IMECHAR", true}, {WM_IME_KEYDOWN, "WM_IMECHAR", true}, {WM_CANCELMODE, "WM_CANCELMODE", true}, diff --git a/src/plugins/platforms/windows/qwindowsguieventdispatcher.h b/src/plugins/platforms/windows/qwindowsguieventdispatcher.h index 65ef912b43..6f67c47279 100644 --- a/src/plugins/platforms/windows/qwindowsguieventdispatcher.h +++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.h @@ -59,8 +59,8 @@ public: static const char *windowsMessageName(UINT msg); - virtual bool QT_ENSURE_STACK_ALIGNED_FOR_SSE processEvents(QEventLoop::ProcessEventsFlags flags); - virtual void sendPostedEvents(); + bool QT_ENSURE_STACK_ALIGNED_FOR_SSE processEvents(QEventLoop::ProcessEventsFlags flags) Q_DECL_OVERRIDE; + void sendPostedEvents() Q_DECL_OVERRIDE; private: QEventLoop::ProcessEventsFlags m_flags; diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 2429e8a4fa..bc7ffc9afd 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -88,18 +88,6 @@ static inline void imeNotifyCancelComposition(HWND hwnd) ImmReleaseContext(hwnd, himc); } -// Query a QObject for an InputMethod-related value -// by sending a QInputMethodQueryEvent. -template <class T> - bool inputMethodQuery(QObject *fo, Qt::InputMethodQuery query, T *result) -{ - QInputMethodQueryEvent queryEvent(query); - if (!QCoreApplication::sendEvent(fo, &queryEvent)) - return false; - *result = qvariant_cast<T>(queryEvent.value(query)); - return true; -} - /*! \class QWindowsInputContext \brief Windows Input context implementation @@ -170,7 +158,7 @@ QWindowsInputContext::QWindowsInputContext() : m_WM_MSIME_MOUSE(RegisterWindowMessage(L"MSIMEMouseOperation")), m_endCompositionRecursionGuard(false) { - connect(qApp->inputMethod(), SIGNAL(cursorRectangleChanged()), + connect(QGuiApplication::inputMethod(), SIGNAL(cursorRectangleChanged()), this, SLOT(cursorRectChanged())); } @@ -215,7 +203,7 @@ void QWindowsInputContext::cursorRectChanged() { if (!m_compositionContext.hwnd) return; - const QInputMethod *inputMethod = qApp->inputMethod(); + const QInputMethod *inputMethod = QGuiApplication::inputMethod(); QRect cursorRectangle = inputMethod->cursorRectangle().toRect(); if (!cursorRectangle.isValid()) return; @@ -536,9 +524,10 @@ int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv) if (!fo) return false; - QString surroundingText; - if (!inputMethodQuery(fo, Qt::ImSurroundingText, &surroundingText)) + const QVariant surroundingTextV = QInputMethod::queryFocusObject(Qt::ImSurroundingText, QVariant()); + if (!surroundingTextV.isValid()) return -1; + const QString surroundingText = surroundingTextV.toString(); const DWORD memSize = sizeof(RECONVERTSTRING) + (surroundingText.length() + 1) * sizeof(ushort); qCDebug(lcQpaInputMethods) << __FUNCTION__ << " reconv=" << reconv @@ -547,8 +536,8 @@ int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv) if (!reconv) return surroundingText.isEmpty() ? -1 : int(memSize); - int pos = 0; - inputMethodQuery(fo, Qt::ImCursorPosition, &pos); + const QVariant posV = QInputMethod::queryFocusObject(Qt::ImCursorPosition, QVariant()); + const int pos = posV.isValid() ? posV.toInt() : 0; // Find the word in the surrounding text. QTextBoundaryFinder bounds(QTextBoundaryFinder::Word, surroundingText); bounds.setPosition(pos); diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h index 31a076cbf8..51ea8adf1e 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.h +++ b/src/plugins/platforms/windows/qwindowsinputcontext.h @@ -68,9 +68,9 @@ public: explicit QWindowsInputContext(); ~QWindowsInputContext(); - virtual void reset(); - virtual void update(Qt::InputMethodQueries); - virtual void invokeAction(QInputMethod::Action, int cursorPosition); + void reset() Q_DECL_OVERRIDE; + void update(Qt::InputMethodQueries) Q_DECL_OVERRIDE; + void invokeAction(QInputMethod::Action, int cursorPosition) Q_DECL_OVERRIDE; static QWindowsInputContext *instance(); diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 78bf833526..529dd75ed5 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch> -** 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. @@ -43,19 +43,7 @@ #include "qwindowsintegration.h" #include "qwindowswindow.h" #include "qwindowscontext.h" - -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -# include "qwindowseglcontext.h" -# include <QtGui/QOpenGLContext> -#endif - -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) -# include "qwindowsglcontext.h" -#endif - -#if !defined(QT_NO_OPENGL) -# include <QtGui/QOpenGLFunctions> -#endif +#include "qwindowsopenglcontext.h" #include "qwindowsscreen.h" #include "qwindowstheme.h" @@ -89,6 +77,19 @@ #include <QtCore/QDebug> #include <QtCore/QVariant> +#include <limits.h> + +#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) +# include "qwindowseglcontext.h" +#endif +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) +# include "qwindowsglcontext.h" +#endif + +#ifndef Q_OS_WINCE +# include "qwindowsopengltester.h" +#endif + QT_BEGIN_NAMESPACE /*! @@ -134,15 +135,9 @@ QT_BEGIN_NAMESPACE struct QWindowsIntegrationPrivate { -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - typedef QSharedPointer<QWindowsEGLStaticContext> QEGLStaticContextPtr; -#endif -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) - typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr; -#endif - explicit QWindowsIntegrationPrivate(const QStringList ¶mList); ~QWindowsIntegrationPrivate(); + bool ensureStaticOpenGLContext(); unsigned m_options; QWindowsContext m_context; @@ -153,12 +148,9 @@ struct QWindowsIntegrationPrivate QWindowsDrag m_drag; # endif #endif -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - QEGLStaticContextPtr m_staticEGLContext; -#endif -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) - QOpenGLStaticContextPtr m_staticOpenGLContext; -#endif +#ifndef QT_NO_OPENGL + QSharedPointer<QWindowsStaticOpenGLContext> m_staticOpenGLContext; +#endif // QT_NO_OPENGL QScopedPointer<QPlatformInputContext> m_inputContext; #ifndef QT_NO_ACCESSIBILITY QWindowsAccessibility m_accessibility; @@ -166,8 +158,32 @@ struct QWindowsIntegrationPrivate QWindowsServices m_services; }; +template <typename IntType> +bool parseIntOption(const QString ¶meter,const QLatin1String &option, + IntType minimumValue, IntType maximumValue, IntType *target) +{ + const int valueLength = parameter.size() - option.size() - 1; + if (valueLength < 1 || !parameter.startsWith(option) || parameter.at(option.size()) != QLatin1Char('=')) + return false; + bool ok; + const QStringRef valueRef = parameter.rightRef(valueLength); + const int value = valueRef.toInt(&ok); + if (ok) { + if (value >= minimumValue && value <= maximumValue) + *target = static_cast<IntType>(value); + else { + qWarning() << "Value" << value << "for option" << option << "out of range" + << minimumValue << ".." << maximumValue; + } + } else { + qWarning() << "Invalid value" << valueRef << "for option" << option; + } + return true; +} + static inline unsigned parseOptions(const QStringList ¶mList, - int *tabletAbsoluteRange) + int *tabletAbsoluteRange, + QtWindows::ProcessDpiAwareness *dpiAwareness) { unsigned options = 0; foreach (const QString ¶m, paramList) { @@ -187,10 +203,11 @@ static inline unsigned parseOptions(const QStringList ¶mList, options |= QWindowsIntegration::DisableArb; } else if (param == QLatin1String("nomousefromtouch")) { options |= QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch; - } else if (param.startsWith(QLatin1String("verbose="))) { - QWindowsContext::verbose = param.right(param.size() - 8).toInt(); - } else if (param.startsWith(QLatin1String("tabletabsoluterange="))) { - *tabletAbsoluteRange = param.rightRef(param.size() - 20).toInt(); + } else if (parseIntOption(param, QLatin1String("verbose"), 0, INT_MAX, &QWindowsContext::verbose) + || parseIntOption(param, QLatin1String("tabletabsoluterange"), 0, INT_MAX, tabletAbsoluteRange) + || parseIntOption(param, QLatin1String("dpiawareness"), QtWindows::ProcessDpiUnaware, QtWindows::ProcessPerMonitorDpiAware, dpiAwareness)) { + } else { + qWarning() << "Unknown option" << param; } } return options; @@ -201,9 +218,13 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL , m_fontDatabase(0) { int tabletAbsoluteRange = -1; - m_options = parseOptions(paramList, &tabletAbsoluteRange); + // Default to per-monitor awareness to avoid being scaled when monitors with different DPI + // are connected to Windows 8.1 + QtWindows::ProcessDpiAwareness dpiAwareness = QtWindows::ProcessPerMonitorDpiAware; + m_options = parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness); if (tabletAbsoluteRange >= 0) m_context.setTabletAbsoluteRange(tabletAbsoluteRange); + m_context.setProcessDpiAwareness(dpiAwareness); } QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate() @@ -242,12 +263,7 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co case OpenGL: return true; case ThreadedOpenGL: -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - return QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL - ? QWindowsEGLContext::hasThreadedOpenGLCapability() : true; -# else - return true; -# endif // QT_OPENGL_ES_2 + return d->ensureStaticOpenGLContext() ? d->m_staticOpenGLContext->supportsThreadedOpenGL() : false; #endif // !QT_NO_OPENGL case WindowMasks: return true; @@ -257,6 +273,8 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co return true; case RasterGLSurface: return true; + case AllGLFunctionsQueryable: + return true; default: return QPlatformIntegration::hasCapability(cap); } @@ -273,8 +291,7 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const if (customMarginsV.isValid()) requested.customMargins = qvariant_cast<QMargins>(customMarginsV); - const QWindowsWindowData obtained - = QWindowsWindowData::create(window, requested, window->title()); + QWindowsWindowData obtained = QWindowsWindowData::create(window, requested, window->title()); qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << '<' << window << "\n Requested: " << requested.geometry << "frame incl.: " @@ -292,6 +309,11 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const QWindowSystemInterface::handleGeometryChange(window, obtained.geometry); } +#ifndef QT_NO_OPENGL + d->ensureStaticOpenGLContext(); + obtained.staticOpenGLContext = d->m_staticOpenGLContext; +#endif // QT_NO_OPENGL + return obtained; } @@ -303,32 +325,80 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons } #ifndef QT_NO_OPENGL -QPlatformOpenGLContext - *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +static QWindowsStaticOpenGLContext *q_staticOpenGLContext = 0; + +QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::create() { - qCDebug(lcQpaGl) << __FUNCTION__ << context->format(); -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) { - if (d->m_staticEGLContext.isNull()) { - QWindowsEGLStaticContext *staticContext = QWindowsEGLStaticContext::create(); - if (!staticContext) - return 0; - d->m_staticEGLContext = QSharedPointer<QWindowsEGLStaticContext>(staticContext); + QWindowsStaticOpenGLContext *ctx = 0; + +#if defined(QT_OPENGL_DYNAMIC) + const QByteArray requested = qgetenv("QT_OPENGL"); // angle, desktop, software + const bool angleRequested = QCoreApplication::testAttribute(Qt::AA_UseOpenGLES) || requested == QByteArrayLiteral("angle"); + const bool desktopRequested = QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL) || requested == QByteArrayLiteral("desktop"); + const bool softwareRequested = QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL) || requested == QByteArrayLiteral("software"); + + // If ANGLE is requested, use it, don't try anything else. + if (angleRequested) { + ctx = QWindowsEGLStaticContext::create(); + } else { + // If opengl32.dll seems to be OpenGL 2.x capable, or desktop OpenGL is requested, use it. + if (!softwareRequested && (desktopRequested || QWindowsOpenGLTester::testDesktopGL())) + ctx = QOpenGLStaticContext::create(); + // If failed and desktop OpenGL is not explicitly requested, try ANGLE. + if (!ctx && !desktopRequested && !softwareRequested) + ctx = QWindowsEGLStaticContext::create(); + // Try software. + if (!ctx) { + ctx = QOpenGLStaticContext::create(true); + // If software was explicitly requested but failed, try the regular one. + if (!ctx && softwareRequested && QWindowsOpenGLTester::testDesktopGL()) + ctx = QOpenGLStaticContext::create(); } - return new QWindowsEGLContext(d->m_staticEGLContext, context->format(), context->shareHandle()); } +#elif defined(QT_OPENGL_ES_2) + ctx = QWindowsEGLStaticContext::create(); +#elif !defined(QT_NO_OPENGL) + ctx = QOpenGLStaticContext::create(); #endif -#if !defined(QT_OPENGL_ES_2) - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { - if (d->m_staticOpenGLContext.isNull()) - d->m_staticOpenGLContext = - QSharedPointer<QOpenGLStaticContext>(QOpenGLStaticContext::create()); - QScopedPointer<QWindowsGLContext> result(new QWindowsGLContext(d->m_staticOpenGLContext, context)); - return result->isValid() ? result.take() : 0; + + q_staticOpenGLContext = ctx; + + return ctx; +} + +bool QWindowsIntegrationPrivate::ensureStaticOpenGLContext() +{ + if (m_staticOpenGLContext.isNull()) + m_staticOpenGLContext = QSharedPointer<QWindowsStaticOpenGLContext>(QWindowsStaticOpenGLContext::create()); + return !m_staticOpenGLContext.isNull(); +} + +QPlatformOpenGLContext *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +{ + qCDebug(lcQpaGl) << __FUNCTION__ << context->format(); + if (d->ensureStaticOpenGLContext()) { + QScopedPointer<QWindowsOpenGLContext> result(d->m_staticOpenGLContext->createContext(context)); + if (result->isValid()) + return result.take(); } -#endif // !QT_OPENGL_ES_2 return 0; } + +QOpenGLContext::OpenGLModuleType QWindowsIntegration::openGLModuleType() +{ +#if defined(QT_OPENGL_ES_2) + return QOpenGLContext::LibGLES; +#elif !defined(QT_OPENGL_DYNAMIC) + return QOpenGLContext::LibGL; +#else + return d->ensureStaticOpenGLContext() ? d->m_staticOpenGLContext->moduleType() : QOpenGLContext::LibGL; +#endif +} + +QWindowsStaticOpenGLContext *QWindowsIntegration::staticOpenGLContext() +{ + return q_staticOpenGLContext; +} #endif // !QT_NO_OPENGL /* Workaround for QTBUG-24205: In 'Auto', pick the FreeType engine for diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 0f417c8239..cae415ccd9 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE struct QWindowsIntegrationPrivate; struct QWindowsWindowData; class QWindowsWindow; +class QWindowsStaticOpenGLContext; class QWindowsIntegration : public QPlatformIntegration { @@ -73,28 +74,30 @@ public: QWindowsWindowData createWindowData(QWindow *window) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; #ifndef QT_NO_OPENGL - virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; + QOpenGLContext::OpenGLModuleType openGLModuleType(); + static QWindowsStaticOpenGLContext *staticOpenGLContext(); #endif - virtual QAbstractEventDispatcher *createEventDispatcher() const; + QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; void initialize() Q_DECL_OVERRIDE; #ifndef QT_NO_CLIPBOARD - virtual QPlatformClipboard *clipboard() const; + QPlatformClipboard *clipboard() const Q_DECL_OVERRIDE; # ifndef QT_NO_DRAGANDDROP - virtual QPlatformDrag *drag() const; + QPlatformDrag *drag() const Q_DECL_OVERRIDE; # endif #endif // !QT_NO_CLIPBOARD - virtual QPlatformInputContext *inputContext() const; + QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE; #ifndef QT_NO_ACCESSIBILITY - virtual QPlatformAccessibility *accessibility() const; + QPlatformAccessibility *accessibility() const Q_DECL_OVERRIDE; #endif - virtual QPlatformFontDatabase *fontDatabase() const; - virtual QStringList themeNames() const; - virtual QPlatformTheme *createPlatformTheme(const QString &name) const; + QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; + QStringList themeNames() const Q_DECL_OVERRIDE; + QPlatformTheme *createPlatformTheme(const QString &name) const Q_DECL_OVERRIDE; QPlatformServices *services() const; - virtual QVariant styleHint(StyleHint hint) const; + QVariant styleHint(StyleHint hint) const Q_DECL_OVERRIDE; - virtual Qt::KeyboardModifiers queryKeyboardModifiers() const; - virtual QList<int> possibleKeys(const QKeyEvent *e) const; + Qt::KeyboardModifiers queryKeyboardModifiers() const Q_DECL_OVERRIDE; + QList<int> possibleKeys(const QKeyEvent *e) const Q_DECL_OVERRIDE; static QWindowsIntegration *instance(); @@ -103,7 +106,7 @@ public: unsigned options() const; #if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER) - virtual QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const; + QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const Q_DECL_OVERRIDE; #endif private: diff --git a/src/plugins/platforms/windows/qwindowsinternalmimedata.h b/src/plugins/platforms/windows/qwindowsinternalmimedata.h index 0c12c662c4..08f2d09534 100644 --- a/src/plugins/platforms/windows/qwindowsinternalmimedata.h +++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.h @@ -54,9 +54,9 @@ class QDebug; // Implementation in qwindowsclipboard.cpp. class QWindowsInternalMimeData : public QInternalMimeData { public: - virtual bool hasFormat_sys(const QString &mimetype) const; - virtual QStringList formats_sys() const; - virtual QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const; + bool hasFormat_sys(const QString &mimetype) const Q_DECL_OVERRIDE; + QStringList formats_sys() const Q_DECL_OVERRIDE; + QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const Q_DECL_OVERRIDE; protected: virtual IDataObject *retrieveDataObject() const = 0; diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 6bcfe01a18..dc1de047fe 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -428,6 +428,63 @@ static const uint KeyTbl[] = { // Keyboard mapping table 0 }; +static const uint CmdTbl[] = { // Multimedia keys mapping table + // Dec | Hex | AppCommand + Qt::Key_unknown, // 0 0x00 + Qt::Key_Back, // 1 0x01 APPCOMMAND_BROWSER_BACKWARD + Qt::Key_Forward, // 2 0x02 APPCOMMAND_BROWSER_FORWARD + Qt::Key_Refresh, // 3 0x03 APPCOMMAND_BROWSER_REFRESH + Qt::Key_Stop, // 4 0x04 APPCOMMAND_BROWSER_STOP + Qt::Key_Search, // 5 0x05 APPCOMMAND_BROWSER_SEARCH + Qt::Key_Favorites, // 6 0x06 APPCOMMAND_BROWSER_FAVORITES + Qt::Key_Home, // 7 0x07 APPCOMMAND_BROWSER_HOME + Qt::Key_VolumeMute, // 8 0x08 APPCOMMAND_VOLUME_MUTE + Qt::Key_VolumeDown, // 9 0x09 APPCOMMAND_VOLUME_DOWN + Qt::Key_VolumeUp, // 10 0x0a APPCOMMAND_VOLUME_UP + Qt::Key_MediaNext, // 11 0x0b APPCOMMAND_MEDIA_NEXTTRACK + Qt::Key_MediaPrevious, // 12 0x0c APPCOMMAND_MEDIA_PREVIOUSTRACK + Qt::Key_MediaStop, // 13 0x0d APPCOMMAND_MEDIA_STOP + Qt::Key_MediaTogglePlayPause, // 14 0x0e APPCOMMAND_MEDIA_PLAYPAUSE + Qt::Key_LaunchMail, // 15 0x0f APPCOMMAND_LAUNCH_MAIL + Qt::Key_LaunchMedia, // 16 0x10 APPCOMMAND_LAUNCH_MEDIA_SELECT + Qt::Key_Launch0, // 17 0x11 APPCOMMAND_LAUNCH_APP1 + Qt::Key_Launch1, // 18 0x12 APPCOMMAND_LAUNCH_APP2 + Qt::Key_BassDown, // 19 0x13 APPCOMMAND_BASS_DOWN + Qt::Key_BassBoost, // 20 0x14 APPCOMMAND_BASS_BOOST + Qt::Key_BassUp, // 21 0x15 APPCOMMAND_BASS_UP + Qt::Key_TrebleDown, // 22 0x16 APPCOMMAND_TREBLE_DOWN + Qt::Key_TrebleUp, // 23 0x17 APPCOMMAND_TREBLE_UP + Qt::Key_MicMute, // 24 0x18 APPCOMMAND_MICROPHONE_VOLUME_MUTE + Qt::Key_MicVolumeDown, // 25 0x19 APPCOMMAND_MICROPHONE_VOLUME_DOWN + Qt::Key_MicVolumeUp, // 26 0x1a APPCOMMAND_MICROPHONE_VOLUME_UP + Qt::Key_Help, // 27 0x1b APPCOMMAND_HELP + Qt::Key_Find, // 28 0x1c APPCOMMAND_FIND + Qt::Key_New, // 29 0x1d APPCOMMAND_NEW + Qt::Key_Open, // 30 0x1e APPCOMMAND_OPEN + Qt::Key_Close, // 31 0x1f APPCOMMAND_CLOSE + Qt::Key_Save, // 32 0x20 APPCOMMAND_SAVE + Qt::Key_Print, // 33 0x21 APPCOMMAND_PRINT + Qt::Key_Undo, // 34 0x22 APPCOMMAND_UNDO + Qt::Key_Redo, // 35 0x23 APPCOMMAND_REDO + Qt::Key_Copy, // 36 0x24 APPCOMMAND_COPY + Qt::Key_Cut, // 37 0x25 APPCOMMAND_CUT + Qt::Key_Paste, // 38 0x26 APPCOMMAND_PASTE + Qt::Key_Reply, // 39 0x27 APPCOMMAND_REPLY_TO_MAIL + Qt::Key_MailForward, // 40 0x28 APPCOMMAND_FORWARD_MAIL + Qt::Key_Send, // 41 0x29 APPCOMMAND_SEND_MAIL + Qt::Key_Spell, // 42 0x2a APPCOMMAND_SPELL_CHECK + Qt::Key_unknown, // 43 0x2b APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE + Qt::Key_unknown, // 44 0x2c APPCOMMAND_MIC_ON_OFF_TOGGLE + Qt::Key_unknown, // 45 0x2d APPCOMMAND_CORRECTION_LIST + Qt::Key_MediaPlay, // 46 0x2e APPCOMMAND_MEDIA_PLAY + Qt::Key_MediaPause, // 47 0x2f APPCOMMAND_MEDIA_PAUSE + Qt::Key_MediaRecord, // 48 0x30 APPCOMMAND_MEDIA_RECORD + Qt::Key_AudioForward, // 49 0x31 APPCOMMAND_MEDIA_FAST_FORWARD + Qt::Key_AudioRewind, // 50 0x32 APPCOMMAND_MEDIA_REWIND + Qt::Key_ChannelDown, // 51 0x33 APPCOMMAND_MEDIA_CHANNEL_DOWN + Qt::Key_ChannelUp // 52 0x34 APPCOMMAND_MEDIA_CHANNEL_UP +}; + // Possible modifier states. // NOTE: The order of these states match the order in QWindowsKeyMapper::updatePossibleKeyCodes()! static const Qt::KeyboardModifiers ModsTbl[] = { @@ -747,6 +804,11 @@ bool QWindowsKeyMapper::translateKeyEvent(QWindow *widget, HWND hwnd, return true; } +#if defined(WM_APPCOMMAND) + if (msg.message == WM_APPCOMMAND) + return translateMultimediaKeyEventInternal(widget, msg); +#endif + // WM_(IME_)CHAR messages already contain the character in question so there is // no need to fiddle with our key map. In any other case add this key to the // keymap if it is not present yet. @@ -761,6 +823,29 @@ bool QWindowsKeyMapper::translateKeyEvent(QWindow *widget, HWND hwnd, return translateKeyEventInternal(widget, msg, false); } +bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, const MSG &msg) +{ +#if defined(WM_APPCOMMAND) + const int cmd = GET_APPCOMMAND_LPARAM(msg.lParam); + const int dwKeys = GET_KEYSTATE_LPARAM(msg.lParam); + int state = 0; + state |= (dwKeys & MK_SHIFT ? int(Qt::ShiftModifier) : 0); + state |= (dwKeys & MK_CONTROL ? int(Qt::ControlModifier) : 0); + + QWindow *receiver = m_keyGrabber ? m_keyGrabber : window; + + if (cmd < 0 || cmd > 52) + return false; + + const int qtKey = CmdTbl[cmd]; + sendExtendedPressRelease(receiver, qtKey, Qt::KeyboardModifier(state), 0, 0, 0); + return true; +#else + Q_UNREACHABLE(); + return false; +#endif +} + bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &msg, bool /* grab */) { const int msgType = msg.message; diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h index f7d33758a0..247a807af7 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.h +++ b/src/plugins/platforms/windows/qwindowskeymapper.h @@ -93,6 +93,7 @@ public: private: bool translateKeyEventInternal(QWindow *receiver, const MSG &msg, bool grab); + bool translateMultimediaKeyEventInternal(QWindow *receiver, const MSG &msg); void updateKeyMap(const MSG &msg); bool m_useRTLExtensions; diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index 3af2cff9a0..37f51e85bd 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -1035,17 +1035,14 @@ bool QWindowsMimeImage::canConvertToMime(const QString &mimeType, IDataObject *p bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const { int cf = getCf(formatetc); - if (mimeData->hasImage()) { - if (cf == CF_DIB) - return true; - else if (cf == CF_DIBV5) { - //support DIBV5 conversion only if the image has alpha channel - QImage image = qvariant_cast<QImage>(mimeData->imageData()); - if (!image.isNull() && image.hasAlphaChannel()) - return true; - } - } - return false; + if (!mimeData->hasImage()) + return false; + const QImage image = qvariant_cast<QImage>(mimeData->imageData()); + if (image.isNull()) + return false; + // QTBUG-11463, deny CF_DIB support for images with alpha to prevent loss of + // transparency in conversion. + return cf == CF_DIBV5 || (cf == CF_DIB && !image.hasAlphaChannel()); } bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const @@ -1442,13 +1439,13 @@ QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const \sa QWindowsMime */ -QWindowsMimeConverter::QWindowsMimeConverter() +QWindowsMimeConverter::QWindowsMimeConverter() : m_internalMimeCount(0) { } QWindowsMimeConverter::~QWindowsMimeConverter() { - qDeleteAll(m_mimes); + qDeleteAll(m_mimes.begin(), m_mimes.begin() + m_internalMimeCount); } QWindowsMime * QWindowsMimeConverter::converterToMime(const QString &mimeType, IDataObject *pDataObj) const @@ -1526,6 +1523,7 @@ void QWindowsMimeConverter::ensureInitialized() const m_mimes << new QWindowsMimeImage << new QLastResortMimes << new QWindowsMimeText << new QWindowsMimeURI << new QWindowsMimeHtml << new QBuiltInMimes; + m_internalMimeCount = m_mimes.size(); } } @@ -1552,4 +1550,10 @@ QVariant QWindowsMimeConverter::convertToMime(const QStringList &mimeTypes, return QVariant(); } +void QWindowsMimeConverter::registerMime(QWindowsMime *mime) +{ + ensureInitialized(); + m_mimes.append(mime); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h index cd0fb4d8b3..e2818422bf 100644 --- a/src/plugins/platforms/windows/qwindowsmime.h +++ b/src/plugins/platforms/windows/qwindowsmime.h @@ -89,12 +89,14 @@ public: QVariant convertToMime(const QStringList &mimeTypes, IDataObject *pDataObj, QVariant::Type preferredType, QString *format = 0) const; -private: - typedef QSharedPointer<QWindowsMime> MimePtr; + void registerMime(QWindowsMime *mime); + void unregisterMime(QWindowsMime *mime) { m_mimes.removeOne(mime); } +private: void ensureInitialized() const; mutable QList<QWindowsMime *> m_mimes; + mutable int m_internalMimeCount; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index 06c0122bbb..ce28166e4f 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -42,24 +42,45 @@ #include "qwindowsnativeinterface.h" #include "qwindowswindow.h" #include "qwindowscontext.h" - -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -# include "qwindowseglcontext.h" -# include <QtGui/QOpenGLContext> -#endif - -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) -# include "qwindowsglcontext.h" -#endif - -#if !defined(QT_NO_OPENGL) -# include <QtGui/QOpenGLFunctions> -#endif +#include "qwindowsopenglcontext.h" +#include "qwindowsintegration.h" +#include "qwindowsmime.h" #include <QtGui/QWindow> +#include <QtGui/QOpenGLContext> QT_BEGIN_NAMESPACE +enum ResourceType { + RenderingContextType, + EglContextType, + EglDisplayType, + EglConfigType, + HandleType, + GlHandleType, + GetDCType, + ReleaseDCType +}; + +static int resourceType(const QByteArray &key) +{ + static const QByteArray names[] = { // match ResourceType + "renderingcontext", + "eglcontext", + "egldisplay", + "eglconfig", + "handle", + "glhandle", + "getdc", + "releasedc" + }; + const QByteArray *end = names + sizeof(names) / sizeof(names[0]); + const QByteArray *result = std::find(names, end, key); + if (result == end) + result = std::find(names, end, key.toLower()); + return int(result - names); +} + void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window) { if (!window || !window->handle()) { @@ -67,14 +88,15 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc return 0; } QWindowsWindow *bw = static_cast<QWindowsWindow *>(window->handle()); - if (resource == "handle") + int type = resourceType(resource); + if (type == HandleType) return bw->handle(); switch (window->surfaceType()) { case QWindow::RasterSurface: case QWindow::RasterGLSurface: - if (resource == "getDC") + if (type == GetDCType) return bw->getDC(); - if (resource == "releaseDC") { + if (type == ReleaseDCType) { bw->releaseDC(); return 0; } @@ -117,6 +139,16 @@ QVariantMap QWindowsNativeInterface::windowProperties(QPlatformWindow *window) c return result; } +void *QWindowsNativeInterface::nativeResourceForIntegration(const QByteArray &resource) +{ +#ifndef QT_NO_OPENGL + if (resourceType(resource) == GlHandleType) + return QWindowsIntegration::staticOpenGLContext()->moduleHandle(); +#endif + + return 0; +} + #ifndef QT_NO_OPENGL void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { @@ -124,24 +156,19 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour qWarning("%s: '%s' requested for null context or context without handle.", __FUNCTION__, resource.constData()); return 0; } -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) { - QWindowsEGLContext *windowsEglContext = static_cast<QWindowsEGLContext *>(context->handle()); - if (resource == QByteArrayLiteral("eglDisplay")) - return windowsEglContext->eglDisplay(); - if (resource == QByteArrayLiteral("eglContext")) - return windowsEglContext->eglContext(); - if (resource == QByteArrayLiteral("eglConfig")) - return windowsEglContext->eglConfig(); - } -#endif // QT_OPENGL_ES_2 || QT_OPENGL_DYNAMIC -#if !defined(QT_OPENGL_ES_2) - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { - QWindowsGLContext *windowsContext = static_cast<QWindowsGLContext *>(context->handle()); - if (resource == QByteArrayLiteral("renderingContext")) - return windowsContext->renderingContext(); + + QWindowsOpenGLContext *glcontext = static_cast<QWindowsOpenGLContext *>(context->handle()); + switch (resourceType(resource)) { + case RenderingContextType: // Fall through. + case EglContextType: + return glcontext->nativeContext(); + case EglDisplayType: + return glcontext->nativeDisplay(); + case EglConfigType: + return glcontext->nativeConfig(); + default: + break; } -#endif // QT_OPENGL_ES_2 || QT_OPENGL_DYNAMIC qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); return 0; @@ -182,4 +209,19 @@ void QWindowsNativeInterface::setAsyncExpose(bool value) QWindowsContext::instance()->setAsyncExpose(value); } +void QWindowsNativeInterface::registerWindowsMime(void *mimeIn) +{ + QWindowsContext::instance()->mimeConverter().registerMime(reinterpret_cast<QWindowsMime *>(mimeIn)); +} + +void QWindowsNativeInterface::unregisterWindowsMime(void *mimeIn) +{ + QWindowsContext::instance()->mimeConverter().unregisterMime(reinterpret_cast<QWindowsMime *>(mimeIn)); +} + +int QWindowsNativeInterface::registerMimeType(const QString &mimeType) +{ + return QWindowsMime::registerMimeType(mimeType); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h index 20100d0f49..1afa0571a0 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.h +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h @@ -66,11 +66,13 @@ class QWindowsNativeInterface : public QPlatformNativeInterface { Q_OBJECT Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose) + public: + void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; #ifndef QT_NO_OPENGL - virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context); + void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) Q_DECL_OVERRIDE; #endif - virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); + void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE; Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate, const QString &windowName, @@ -80,13 +82,17 @@ public: Q_INVOKABLE void beep() { MessageBeep(MB_OK); } // For QApplication + Q_INVOKABLE void registerWindowsMime(void *mimeIn); + Q_INVOKABLE void unregisterWindowsMime(void *mime); + Q_INVOKABLE int registerMimeType(const QString &mimeType); + bool asyncExpose() const; void setAsyncExpose(bool value); - QVariantMap windowProperties(QPlatformWindow *window) const; - QVariant windowProperty(QPlatformWindow *window, const QString &name) const; - QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const; - void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value); + QVariantMap windowProperties(QPlatformWindow *window) const Q_DECL_OVERRIDE; + QVariant windowProperty(QPlatformWindow *window, const QString &name) const Q_DECL_OVERRIDE; + QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const Q_DECL_OVERRIDE; + void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) Q_DECL_OVERRIDE; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsopenglcontext.h b/src/plugins/platforms/windows/qwindowsopenglcontext.h new file mode 100644 index 0000000000..555af72f37 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsopenglcontext.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 QWINDOWSOPENGLCONTEXT_H +#define QWINDOWSOPENGLCONTEXT_H + +#include <QtGui/QOpenGLContext> +#include <qpa/qplatformopenglcontext.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_OPENGL + +class QWindowsOpenGLContext; + +class QWindowsStaticOpenGLContext +{ +public: + static QWindowsStaticOpenGLContext *create(); + virtual ~QWindowsStaticOpenGLContext() { } + + virtual QWindowsOpenGLContext *createContext(QOpenGLContext *context) = 0; + virtual void *moduleHandle() const = 0; + virtual QOpenGLContext::OpenGLModuleType moduleType() const = 0; + virtual bool supportsThreadedOpenGL() const { return false; } + + // If the windowing system interface needs explicitly created window surfaces (like EGL), + // reimplement these. + virtual void *createWindowSurface(void * /*nativeWindow*/, void * /*nativeConfig*/) { return 0; } + virtual void destroyWindowSurface(void * /*nativeSurface*/) { } +}; + +class QWindowsOpenGLContext : public QPlatformOpenGLContext +{ +public: + virtual ~QWindowsOpenGLContext() { } + + // Returns the native context handle (e.g. HGLRC for WGL, EGLContext for EGL). + virtual void *nativeContext() const = 0; + + // These should be implemented only for some winsys interfaces, for example EGL. + // For others, like WGL, they are not relevant. + virtual void *nativeDisplay() const { return 0; } + virtual void *nativeConfig() const { return 0; } +}; + +#endif // QT_NO_OPENGL + +QT_END_NAMESPACE + +#endif // QWINDOWSOPENGLCONTEXT_H diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp new file mode 100644 index 0000000000..9ee62e6d56 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 "qwindowsopengltester.h" +#include "qt_windows.h" +#include "qwindowscontext.h" + +QT_BEGIN_NAMESPACE + +bool QWindowsOpenGLTester::testDesktopGL() +{ + HMODULE lib = 0; + HWND wnd = 0; + HDC dc = 0; + HGLRC context = 0; + LPCTSTR className = L"qtopengltest"; + + HGLRC (WINAPI * CreateContext)(HDC dc) = 0; + BOOL (WINAPI * DeleteContext)(HGLRC context) = 0; + BOOL (WINAPI * MakeCurrent)(HDC dc, HGLRC context) = 0; + PROC (WINAPI * WGL_GetProcAddress)(LPCSTR name) = 0; + + bool result = false; + + // Test #1: Load opengl32.dll and try to resolve an OpenGL 2 function. + // This will typically fail on systems that do not have a real OpenGL driver. + lib = LoadLibraryA("opengl32.dll"); + if (lib) { + CreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(::GetProcAddress(lib, "wglCreateContext")); + if (!CreateContext) + goto cleanup; + DeleteContext = reinterpret_cast<BOOL (WINAPI *)(HGLRC)>(::GetProcAddress(lib, "wglDeleteContext")); + if (!DeleteContext) + goto cleanup; + MakeCurrent = reinterpret_cast<BOOL (WINAPI *)(HDC, HGLRC)>(::GetProcAddress(lib, "wglMakeCurrent")); + if (!MakeCurrent) + goto cleanup; + WGL_GetProcAddress = reinterpret_cast<PROC (WINAPI *)(LPCSTR)>(::GetProcAddress(lib, "wglGetProcAddress")); + if (!WGL_GetProcAddress) + goto cleanup; + + WNDCLASS wclass; + wclass.cbClsExtra = 0; + wclass.cbWndExtra = 0; + wclass.hInstance = (HINSTANCE) GetModuleHandle(0); + wclass.hIcon = 0; + wclass.hCursor = 0; + wclass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND); + wclass.lpszMenuName = 0; + wclass.lpfnWndProc = DefWindowProc; + wclass.lpszClassName = className; + wclass.style = CS_OWNDC; + if (!RegisterClass(&wclass)) + goto cleanup; + wnd = CreateWindow(className, L"qtopenglproxytest", WS_OVERLAPPED, + 0, 0, 640, 480, 0, 0, wclass.hInstance, 0); + if (!wnd) + goto cleanup; + dc = GetDC(wnd); + if (!dc) + goto cleanup; + + PIXELFORMATDESCRIPTOR pfd; + memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT; + pfd.iPixelType = PFD_TYPE_RGBA; + // Use the GDI functions. Under the hood this will call the wgl variants in opengl32.dll. + int pixelFormat = ChoosePixelFormat(dc, &pfd); + if (!pixelFormat) + goto cleanup; + if (!SetPixelFormat(dc, pixelFormat, &pfd)) + goto cleanup; + context = CreateContext(dc); + if (!context) + goto cleanup; + if (!MakeCurrent(dc, context)) + goto cleanup; + + // Now that there is finally a context current, try doing something useful. + if (WGL_GetProcAddress("glCreateShader")) { + result = true; + qCDebug(lcQpaGl, "OpenGL 2.0 entry points available"); + } else { + qCDebug(lcQpaGl, "OpenGL 2.0 entry points not found"); + } + } else { + qCDebug(lcQpaGl, "Failed to load opengl32.dll"); + } + +cleanup: + if (MakeCurrent) + MakeCurrent(0, 0); + if (context) + DeleteContext(context); + if (dc && wnd) + ReleaseDC(wnd, dc); + if (wnd) { + DestroyWindow(wnd); + UnregisterClass(className, GetModuleHandle(0)); + } + // No FreeLibrary. Some implementations, Mesa in particular, deadlock when trying to unload. + + return result; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsopengltester.h b/src/plugins/platforms/windows/qwindowsopengltester.h new file mode 100644 index 0000000000..f7cd7e3005 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsopengltester.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 <qtwindowsglobal.h> + +QT_BEGIN_NAMESPACE + +class QWindowsOpenGLTester +{ +public: + static bool testDesktopGL(); +}; + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index a6e2aabaf0..bcdb8a2352 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -68,6 +68,21 @@ static inline QDpi deviceDPI(HDC hdc) return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY)); } +#ifndef Q_OS_WINCE + +static inline QDpi monitorDPI(HMONITOR hMonitor) +{ + if (QWindowsContext::shcoredll.isValid()) { + UINT dpiX; + UINT dpiY; + if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, 0, &dpiX, &dpiY))) + return QDpi(dpiX, dpiY); + } + return QDpi(0, 0); +} + +#endif // !Q_OS_WINCE + static inline QSizeF deviceSizeMM(const QSize &pixels, const QDpi &dpi) { const qreal inchToMM = 25.4; @@ -110,7 +125,12 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL); #endif if (hdc) { +#ifndef Q_OS_WINCE + const QDpi dpi = monitorDPI(hMonitor); + data.dpi = dpi.first ? dpi : deviceDPI(hdc); +#else data.dpi = deviceDPI(hdc); +#endif data.depth = GetDeviceCaps(hdc, BITSPIXEL); data.format = data.depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; data.physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE)); @@ -387,6 +407,30 @@ static inline int indexOfMonitor(const QList<QWindowsScreenData> &screenData, return -1; } +void QWindowsScreenManager::removeScreen(int index) +{ + qCDebug(lcQpaWindows) << "Removing Monitor:" << m_screens.at(index)->data(); + QScreen *screen = m_screens.at(index)->screen(); + QScreen *primaryScreen = QGuiApplication::primaryScreen(); + // QTBUG-38650: When a screen is disconnected, Windows will automatically + // move the Window to another screen. This will trigger a geometry change + // event, but unfortunately after the screen destruction signal. To prevent + // QtGui from automatically hiding the QWindow, pretend all Windows move to + // the primary screen first (which is likely the correct, final screen). + if (screen != primaryScreen) { + unsigned movedWindowCount = 0; + foreach (QWindow *w, QGuiApplication::topLevelWindows()) { + if (w->screen() == screen && w->handle() && w->type() != Qt::Desktop) { + QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen); + ++movedWindowCount; + } + } + if (movedWindowCount) + QWindowSystemInterface::flushWindowSystemEvents(); + } + delete m_screens.takeAt(index); +} + /*! \brief Synchronizes the screen list, adds new screens, removes deleted ones and propagates resolution changes to QWindowSystemInterface. @@ -412,10 +456,8 @@ bool QWindowsScreenManager::handleScreenChanges() // temporary lock screen to avoid window recreation (QTBUG-33062). if (!lockScreen) { for (int i = m_screens.size() - 1; i >= 0; --i) { - if (indexOfMonitor(newDataList, m_screens.at(i)->data().name) == -1) { - qCDebug(lcQpaWindows) << "Removing Monitor: " << m_screens.at(i) ->data(); - delete m_screens.takeAt(i); - } // not found + if (indexOfMonitor(newDataList, m_screens.at(i)->data().name) == -1) + removeScreen(i); } // for existing screens } // not lock screen return true; diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 930814a17d..c9d8a5662c 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -88,24 +88,24 @@ public: static QWindowsScreen *screenOf(const QWindow *w = 0); - virtual QRect geometry() const { return m_data.geometry; } - virtual QRect availableGeometry() const { return m_data.availableGeometry; } - virtual int depth() const { return m_data.depth; } - virtual QImage::Format format() const { return m_data.format; } - virtual QSizeF physicalSize() const { return m_data.physicalSizeMM; } - virtual QDpi logicalDpi() const { return m_data.dpi; } - virtual qreal refreshRate() const { return m_data.refreshRateHz; } - virtual QString name() const { return m_data.name; } - virtual Qt::ScreenOrientation primaryOrientation() { return m_data.orientation; } - virtual QList<QPlatformScreen *> virtualSiblings() const; - virtual QWindow *topLevelAt(const QPoint &point) const + QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; } + QRect availableGeometry() const Q_DECL_OVERRIDE { return m_data.availableGeometry; } + int depth() const Q_DECL_OVERRIDE { return m_data.depth; } + QImage::Format format() const Q_DECL_OVERRIDE { return m_data.format; } + QSizeF physicalSize() const Q_DECL_OVERRIDE { return m_data.physicalSizeMM; } + QDpi logicalDpi() const Q_DECL_OVERRIDE { return m_data.dpi; } + qreal refreshRate() const Q_DECL_OVERRIDE { return m_data.refreshRateHz; } + QString name() const Q_DECL_OVERRIDE { return m_data.name; } + Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE { return m_data.orientation; } + QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE; + QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE { return QWindowsScreen::findTopLevelAt(point, CWP_SKIPINVISIBLE); } static QWindow *findTopLevelAt(const QPoint &point, unsigned flags); static QWindow *windowAt(const QPoint &point, unsigned flags = CWP_SKIPINVISIBLE); static QWindow *windowUnderMouse(unsigned flags = CWP_SKIPINVISIBLE); - virtual QPixmap grabWindow(WId window, int x, int y, int width, int height) const; + QPixmap grabWindow(WId window, int x, int y, int width, int height) const Q_DECL_OVERRIDE; inline void handleChanges(const QWindowsScreenData &newData); @@ -143,6 +143,8 @@ public: const WindowsScreenList &screens() const { return m_screens; } private: + void removeScreen(int index); + WindowsScreenList m_screens; int m_lastDepth; WORD m_lastHorizontalResolution; diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index 8ceab02311..d1737de907 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -465,7 +465,9 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() const double degY = atan(cos(radAzim) / tanAlt); tiltX = int(degX * (180 / M_PI)); tiltY = int(-degY * (180 / M_PI)); - rotation = packet.pkOrientation.orTwist; + rotation = 360.0 - (packet.pkOrientation.orTwist / 10.0); + if (rotation > 180.0) + rotation -= 360.0; } if (QWindowsContext::verbose > 1) { @@ -477,8 +479,9 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; } - QWindowSystemInterface::handleTabletEvent(target, packet.pkButtons, localPos, globalPosF, + QWindowSystemInterface::handleTabletEvent(target, QPointF(localPos), globalPosF, currentDevice, currentPointer, + static_cast<Qt::MouseButtons>(packet.pkButtons), pressureNew, tiltX, tiltY, tangentialPressure, rotation, z, m_devices.at(m_currentDevice).uniqueId, diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 9346621d59..4414c71bc0 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -59,17 +59,17 @@ public: static QWindowsTheme *instance() { return m_instance; } - virtual bool usePlatformNativeDialog(DialogType type) const; - virtual QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const; - virtual QVariant themeHint(ThemeHint) const; + bool usePlatformNativeDialog(DialogType type) const Q_DECL_OVERRIDE; + QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const Q_DECL_OVERRIDE; + QVariant themeHint(ThemeHint) const Q_DECL_OVERRIDE; virtual const QPalette *palette(Palette type = SystemPalette) const { return m_palettes[type]; } virtual const QFont *font(Font type = SystemFont) const { return m_fonts[type]; } - virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; - virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, - QPlatformTheme::IconOptions iconOptions = 0) const; + QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const Q_DECL_OVERRIDE; + QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions = 0) const Q_DECL_OVERRIDE; void windowsThemeChanged(QWindow *window); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 7d04c99d16..c5978c125c 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -48,15 +48,11 @@ # include "qwindowscursor.h" #endif -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -# include "qwindowseglcontext.h" -# include <QtGui/QOpenGLFunctions> -#endif - #include <QtGui/QGuiApplication> #include <QtGui/QScreen> #include <QtGui/QWindow> #include <QtGui/QRegion> +#include <QtGui/QOpenGLContext> #include <private/qsystemlibrary_p.h> #include <private/qwindow_p.h> #include <private/qguiapplication_p.h> @@ -110,6 +106,8 @@ static QByteArray debugWinExStyle(DWORD exStyle) rc += " WS_EX_CONTEXTHELP"; if (exStyle & WS_EX_LAYERED) rc += " WS_EX_LAYERED"; + if (exStyle & WS_EX_DLGMODALFRAME) + rc += " WS_EX_DLGMODALFRAME"; return rc; } @@ -183,6 +181,14 @@ QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p) static inline QRect frameGeometry(HWND hwnd, bool topLevel) { RECT rect = { 0, 0, 0, 0 }; +#ifndef Q_OS_WINCE + if (topLevel) { + WINDOWPLACEMENT windowPlacement; + GetWindowPlacement(hwnd, &windowPlacement); + if (windowPlacement.showCmd == SW_SHOWMINIMIZED) + return qrectFromRECT(windowPlacement.rcNormalPosition); + } +#endif // !Q_OS_WINCE GetWindowRect(hwnd, &rect); // Screen coordinates. const HWND parent = GetParent(hwnd); if (parent && !topLevel) { @@ -513,6 +519,10 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag } if (flags & Qt::WindowSystemMenuHint) style |= WS_SYSMENU; + else if (dialog) { + style |= WS_SYSMENU | WS_BORDER; // QTBUG-2027, dialogs without system menu. + exStyle |= WS_EX_DLGMODALFRAME; + } if (flags & Qt::WindowMinimizeButtonHint) style |= WS_MINIMIZEBOX; if (shouldShowMaximizeButton(w, flags)) @@ -861,15 +871,13 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) m_opacity(1.0), m_dropTarget(0), m_savedStyle(0), - m_format(aWindow->format()), -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - m_eglSurface(0), -#endif + m_format(aWindow->requestedFormat()), #ifdef Q_OS_WINCE m_previouslyHidden(false), #endif m_iconSmall(0), - m_iconBig(0) + m_iconBig(0), + m_surface(0) { // Clear the creation context as the window can be found in QWindowsContext's map. QWindowsContext::instance()->setWindowCreationContext(QSharedPointer<QWindowCreationContext>()); @@ -877,13 +885,14 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) const Qt::WindowType type = aWindow->type(); if (type == Qt::Desktop) return; // No further handling for Qt::Desktop +#ifndef QT_NO_OPENGL if (aWindow->surfaceType() == QWindow::OpenGLSurface) { - setFlag(OpenGLSurface); -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) + setFlag(OpenGLSurface); + else setFlag(OpenGL_ES2); -#endif } +#endif // QT_NO_OPENGL updateDropSite(); #ifndef Q_OS_WINCE @@ -947,11 +956,10 @@ void QWindowsWindow::destroyWindow() if (hasMouseCapture()) setMouseGrabEnabled(false); setDropSiteEnabled(false); -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (m_eglSurface) { - qCDebug(lcQpaGl) << __FUNCTION__ << "Freeing EGL surface " << m_eglSurface << window(); - eglDestroySurface(m_staticEglContext->display(), m_eglSurface); - m_eglSurface = 0; +#ifndef QT_NO_OPENGL + if (m_surface) { + m_data.staticOpenGLContext->destroyWindowSurface(m_surface); + m_surface = 0; } #endif #ifdef Q_OS_WINCE @@ -1383,6 +1391,11 @@ void QWindowsWindow::handleGeometryChange() && !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) { fireExpose(QRegion(m_data.geometry), true); } + if (previousGeometry.topLeft() != m_data.geometry.topLeft()) { + QPlatformScreen *newScreen = screenForGeometry(m_data.geometry); + if (newScreen != screen()) + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + } if (testFlag(SynchronousGeometryChangeEvent)) QWindowSystemInterface::flushWindowSystemEvents(); @@ -1399,15 +1412,29 @@ void QWindowsWindow::setGeometry_sys(const QRect &rect) const << margins << " to " <<rect << " new frame: " << frameGeometry; - const bool rc = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(), - frameGeometry.width(), frameGeometry.height(), true); + bool result = false; +#ifndef Q_OS_WINCE + WINDOWPLACEMENT windowPlacement; + GetWindowPlacement(m_data.hwnd, &windowPlacement); + // If the window is hidden and in maximized state or minimized, instead of moving the + // window, set the normal position of the window. + if ((windowPlacement.showCmd == SW_MAXIMIZE && !IsWindowVisible(m_data.hwnd)) + || windowPlacement.showCmd == SW_SHOWMINIMIZED) { + windowPlacement.rcNormalPosition = RECTfromQRect(frameGeometry); + windowPlacement.showCmd = windowPlacement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWMINIMIZED : SW_HIDE; + result = SetWindowPlacement(m_data.hwnd, &windowPlacement); + } else +#endif // !Q_OS_WINCE + { + result = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(), + frameGeometry.width(), frameGeometry.height(), true); + } qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << this << window() - << " \n resulting " << rc << geometry_sys(); + << " \n resulting " << result << geometry_sys(); } QRect QWindowsWindow::frameGeometry_sys() const { - // Warning: Returns bogus values when minimized. bool isRealTopLevel = window()->isTopLevel() && !m_data.embedded; return frameGeometry(m_data.hwnd, isRealTopLevel); } @@ -1573,23 +1600,9 @@ void QWindowsWindow::setWindowState(Qt::WindowState state) } } -// Return the effective screen for full screen mode in a virtual desktop. -static const QScreen *effectiveScreen(const QWindow *w) -{ - QPoint center = w->geometry().center(); - if (!w->isTopLevel()) - center = w->mapToGlobal(center); - const QScreen *screen = w->screen(); - if (!screen->geometry().contains(center)) - foreach (const QScreen *sibling, screen->virtualSiblings()) - if (sibling->geometry().contains(center)) - return sibling; - return screen; -} - bool QWindowsWindow::isFullScreen_sys() const { - return window()->isTopLevel() && geometry_sys() == effectiveScreen(window())->geometry(); + return window()->isTopLevel() && geometry_sys() == window()->screen()->geometry(); } /*! @@ -1669,7 +1682,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) setStyle(newStyle); // Use geometry of QWindow::screen() within creation or the virtual screen the // window is in (QTBUG-31166, QTBUG-30724). - const QScreen *screen = testFlag(WithinCreate) ? window()->screen() : effectiveScreen(window()); + const QScreen *screen = window()->screen(); const QRect r = screen->geometry(); const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; const bool wasSync = testFlag(SynchronousGeometryChangeEvent); @@ -1939,7 +1952,7 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const && (m_data.flags & Qt::FramelessWindowHint)) { // This block fixes QTBUG-8361: Frameless windows shouldn't cover the // taskbar when maximized - const QScreen *screen = effectiveScreen(window()); + const QScreen *screen = window()->screen(); // Documentation of MINMAXINFO states that it will only work for the primary screen if (screen && screen == QGuiApplication::primaryScreen()) { @@ -2144,23 +2157,6 @@ void QWindowsWindow::setEnabled(bool enabled) setStyle(newStyle); } -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -EGLSurface QWindowsWindow::ensureEglSurfaceHandle(const QWindowsWindow::QWindowsEGLStaticContextPtr &staticContext, EGLConfig config) -{ - if (!m_eglSurface) { - m_staticEglContext = staticContext; - m_eglSurface = eglCreateWindowSurface(staticContext->display(), config, (EGLNativeWindowType)m_data.hwnd, NULL); - if (m_eglSurface == EGL_NO_SURFACE) - qWarning("%s: Could not create the egl surface for %s/'%s' (eglCreateWindowSurface failed): error = 0x%x\n", - Q_FUNC_INFO, window()->metaObject()->className(), - qPrintable(window()->objectName()), eglGetError()); - - qCDebug(lcQpaGl) << __FUNCTION__<<"Created EGL surface "<< m_eglSurface <<window(); - } - return m_eglSurface; -} -#endif // QT_OPENGL_ES_2 - QByteArray QWindowsWindow::debugWindowFlags(Qt::WindowFlags wf) { const int iwf = int(wf); @@ -2272,4 +2268,16 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) } } +void *QWindowsWindow::surface(void *nativeConfig) +{ +#ifdef QT_NO_OPENGL + return 0; +#else + if (!m_surface) + m_surface = m_data.staticOpenGLContext->createWindowSurface(m_data.hwnd, nativeConfig); + + return m_surface; +#endif +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index cb437b76d0..19d2236688 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -47,23 +47,15 @@ # include "qplatformfunctions_wince.h" #endif #include "qwindowscursor.h" +#include "qwindowsopenglcontext.h" #include <qpa/qplatformwindow.h> -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -# include <QtCore/QSharedPointer> -# include <EGL/egl.h> -#endif - QT_BEGIN_NAMESPACE class QWindowsOleDropTarget; class QDebug; -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -class QWindowsEGLStaticContext; -#endif - struct QWindowsGeometryHint { QWindowsGeometryHint() {} @@ -121,6 +113,9 @@ struct QWindowsWindowData QMargins customMargins; // User-defined, additional frame for NCCALCSIZE HWND hwnd; bool embedded; +#ifndef QT_NO_OPENGL + QSharedPointer<QWindowsStaticOpenGLContext> staticOpenGLContext; +#endif // QT_NO_OPENGL static QWindowsWindowData create(const QWindow *w, const QWindowsWindowData ¶meters, @@ -130,10 +125,6 @@ struct QWindowsWindowData class QWindowsWindow : public QPlatformWindow { public: -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - typedef QSharedPointer<QWindowsEGLStaticContext> QWindowsEGLStaticContextPtr; -#endif - enum Flags { AutoMouseCapture = 0x1, //! Automatic mouse capture on button press. @@ -160,46 +151,46 @@ public: QWindowsWindow(QWindow *window, const QWindowsWindowData &data); ~QWindowsWindow(); - virtual QSurfaceFormat format() const { return m_format; } - virtual void setGeometry(const QRect &rect); - virtual QRect geometry() const { return m_data.geometry; } + QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } + void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; + QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; } QRect normalGeometry() const Q_DECL_OVERRIDE; - virtual void setVisible(bool visible); + void setVisible(bool visible) Q_DECL_OVERRIDE; bool isVisible() const; - virtual bool isExposed() const { return testFlag(Exposed); } - virtual bool isActive() const; - virtual bool isEmbedded(const QPlatformWindow *parentWindow) const; - virtual QPoint mapToGlobal(const QPoint &pos) const; - virtual QPoint mapFromGlobal(const QPoint &pos) const; + bool isExposed() const Q_DECL_OVERRIDE { return testFlag(Exposed); } + bool isActive() const Q_DECL_OVERRIDE; + bool isEmbedded(const QPlatformWindow *parentWindow) const Q_DECL_OVERRIDE; + QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; + QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; - virtual void setWindowFlags(Qt::WindowFlags flags); - virtual void setWindowState(Qt::WindowState state); + void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE; + void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; HWND handle() const { return m_data.hwnd; } - virtual WId winId() const { return WId(m_data.hwnd); } - virtual void setParent(const QPlatformWindow *window); + WId winId() const Q_DECL_OVERRIDE { return WId(m_data.hwnd); } + void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE; - virtual void setWindowTitle(const QString &title); - virtual void raise(); - virtual void lower(); + void setWindowTitle(const QString &title) Q_DECL_OVERRIDE; + void raise() Q_DECL_OVERRIDE; + void lower() Q_DECL_OVERRIDE; void windowEvent(QEvent *event); - virtual void propagateSizeHints(); - virtual QMargins frameMargins() const; + void propagateSizeHints() Q_DECL_OVERRIDE; + QMargins frameMargins() const Q_DECL_OVERRIDE; - virtual void setOpacity(qreal level); - virtual void setMask(const QRegion ®ion); + void setOpacity(qreal level) Q_DECL_OVERRIDE; + void setMask(const QRegion ®ion) Q_DECL_OVERRIDE; qreal opacity() const { return m_opacity; } - virtual void requestActivateWindow(); + void requestActivateWindow() Q_DECL_OVERRIDE; - virtual bool setKeyboardGrabEnabled(bool grab); - virtual bool setMouseGrabEnabled(bool grab); + bool setKeyboardGrabEnabled(bool grab) Q_DECL_OVERRIDE; + bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE; inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; } - virtual bool startSystemResize(const QPoint &pos, Qt::Corner corner); + bool startSystemResize(const QPoint &pos, Qt::Corner corner) Q_DECL_OVERRIDE; void setFrameStrutEventsEnabled(bool enabled); bool frameStrutEventsEnabled() const { return testFlag(FrameStrutEventsEnabled); } @@ -207,11 +198,6 @@ public: QMargins customMargins() const { return m_data.customMargins; } void setCustomMargins(const QMargins &m); -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - EGLSurface eglSurfaceHandle() const { return m_eglSurface;} - EGLSurface ensureEglSurfaceHandle(const QWindowsEGLStaticContextPtr &staticContext, EGLConfig config); -#endif - inline unsigned style() const { return GetWindowLongPtr(m_data.hwnd, GWL_STYLE); } void setStyle(unsigned s) const; @@ -263,6 +249,8 @@ public: bool isEnabled() const; void setWindowIcon(const QIcon &icon); + void *surface(void *nativeConfig); + #ifndef Q_OS_WINCE void setAlertState(bool enabled); bool isAlertState() const { return testFlag(AlertState); } @@ -302,15 +290,12 @@ private: unsigned m_savedStyle; QRect m_savedFrameGeometry; const QSurfaceFormat m_format; -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - EGLSurface m_eglSurface; - QSharedPointer<QWindowsEGLStaticContext> m_staticEglContext; -#endif #ifdef Q_OS_WINCE bool m_previouslyHidden; #endif HICON m_iconSmall; HICON m_iconBig; + void *m_surface; }; // Debug diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index 13799ba1ba..104d882fba 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -66,8 +66,12 @@ HEADERS += \ $$PWD/qwindowsnativeimage.h \ $$PWD/qwindowsnativeinterface.h +!wince: HEADERS += $$PWD/qwindowsopengltester.h + INCLUDEPATH += $$PWD +contains(QT_CONFIG,opengl): HEADERS += $$PWD/qwindowsopenglcontext.h + contains(QT_CONFIG, opengles2) { SOURCES += $$PWD/qwindowseglcontext.cpp HEADERS += $$PWD/qwindowseglcontext.h @@ -78,7 +82,8 @@ contains(QT_CONFIG, opengles2) { # Dynamic GL needs both WGL and EGL contains(QT_CONFIG,dynamicgl) { - SOURCES += $$PWD/qwindowseglcontext.cpp + SOURCES += $$PWD/qwindowseglcontext.cpp \ + $$PWD/qwindowsopengltester.cpp HEADERS += $$PWD/qwindowseglcontext.h } @@ -108,6 +113,10 @@ contains(QT_CONFIG,dynamicgl) { HEADERS += $$PWD/qwindowssessionmanager.h } +!wince*:!contains( DEFINES, QT_NO_IMAGEFORMAT_PNG ) { + RESOURCES += $$PWD/cursors.qrc +} + contains(QT_CONFIG, freetype) { DEFINES *= QT_NO_FONTCONFIG QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype diff --git a/src/plugins/platforms/winrt/qwinrtcursor.cpp b/src/plugins/platforms/winrt/qwinrtcursor.cpp index f09454ebc3..d2d87bde0b 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.cpp +++ b/src/plugins/platforms/winrt/qwinrtcursor.cpp @@ -40,40 +40,54 @@ ****************************************************************************/ #include "qwinrtcursor.h" +#include "qwinrtscreen.h" + +#include <QtCore/qfunctions_winrt.h> +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> #include <wrl.h> #include <windows.ui.core.h> #include <windows.foundation.h> +using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::Foundation; -QT_BEGIN_NAMESPACE +QT_USE_NAMESPACE + +class QWinRTCursorPrivate +{ +public: + ComPtr<ICoreCursorFactory> cursorFactory; +}; -QWinRTCursor::QWinRTCursor(ICoreWindow *window) : m_window(window), m_cursorFactory(nullptr) +QWinRTCursor::QWinRTCursor() + : d_ptr(new QWinRTCursorPrivate) { -#ifndef Q_OS_WINPHONE - GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Core_CoreCursor).Get(), &m_cursorFactory); -#endif + Q_D(QWinRTCursor); + + HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Core_CoreCursor).Get(), + IID_PPV_ARGS(&d->cursorFactory)); + Q_ASSERT_SUCCEEDED(hr); } QWinRTCursor::~QWinRTCursor() { - if (m_cursorFactory) - m_cursorFactory->Release(); } #ifndef QT_NO_CURSOR -void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *) +void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window) { -#ifndef Q_OS_WINPHONE - if (!m_cursorFactory) - return; + Q_D(QWinRTCursor); + + ICoreWindow *coreWindow = static_cast<QWinRTScreen *>(window->screen()->handle())->coreWindow(); CoreCursorType type; switch (windowCursor ? windowCursor->shape() : Qt::ArrowCursor) { case Qt::BlankCursor: - m_window->put_PointerCursor(nullptr); + coreWindow->put_PointerCursor(Q_NULLPTR); return; default: case Qt::OpenHandCursor: @@ -132,24 +146,20 @@ void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *) break; } - ICoreCursor *cursor; - if (SUCCEEDED(m_cursorFactory->CreateCursor(type, 0, &cursor))) - m_window->put_PointerCursor(cursor); -#else // Q_OS_WINPHONE - Q_UNUSED(windowCursor) -#endif // Q_OS_WINPHONE + ComPtr<ICoreCursor> cursor; + HRESULT hr = d->cursorFactory->CreateCursor(type, 0, &cursor); + RETURN_VOID_IF_FAILED("Failed to create native cursor."); + + hr = coreWindow->put_PointerCursor(cursor.Get()); + RETURN_VOID_IF_FAILED("Failed to set native cursor."); } #endif // QT_NO_CURSOR QPoint QWinRTCursor::pos() const { -#ifdef Q_OS_WINPHONE - return QPlatformCursor::pos(); -#else + ICoreWindow *coreWindow = + static_cast<QWinRTScreen *>(QGuiApplication::primaryScreen()->handle())->coreWindow(); Point point; - m_window->get_PointerPosition(&point); + coreWindow->get_PointerPosition(&point); return QPoint(point.X, point.Y); -#endif } - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtcursor.h b/src/plugins/platforms/winrt/qwinrtcursor.h index f7b301a98b..a08002f34c 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.h +++ b/src/plugins/platforms/winrt/qwinrtcursor.h @@ -44,34 +44,22 @@ #include <qpa/qplatformcursor.h> -namespace ABI { - namespace Windows { - namespace UI { - namespace Core { - struct ICoreWindow; - struct ICoreCursorFactory; - } - } - } -} - -QT_BEGIN_NAMESPACE +QT_USE_NAMESPACE +class QWinRTCursorPrivate; class QWinRTCursor : public QPlatformCursor { public: - explicit QWinRTCursor(ABI::Windows::UI::Core::ICoreWindow *window); + explicit QWinRTCursor(); ~QWinRTCursor(); #ifndef QT_NO_CURSOR - void changeCursor(QCursor * windowCursor, QWindow *); + void changeCursor(QCursor * windowCursor, QWindow *window); #endif QPoint pos() const; private: - ABI::Windows::UI::Core::ICoreWindow *m_window; - ABI::Windows::UI::Core::ICoreCursorFactory *m_cursorFactory; + QScopedPointer<QWinRTCursorPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTCursor) }; -QT_END_NAMESPACE - #endif // QWINRTCURSOR_H diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index b3a2cafa2e..53d52a430c 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -48,7 +48,7 @@ #include "qwinrtservices.h" #include "qwinrteglcontext.h" #include "qwinrtfontdatabase.h" -#include "qwinrtplatformtheme.h" +#include "qwinrttheme.h" #include <QtGui/QOpenGLContext> @@ -63,18 +63,6 @@ using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::UI::ViewManagement; using namespace ABI::Windows::ApplicationModel::Core; -static IUISettings *getSettings() -{ - static IUISettings *settings = 0; - if (!settings) { - if (FAILED(RoActivateInstance(Wrappers::HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_UISettings).Get(), - reinterpret_cast<IInspectable **>(&settings)))) { - qWarning("Could not activate UISettings."); - } - } - return settings; -} - QT_BEGIN_NAMESPACE QWinRTIntegration::QWinRTIntegration() @@ -82,26 +70,7 @@ QWinRTIntegration::QWinRTIntegration() , m_fontDatabase(new QWinRTFontDatabase) , m_services(new QWinRTServices) { - // Obtain the WinRT Application, view, and window - ICoreApplication *application; - if (FAILED(RoGetActivationFactory(Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), - IID_PPV_ARGS(&application)))) - qCritical("Could not attach to the application factory."); - - ICoreApplicationView *view; - if (FAILED(application->GetCurrentView(&view))) { - qCritical("Could not obtain the application view - have you started outside of WinRT?"); - return; - } - - // Get core window (will act as our screen) - ICoreWindow *window; - if (FAILED(view->get_CoreWindow(&window))) { - qCritical("Could not obtain the application window - have you started outside of WinRT?"); - return; - } - window->Activate(); - m_screen = new QWinRTScreen(window); + m_screen = new QWinRTScreen; screenAdded(m_screen); m_success = true; @@ -133,26 +102,7 @@ bool QWinRTIntegration::hasCapability(QPlatformIntegration::Capability cap) cons QVariant QWinRTIntegration::styleHint(StyleHint hint) const { - switch (hint) { - case CursorFlashTime: - if (IUISettings *settings = getSettings()) { - quint32 blinkRate; - settings->get_CaretBlinkRate(&blinkRate); - return blinkRate; - } - break; - case MouseDoubleClickInterval: - if (IUISettings *settings = getSettings()) { - quint32 doubleClickTime; - settings->get_DoubleClickTime(&doubleClickTime); - return doubleClickTime; - } - case ShowIsFullScreen: - return true; - default: - break; - } - return QPlatformIntegration::styleHint(hint); + return QWinRTTheme::styleHint(hint); } QPlatformWindow *QWinRTIntegration::createPlatformWindow(QWindow *window) const @@ -200,7 +150,7 @@ QPlatformTheme *QWinRTIntegration::createPlatformTheme(const QString & name) const { if (name == QLatin1String("winrt")) - return new QWinRTPlatformTheme(); + return new QWinRTTheme(); return 0; } diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp new file mode 100644 index 0000000000..6de90ba1ec --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 "qwinrtmessagedialoghelper.h" +#include "qwinrttheme.h" + +#include <QtCore/qfunctions_winrt.h> + +#include <windows.ui.popups.h> +#include <windows.foundation.h> +#include <windows.foundation.collections.h> +#include <wrl.h> + +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Popups; +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; + +typedef IAsyncOperationCompletedHandler<IUICommand *> DialogCompletedHandler; + +QT_BEGIN_NAMESPACE + +class CommandId : public RuntimeClass<IInspectable> +{ +public: + CommandId(QPlatformDialogHelper::StandardButton button) + : button(button) { } + QPlatformDialogHelper::StandardButton button; +}; + +class QWinRTMessageDialogHelperPrivate +{ +public: + const QWinRTTheme *theme; + bool shown; + ComPtr<IAsyncInfo> info; + QEventLoop loop; +}; + +QWinRTMessageDialogHelper::QWinRTMessageDialogHelper(const QWinRTTheme *theme) + : QPlatformMessageDialogHelper(), d_ptr(new QWinRTMessageDialogHelperPrivate) +{ + Q_D(QWinRTMessageDialogHelper); + + d->theme = theme; + d->shown = false; +} + +QWinRTMessageDialogHelper::~QWinRTMessageDialogHelper() +{ + Q_D(QWinRTMessageDialogHelper); + + if (d->shown) + hide(); +} + +void QWinRTMessageDialogHelper::exec() +{ + Q_D(QWinRTMessageDialogHelper); + + if (!d->shown) + show(Qt::Dialog, Qt::ApplicationModal, 0); + d->loop.exec(); +} + +bool QWinRTMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) +{ + Q_UNUSED(windowFlags) + Q_UNUSED(windowModality) + Q_UNUSED(parent) + Q_D(QWinRTMessageDialogHelper); + + QSharedPointer<QMessageDialogOptions> options = this->options(); + const QString informativeText = options->informativeText(); + const QString title = options->windowTitle(); + const QString text = informativeText.isEmpty() ? options->text() : (options->text() + QLatin1Char('\n') + informativeText); + + HRESULT hr; + ComPtr<IMessageDialogFactory> dialogFactory; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_MessageDialog).Get(), + IID_PPV_ARGS(&dialogFactory)); + RETURN_FALSE_IF_FAILED("Failed to create dialog factory"); + + ComPtr<IUICommandFactory> commandFactory; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_UICommand).Get(), + IID_PPV_ARGS(&commandFactory)); + RETURN_FALSE_IF_FAILED("Failed to create command factory"); + + ComPtr<IMessageDialog> dialog; + HStringReference nativeText(reinterpret_cast<LPCWSTR>(text.utf16()), text.size()); + if (!title.isEmpty()) { + HStringReference nativeTitle(reinterpret_cast<LPCWSTR>(title.utf16()), title.size()); + hr = dialogFactory->CreateWithTitle(nativeText.Get(), nativeTitle.Get(), &dialog); + RETURN_FALSE_IF_FAILED("Failed to create dialog with title"); + } else { + hr = dialogFactory->Create(nativeText.Get(), &dialog); + RETURN_FALSE_IF_FAILED("Failed to create dialog"); + } + + // Add Buttons + ComPtr<IVector<IUICommand *>> dialogCommands; + hr = dialog->get_Commands(&dialogCommands); + RETURN_FALSE_IF_FAILED("Failed to get dialog commands"); + + // If no button is specified we need to create one to get close notification + int buttons = options->standardButtons(); + if (buttons == 0) + buttons = Ok; + + for (int i = FirstButton; i < LastButton; i<<=1) { + if (!(buttons & i)) + continue; + // Add native command + const QString label = d->theme->standardButtonText(i); + HStringReference nativeLabel(reinterpret_cast<LPCWSTR>(label.utf16()), label.size()); + ComPtr<IUICommand> command; + hr = commandFactory->Create(nativeLabel.Get(), &command); + RETURN_FALSE_IF_FAILED("Failed to create message box command"); + ComPtr<IInspectable> id = Make<CommandId>(static_cast<StandardButton>(i)); + hr = command->put_Id(id.Get()); + RETURN_FALSE_IF_FAILED("Failed to set command ID"); + hr = dialogCommands->Append(command.Get()); + if (hr == E_BOUNDS) { + qErrnoWarning(hr, "The WinRT message dialog supports a maximum of three buttons"); + continue; + } + RETURN_FALSE_IF_FAILED("Failed to append message box command"); + if (i == Abort || i == Cancel || i == Close) { + quint32 size; + hr = dialogCommands->get_Size(&size); + RETURN_FALSE_IF_FAILED("Failed to get command list size"); + hr = dialog->put_CancelCommandIndex(size - 1); + RETURN_FALSE_IF_FAILED("Failed to set cancel index"); + } + } + + ComPtr<IAsyncOperation<IUICommand *>> op; + hr = dialog->ShowAsync(&op); + RETURN_FALSE_IF_FAILED("Failed to show dialog"); + hr = op->put_Completed(Callback<DialogCompletedHandler>(this, &QWinRTMessageDialogHelper::onCompleted).Get()); + RETURN_FALSE_IF_FAILED("Failed to set dialog callback"); + + d->shown = true; + hr = op.As(&d->info); + RETURN_FALSE_IF_FAILED("Failed to acquire AsyncInfo for MessageDialog"); + + return true; +} + +void QWinRTMessageDialogHelper::hide() +{ + Q_D(QWinRTMessageDialogHelper); + + if (!d->shown) + return; + + HRESULT hr = d->info->Cancel(); + if (FAILED(hr)) + qErrnoWarning(hr, "Failed to cancel dialog operation"); + + d->shown = false; +} + +HRESULT QWinRTMessageDialogHelper::onCompleted(IAsyncOperation<IUICommand *> *asyncInfo, AsyncStatus status) +{ + Q_UNUSED(status); + Q_D(QWinRTMessageDialogHelper); + + if (d->loop.isRunning()) + d->loop.exit(); + + d->shown = false; + + if (status == Canceled) { + emit reject(); + return S_OK; + } + + HRESULT hr; + ComPtr<IUICommand> command; + hr = asyncInfo->GetResults(&command); + RETURN_OK_IF_FAILED("Failed to get command"); + + ComPtr<CommandId> id; + hr = command->get_Id(&id); + RETURN_OK_IF_FAILED("Failed to get command ID"); + + ButtonRole role = buttonRole(id->button); + emit clicked(id->button, role); + return S_OK; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.h b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h index fbb21ed69c..25199e569c 100644 --- a/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.h +++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h @@ -39,11 +39,10 @@ ** ****************************************************************************/ -#ifndef QWINRTPLATFORMMESSAGEDIALOGHELPER_H -#define QWINRTPLATFORMMESSAGEDIALOGHELPER_H +#ifndef QWINRTMESSAGEDIALOGHELPER_H +#define QWINRTMESSAGEDIALOGHELPER_H #include <qpa/qplatformdialoghelper.h> -#include <QtCore/QEventLoop> #include <QtCore/qt_windows.h> namespace ABI { @@ -53,19 +52,24 @@ namespace ABI { struct IUICommand; } } + namespace Foundation { + enum class AsyncStatus; + template <typename T> struct IAsyncOperation; + } } } QT_BEGIN_NAMESPACE -struct QWinRTPlatformMessageDialogInfo; +class QWinRTTheme; -class QWinRTPlatformMessageDialogHelper : public QPlatformMessageDialogHelper +class QWinRTMessageDialogHelperPrivate; +class QWinRTMessageDialogHelper : public QPlatformMessageDialogHelper { Q_OBJECT public: - explicit QWinRTPlatformMessageDialogHelper(); - ~QWinRTPlatformMessageDialogHelper(); + explicit QWinRTMessageDialogHelper(const QWinRTTheme *theme); + ~QWinRTMessageDialogHelper(); void exec(); bool show(Qt::WindowFlags windowFlags, @@ -73,13 +77,14 @@ public: QWindow *parent); void hide(); - HRESULT onInvoked(ABI::Windows::UI::Popups::IUICommand *command); private: - QWinRTPlatformMessageDialogInfo *m_info; - QEventLoop m_loop; - bool m_shown; + HRESULT onCompleted(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::UI::Popups::IUICommand *> *asyncInfo, + ABI::Windows::Foundation::AsyncStatus status); + + QScopedPointer<QWinRTMessageDialogHelperPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTMessageDialogHelper) }; QT_END_NAMESPACE -#endif // QWINRTPLATFORMMESSAGEDIALOGHELPER_H +#endif // QWINRTMESSAGEDIALOGHELPER_H diff --git a/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.cpp deleted file mode 100644 index c2f884055d..0000000000 --- a/src/plugins/platforms/winrt/qwinrtplatformmessagedialoghelper.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 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 "qwinrtplatformmessagedialoghelper.h" - -#include <QtGui/QGuiApplication> -#include <private/qguiapplication_p.h> -#include <qpa/qplatformtheme.h> - -#include <asyncinfo.h> -#include <windows.ui.popups.h> -#include <windows.foundation.h> -#include <windows.foundation.collections.h> -#include <wrl.h> - -using namespace ABI::Windows::Foundation; -using namespace ABI::Windows::Foundation::Collections; -using namespace ABI::Windows::UI::Popups; -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; - -QT_BEGIN_NAMESPACE - -struct QWinRTPlatformMessageDialogInfo -{ - ComPtr<IAsyncInfo> info; -}; - -QWinRTPlatformMessageDialogHelper::QWinRTPlatformMessageDialogHelper() : - QPlatformMessageDialogHelper(), - m_info(new QWinRTPlatformMessageDialogInfo), - m_shown(false) -{ -} - -QWinRTPlatformMessageDialogHelper::~QWinRTPlatformMessageDialogHelper() -{ - if (m_shown) - hide(); - delete m_info; -} - -void QWinRTPlatformMessageDialogHelper::exec() -{ - if (!m_shown) - show(Qt::Dialog, Qt::ApplicationModal, 0); - m_loop.exec(); -} - -bool QWinRTPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) -{ - Q_UNUSED(windowFlags) - Q_UNUSED(windowModality) - Q_UNUSED(parent) - - QSharedPointer<QMessageDialogOptions> options = this->options(); - - const QString informativeText = options->informativeText(); - const QString title = options->windowTitle(); - const QString text = informativeText.isEmpty() ? options->text() : (options->text() + QLatin1Char('\n') + informativeText); - - - ComPtr<IMessageDialogFactory> dialogFactory; - if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_MessageDialog).Get(), &dialogFactory))) - return false; - - ComPtr<IUICommandFactory> commandFactory; - if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Popups_UICommand).Get(), &commandFactory))) - return false; - - HString nativeText; - nativeText.Set(reinterpret_cast<LPCWSTR>(text.utf16()), text.size()); - ComPtr<IMessageDialog> dialog; - - if (!title.isEmpty()) { - HString nativeTitle; - nativeTitle.Set(reinterpret_cast<LPCWSTR>(title.utf16()), title.size()); - if (FAILED(dialogFactory->CreateWithTitle(nativeText.Get(), nativeTitle.Get(), &dialog))) - return false; - } else { - if (FAILED(dialogFactory->Create(nativeText.Get(), &dialog))) - return false; - } - - // Add Buttons - ComPtr<IVector<IUICommand*> > dialogCommands; - if (FAILED(dialog->get_Commands(&dialogCommands))) - return false; - - // If no button is specified we need to create one to get close notification - int buttons = options->standardButtons(); - if (buttons == 0) - buttons = QPlatformDialogHelper::Ok; - - for (int i = QPlatformDialogHelper::FirstButton; i < QPlatformDialogHelper::LastButton; i<<=1) { - if (buttons & i) { - // Add native command - const QString label = QGuiApplicationPrivate::platformTheme()->standardButtonText(i); - - HString hLabel; - hLabel.Set(reinterpret_cast<LPCWSTR>(label.utf16()), label.size()); - - ABI::Windows::UI::Popups::IUICommand *command; - if (FAILED(commandFactory->CreateWithHandler(hLabel.Get(), - Callback<IUICommandInvokedHandler>(this, &QWinRTPlatformMessageDialogHelper::onInvoked).Get(), - &command))) - return false; - dialogCommands->Append(command); - } - } - - ComPtr<IAsyncOperation<IUICommand*> > op; - if (FAILED(dialog->ShowAsync(&op))) - return false; - - m_shown = true; - if (FAILED(op.As(&m_info->info))) { - m_shown = false; - // The dialog is shown already, so we cannot return false - qWarning("Failed to acquire AsyncInfo for MessageDialog"); - } - return true; -} - -void QWinRTPlatformMessageDialogHelper::hide() -{ - if (!m_shown) - return; - - m_info->info->Cancel(); - m_shown = false; -} - -HRESULT QWinRTPlatformMessageDialogHelper::onInvoked(ABI::Windows::UI::Popups::IUICommand *command) -{ - HString hLabel; - UINT32 labelLength; - command->get_Label(hLabel.GetAddressOf()); - PCWSTR rawString = hLabel.GetRawBuffer(&labelLength); - QString label = QString::fromWCharArray(rawString, labelLength); - int buttonId = -1; - for (int i = QPlatformDialogHelper::FirstButton; i < QPlatformDialogHelper::LastButton; i<<=1) { - if ( options()->standardButtons() & i ) { - if (QGuiApplicationPrivate::platformTheme()->standardButtonText(i) == label) { - buttonId = i; - break; - } - } - } - if (m_loop.isRunning()) - m_loop.exit(); - - m_shown = false; - - if (buttonId < 0) { - emit reject(); - return S_OK; - } - - QPlatformDialogHelper::StandardButton standardButton = static_cast<QPlatformDialogHelper::StandardButton>(buttonId); - QPlatformDialogHelper::ButtonRole role = QPlatformDialogHelper::buttonRole(standardButton); - emit clicked(standardButton, role); - return S_OK; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index f948cf9924..cbc7449591 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -51,6 +51,7 @@ #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <qpa/qwindowsysteminterface.h> #include <QtCore/qt_windows.h> +#include <QtCore/qfunctions_winrt.h> #include <wrl.h> #include <windows.system.h> @@ -93,11 +94,7 @@ typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler; typedef ITypedEventHandler<CoreWindow*, WindowSizeChangedEventArgs*> SizeChangedHandler; typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler; typedef ITypedEventHandler<CoreWindow*, AutomationProviderRequestedEventArgs*> AutomationProviderRequestedHandler; -#if _MSC_VER <=1700 -typedef IDisplayPropertiesEventHandler DisplayInformationHandler; -#else typedef ITypedEventHandler<DisplayInformation*, IInspectable*> DisplayInformationHandler; -#endif #ifdef Q_OS_WINPHONE typedef IEventHandler<BackPressedEventArgs*> BackPressedHandler; #endif @@ -419,199 +416,272 @@ static inline Qt::Key qKeyFromCode(quint32 code, int mods) return static_cast<Qt::Key>(code & 0xff); } -QWinRTScreen::QWinRTScreen(ICoreWindow *window) - : m_coreWindow(window) - , m_depth(32) - , m_format(QImage::Format_ARGB32_Premultiplied) +typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken); +uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistrationToken); +uint qHash(CoreWindowCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +typedef HRESULT (__stdcall IDisplayInformation::*DisplayCallbackRemover)(EventRegistrationToken); +uint qHash(DisplayCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#ifdef Q_OS_WINPHONE +typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken); +uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#endif + +class QWinRTScreenPrivate +{ +public: + ComPtr<ICoreApplication> application; + ComPtr<ICoreWindow> coreWindow; + ComPtr<IDisplayInformationStatics> displayInformationStatics; + ComPtr<IDisplayInformation> displayInformation; #ifdef Q_OS_WINPHONE - , m_inputContext(new QWinRTInputContext(m_coreWindow)) + ComPtr<IHardwareButtonsStatics> hardwareButtons; +#endif + + QScopedPointer<QWinRTCursor> cursor; +#ifdef Q_OS_WINPHONE + QScopedPointer<QWinRTInputContext> inputContext; #else - , m_inputContext(Make<QWinRTInputContext>(m_coreWindow).Detach()) + ComPtr<QWinRTInputContext> inputContext; +#endif + + QRectF geometry; + QSurfaceFormat surfaceFormat; + qreal dpi; + qreal devicePixelRatio; + Qt::ScreenOrientation nativeOrientation; + Qt::ScreenOrientation orientation; + QList<QWindow *> visibleWindows; +#ifndef Q_OS_WINPHONE + QHash<quint32, QPair<Qt::Key, QString>> activeKeys; +#endif + QTouchDevice *touchDevice; + QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints; + + EGLDisplay eglDisplay; + EGLSurface eglSurface; + + QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens; + QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens; + QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens; +#ifdef Q_OS_WINPHONE + QHash<HardwareButtonsCallbackRemover, EventRegistrationToken> buttonsTokens; #endif - , m_cursor(new QWinRTCursor(window)) - , m_devicePixelRatio(1.0) - , m_orientation(Qt::PrimaryOrientation) - , m_touchDevice(Q_NULLPTR) +}; + +QWinRTScreen::QWinRTScreen() + : d_ptr(new QWinRTScreenPrivate) { + Q_D(QWinRTScreen); + d->orientation = Qt::PrimaryOrientation; + d->touchDevice = Q_NULLPTR; + + // Obtain the WinRT Application, view, and window + HRESULT hr; + hr = RoGetActivationFactory(Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), + IID_PPV_ARGS(&d->application)); + Q_ASSERT_SUCCEEDED(hr); + hr = d->application->add_Suspending(Callback<SuspendHandler>(this, &QWinRTScreen::onSuspended).Get(), &d->applicationTokens[&ICoreApplication::remove_Resuming]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->application->add_Resuming(Callback<ResumeHandler>(this, &QWinRTScreen::onResume).Get(), &d->applicationTokens[&ICoreApplication::remove_Resuming]); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<ICoreApplicationView> view; + hr = d->application->GetCurrentView(&view); + Q_ASSERT_SUCCEEDED(hr); + hr = view->get_CoreWindow(&d->coreWindow); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->Activate(); + Q_ASSERT_SUCCEEDED(hr); + +#ifdef Q_OS_WINPHONE + d->inputContext.reset(new QWinRTInputContext(d->coreWindow.Get())); +#else + d->inputContext = Make<QWinRTInputContext>(d->coreWindow.Get()); +#endif + Rect rect; - window->get_Bounds(&rect); - m_geometry = QRectF(0, 0, rect.Width, rect.Height); - - m_surfaceFormat.setAlphaBufferSize(0); - m_surfaceFormat.setRedBufferSize(8); - m_surfaceFormat.setGreenBufferSize(8); - m_surfaceFormat.setBlueBufferSize(8); - - m_surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); - m_surfaceFormat.setSamples(1); - m_surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); - m_surfaceFormat.setDepthBufferSize(24); - m_surfaceFormat.setStencilBufferSize(8); - - m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (m_eglDisplay == EGL_NO_DISPLAY) + d->coreWindow->get_Bounds(&rect); + d->geometry = QRectF(0, 0, rect.Width, rect.Height); + + d->surfaceFormat.setAlphaBufferSize(0); + d->surfaceFormat.setRedBufferSize(8); + d->surfaceFormat.setGreenBufferSize(8); + d->surfaceFormat.setBlueBufferSize(8); + d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); + d->surfaceFormat.setSamples(1); + d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + d->surfaceFormat.setDepthBufferSize(24); + d->surfaceFormat.setStencilBufferSize(8); + + d->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (d->eglDisplay == EGL_NO_DISPLAY) qFatal("Qt WinRT platform plugin: failed to initialize EGL display."); - if (!eglInitialize(m_eglDisplay, NULL, NULL)) + if (!eglInitialize(d->eglDisplay, NULL, NULL)) qFatal("Qt WinRT platform plugin: failed to initialize EGL. This can happen if you haven't included the D3D compiler DLL in your application package."); // TODO: move this to Window - m_eglSurface = eglCreateWindowSurface(m_eglDisplay, q_configFromGLFormat(m_eglDisplay, m_surfaceFormat), window, NULL); - if (m_eglSurface == EGL_NO_SURFACE) + d->eglSurface = eglCreateWindowSurface(d->eglDisplay, q_configFromGLFormat(d->eglDisplay, d->surfaceFormat), d->coreWindow.Get(), NULL); + if (d->eglSurface == EGL_NO_SURFACE) qFatal("Could not create EGL surface, error 0x%X", eglGetError()); - // Event handlers mapped to QEvents - m_coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &m_tokens[QEvent::KeyPress]); - m_coreWindow->add_KeyUp(Callback<KeyHandler>(this, &QWinRTScreen::onKeyUp).Get(), &m_tokens[QEvent::KeyRelease]); - m_coreWindow->add_CharacterReceived(Callback<CharacterReceivedHandler>(this, &QWinRTScreen::onCharacterReceived).Get(), &m_tokens[QEvent::User]); - m_coreWindow->add_PointerEntered(Callback<PointerHandler>(this, &QWinRTScreen::onPointerEntered).Get(), &m_tokens[QEvent::Enter]); - m_coreWindow->add_PointerExited(Callback<PointerHandler>(this, &QWinRTScreen::onPointerExited).Get(), &m_tokens[QEvent::Leave]); - m_coreWindow->add_PointerMoved(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::MouseMove]); - m_coreWindow->add_PointerPressed(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::MouseButtonPress]); - m_coreWindow->add_PointerReleased(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::MouseButtonRelease]); - m_coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::Wheel]); - m_coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onSizeChanged).Get(), &m_tokens[QEvent::Resize]); + hr = d->coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &d->windowTokens[&ICoreWindow::remove_KeyDown]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_KeyUp(Callback<KeyHandler>(this, &QWinRTScreen::onKeyUp).Get(), &d->windowTokens[&ICoreWindow::remove_KeyUp]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_CharacterReceived(Callback<CharacterReceivedHandler>(this, &QWinRTScreen::onCharacterReceived).Get(), &d->windowTokens[&ICoreWindow::remove_CharacterReceived]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerEntered(Callback<PointerHandler>(this, &QWinRTScreen::onPointerEntered).Get(), &d->windowTokens[&ICoreWindow::remove_PointerEntered]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerExited(Callback<PointerHandler>(this, &QWinRTScreen::onPointerExited).Get(), &d->windowTokens[&ICoreWindow::remove_PointerExited]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerMoved(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerMoved]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerPressed(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerPressed]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerReleased(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerReleased]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_Activated(Callback<ActivatedHandler>(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_Closed(Callback<ClosedHandler>(this, &QWinRTScreen::onClosed).Get(), &d->windowTokens[&ICoreWindow::remove_Closed]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_VisibilityChanged(Callback<VisibilityChangedHandler>(this, &QWinRTScreen::onVisibilityChanged).Get(), &d->windowTokens[&ICoreWindow::remove_VisibilityChanged]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_AutomationProviderRequested(Callback<AutomationProviderRequestedHandler>(this, &QWinRTScreen::onAutomationProviderRequested).Get(), &d->windowTokens[&ICoreWindow::remove_AutomationProviderRequested]); + Q_ASSERT_SUCCEEDED(hr); #ifdef Q_OS_WINPHONE - ComPtr<IHardwareButtonsStatics> hardwareButtons; - if (SUCCEEDED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), &hardwareButtons))) - hardwareButtons->add_BackPressed(Callback<BackPressedHandler>(this, &QWinRTScreen::onBackButtonPressed).Get(), &m_tokens[QEvent::User]); + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), IID_PPV_ARGS(&d->hardwareButtons)); + Q_ASSERT_SUCCEEDED(hr); + hr = d->hardwareButtons->add_BackPressed(Callback<BackPressedHandler>(this, &QWinRTScreen::onBackButtonPressed).Get(), &d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]); + Q_ASSERT_SUCCEEDED(hr); #endif // Q_OS_WINPHONE - // Window event handlers - m_coreWindow->add_Activated(Callback<ActivatedHandler>(this, &QWinRTScreen::onActivated).Get(), &m_tokens[QEvent::WindowActivate]); - m_coreWindow->add_Closed(Callback<ClosedHandler>(this, &QWinRTScreen::onClosed).Get(), &m_tokens[QEvent::WindowDeactivate]); - m_coreWindow->add_VisibilityChanged(Callback<VisibilityChangedHandler>(this, &QWinRTScreen::onVisibilityChanged).Get(), &m_tokens[QEvent::Show]); - m_coreWindow->add_AutomationProviderRequested(Callback<AutomationProviderRequestedHandler>(this, &QWinRTScreen::onAutomationProviderRequested).Get(), &m_tokens[QEvent::InputMethodQuery]); - // Orientation handling -#if _MSC_VER<=1700 - HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), - &m_displayInformation); -#else - HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(), - &m_displayInformationFactory); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get display information factory."); - return; - } + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(), + IID_PPV_ARGS(&d->displayInformationStatics)); + Q_ASSERT_SUCCEEDED(hr); - hr = m_displayInformationFactory->GetForCurrentView(&m_displayInformation); -#endif - - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get display information for the current view."); - return; - } + hr = d->displayInformationStatics->GetForCurrentView(&d->displayInformation); + Q_ASSERT_SUCCEEDED(hr); // Set native orientation DisplayOrientations displayOrientation; - hr = m_displayInformation->get_NativeOrientation(&displayOrientation); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get native orientation."); - return; - } + hr = d->displayInformation->get_NativeOrientation(&displayOrientation); + Q_ASSERT_SUCCEEDED(hr); + d->nativeOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation))); - m_nativeOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation))); + hr = d->displayInformation->add_OrientationChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onOrientationChanged).Get(), &d->displayTokens[&IDisplayInformation::remove_OrientationChanged]); + Q_ASSERT_SUCCEEDED(hr); - hr = m_displayInformation->add_OrientationChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onOrientationChanged).Get(), - &m_tokens[QEvent::OrientationChange]); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to add orientation change callback."); - return; - } - -#if _MSC_VER<=1700 - hr = m_displayInformation->add_LogicalDpiChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onDpiChanged).Get(), - &m_tokens[QEvent::Type(QEvent::User + 1)]); -#else - hr = m_displayInformation->add_DpiChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onDpiChanged).Get(), - &m_tokens[QEvent::Type(QEvent::User + 1)]); -#endif - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to add logical dpi change callback."); - return; - } + hr = d->displayInformation->add_DpiChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onDpiChanged).Get(), &d->displayTokens[&IDisplayInformation::remove_DpiChanged]); + Q_ASSERT_SUCCEEDED(hr); // Set initial orientation & pixel density -#if _MSC_VER<=1700 - onOrientationChanged(Q_NULLPTR); - onDpiChanged(Q_NULLPTR); -#else onOrientationChanged(Q_NULLPTR, Q_NULLPTR); onDpiChanged(Q_NULLPTR, Q_NULLPTR); -#endif - setOrientationUpdateMask(m_nativeOrientation); + setOrientationUpdateMask(d->nativeOrientation); +} - if (SUCCEEDED(RoGetActivationFactory(Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), - IID_PPV_ARGS(&m_application)))) { - m_application->add_Suspending(Callback<SuspendHandler>(this, &QWinRTScreen::onSuspended).Get(), &m_suspendTokens[Qt::ApplicationSuspended]); - m_application->add_Resuming(Callback<ResumeHandler>(this, &QWinRTScreen::onResume).Get(), &m_suspendTokens[Qt::ApplicationHidden]); - } +QWinRTScreen::~QWinRTScreen() +{ + Q_D(QWinRTScreen); + + // Unregister callbacks + for (QHash<CoreApplicationCallbackRemover, EventRegistrationToken>::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i) + (d->application.Get()->*i.key())(i.value()); + for (QHash<CoreWindowCallbackRemover, EventRegistrationToken>::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i) + (d->coreWindow.Get()->*i.key())(i.value()); + for (QHash<DisplayCallbackRemover, EventRegistrationToken>::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i) + (d->displayInformation.Get()->*i.key())(i.value()); +#ifdef Q_OS_WINPHONE + for (QHash<HardwareButtonsCallbackRemover, EventRegistrationToken>::const_iterator i = d->buttonsTokens.begin(); i != d->buttonsTokens.end(); ++i) + (d->hardwareButtons.Get()->*i.key())(i.value()); +#endif } QRect QWinRTScreen::geometry() const { - return m_geometry.toRect(); + Q_D(const QWinRTScreen); + return d->geometry.toRect(); } int QWinRTScreen::depth() const { - return m_depth; + return 32; } QImage::Format QWinRTScreen::format() const { - return m_format; + return QImage::Format_ARGB32_Premultiplied; } QSurfaceFormat QWinRTScreen::surfaceFormat() const { - return m_surfaceFormat; + Q_D(const QWinRTScreen); + return d->surfaceFormat; } QSizeF QWinRTScreen::physicalSize() const { - return m_geometry.size() / m_dpi * qreal(25.4); + Q_D(const QWinRTScreen); + return d->geometry.size() / d->dpi * qreal(25.4); } QDpi QWinRTScreen::logicalDpi() const { - return QDpi(m_dpi, m_dpi); + Q_D(const QWinRTScreen); + return QDpi(d->dpi, d->dpi); } qreal QWinRTScreen::devicePixelRatio() const { - return m_devicePixelRatio; + Q_D(const QWinRTScreen); + return d->devicePixelRatio; } QWinRTInputContext *QWinRTScreen::inputContext() const { - return m_inputContext; + Q_D(const QWinRTScreen); +#ifdef Q_OS_WINPHONE + return d->inputContext.data(); +#else + return d->inputContext.Get(); +#endif } QPlatformCursor *QWinRTScreen::cursor() const { - return m_cursor; + Q_D(const QWinRTScreen); + if (!d->cursor) + const_cast<QWinRTScreenPrivate *>(d)->cursor.reset(new QWinRTCursor); + return d->cursor.data(); } Qt::KeyboardModifiers QWinRTScreen::keyboardModifiers() const { + Q_D(const QWinRTScreen); + Qt::KeyboardModifiers mods; CoreVirtualKeyStates mod; - m_coreWindow->GetAsyncKeyState(VirtualKey_Shift, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_Shift, &mod); if (mod == CoreVirtualKeyStates_Down) mods |= Qt::ShiftModifier; - m_coreWindow->GetAsyncKeyState(VirtualKey_Menu, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_Menu, &mod); if (mod == CoreVirtualKeyStates_Down) mods |= Qt::AltModifier; - m_coreWindow->GetAsyncKeyState(VirtualKey_Control, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_Control, &mod); if (mod == CoreVirtualKeyStates_Down) mods |= Qt::ControlModifier; - m_coreWindow->GetAsyncKeyState(VirtualKey_LeftWindows, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_LeftWindows, &mod); if (mod == CoreVirtualKeyStates_Down) { mods |= Qt::MetaModifier; } else { - m_coreWindow->GetAsyncKeyState(VirtualKey_RightWindows, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_RightWindows, &mod); if (mod == CoreVirtualKeyStates_Down) mods |= Qt::MetaModifier; } @@ -620,56 +690,63 @@ Qt::KeyboardModifiers QWinRTScreen::keyboardModifiers() const Qt::ScreenOrientation QWinRTScreen::nativeOrientation() const { - return m_nativeOrientation; + Q_D(const QWinRTScreen); + return d->nativeOrientation; } Qt::ScreenOrientation QWinRTScreen::orientation() const { - return m_orientation; + Q_D(const QWinRTScreen); + return d->orientation; } void QWinRTScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask) { -#if _MSC_VER<=1700 - m_displayInformation->put_AutoRotationPreferences(nativeOrientationsFromQt(mask)); -#else - m_displayInformationFactory->put_AutoRotationPreferences(nativeOrientationsFromQt(mask)); -#endif + Q_D(QWinRTScreen); + + HRESULT hr = d->displayInformationStatics->put_AutoRotationPreferences(nativeOrientationsFromQt(mask)); + RETURN_VOID_IF_FAILED("Failed to set display auto rotation preferences."); } ICoreWindow *QWinRTScreen::coreWindow() const { - return m_coreWindow; + Q_D(const QWinRTScreen); + return d->coreWindow.Get(); } EGLDisplay QWinRTScreen::eglDisplay() const { - return m_eglDisplay; + Q_D(const QWinRTScreen); + return d->eglDisplay; } EGLSurface QWinRTScreen::eglSurface() const { - return m_eglSurface; + Q_D(const QWinRTScreen); + return d->eglSurface; } QWindow *QWinRTScreen::topWindow() const { - return m_visibleWindows.isEmpty() ? 0 : m_visibleWindows.first(); + Q_D(const QWinRTScreen); + return d->visibleWindows.isEmpty() ? 0 : d->visibleWindows.first(); } void QWinRTScreen::addWindow(QWindow *window) { + Q_D(QWinRTScreen); if (window == topWindow()) return; - m_visibleWindows.prepend(window); + d->visibleWindows.prepend(window); QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); } void QWinRTScreen::removeWindow(QWindow *window) { + Q_D(QWinRTScreen); const bool wasTopWindow = window == topWindow(); - if (!m_visibleWindows.removeAll(window)) + if (!d->visibleWindows.removeAll(window)) return; if (wasTopWindow) QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); @@ -678,17 +755,19 @@ void QWinRTScreen::removeWindow(QWindow *window) void QWinRTScreen::raise(QWindow *window) { - m_visibleWindows.removeAll(window); + Q_D(QWinRTScreen); + d->visibleWindows.removeAll(window); addWindow(window); } void QWinRTScreen::lower(QWindow *window) { + Q_D(QWinRTScreen); const bool wasTopWindow = window == topWindow(); - if (wasTopWindow && m_visibleWindows.size() == 1) + if (wasTopWindow && d->visibleWindows.size() == 1) return; - m_visibleWindows.removeAll(window); - m_visibleWindows.append(window); + d->visibleWindows.removeAll(window); + d->visibleWindows.append(window); if (wasTopWindow) QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); @@ -696,18 +775,18 @@ void QWinRTScreen::lower(QWindow *window) void QWinRTScreen::handleExpose() { - if (m_visibleWindows.isEmpty()) + Q_D(QWinRTScreen); + if (d->visibleWindows.isEmpty()) return; - QList<QWindow *>::const_iterator it = m_visibleWindows.constBegin(); - QWindowSystemInterface::handleExposeEvent(*it, m_geometry.toRect()); - while (++it != m_visibleWindows.constEnd()) + QList<QWindow *>::const_iterator it = d->visibleWindows.constBegin(); + QWindowSystemInterface::handleExposeEvent(*it, d->geometry.toRect()); + while (++it != d->visibleWindows.constEnd()) QWindowSystemInterface::handleExposeEvent(*it, QRegion()); QWindowSystemInterface::flushWindowSystemEvents(); } -HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args) +HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args) { - Q_UNUSED(window); VirtualKey virtualKey; args->get_VirtualKey(&virtualKey); Qt::Key key = qKeyFromVirtual(virtualKey); @@ -718,14 +797,14 @@ HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *window, ABI return S_OK; } -HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args) +HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args) { - Q_UNUSED(window); Qt::KeyboardModifiers mods = keyboardModifiers(); #ifndef Q_OS_WINPHONE + Q_D(QWinRTScreen); CorePhysicalKeyStatus status; // Look for a pressed character key - if (SUCCEEDED(args->get_KeyStatus(&status)) && m_activeKeys.contains(status.ScanCode)) { - QPair<Qt::Key, QString> keyStatus = m_activeKeys.take(status.ScanCode); + if (SUCCEEDED(args->get_KeyStatus(&status)) && d->activeKeys.contains(status.ScanCode)) { + QPair<Qt::Key, QString> keyStatus = d->activeKeys.take(status.ScanCode); QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyRelease, keyStatus.first, mods, keyStatus.second); return S_OK; @@ -738,10 +817,8 @@ HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *window, ABI:: return S_OK; } -HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *window, ICharacterReceivedEventArgs *args) +HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *, ICharacterReceivedEventArgs *args) { - Q_UNUSED(window); - quint32 keyCode; args->get_KeyCode(&keyCode); // Don't generate character events for non-printables; the meta key stage is enough @@ -753,9 +830,10 @@ HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *window, ICharacterReceive QString text = QChar(keyCode); QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyPress, key, mods, text); #ifndef Q_OS_WINPHONE + Q_D(QWinRTScreen); CorePhysicalKeyStatus status; // Defer release to onKeyUp for physical keys if (SUCCEEDED(args->get_KeyStatus(&status)) && !status.IsKeyReleased) { - m_activeKeys.insert(status.ScanCode, qMakePair(key, text)); + d->activeKeys.insert(status.ScanCode, qMakePair(key, text)); return S_OK; } #endif // !Q_OS_WINPHONE @@ -763,10 +841,9 @@ HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *window, ICharacterReceive return S_OK; } -HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *window, IPointerEventArgs *args) +HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) { - Q_UNUSED(window); - IPointerPoint *pointerPoint; + ComPtr<IPointerPoint> pointerPoint; if (SUCCEEDED(args->get_CurrentPoint(&pointerPoint))) { // Assumes full-screen window Point point; @@ -774,24 +851,20 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *window, IPointerEventArgs *a QPoint pos(point.X, point.Y); QWindowSystemInterface::handleEnterEvent(topWindow(), pos, pos); - pointerPoint->Release(); } return S_OK; } -HRESULT QWinRTScreen::onPointerExited(ICoreWindow *window, IPointerEventArgs *args) +HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *) { - Q_UNUSED(window); - Q_UNUSED(args); QWindowSystemInterface::handleLeaveEvent(0); return S_OK; } -HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *args) +HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) { - Q_UNUSED(window); - - IPointerPoint *pointerPoint; + Q_D(QWinRTScreen); + ComPtr<IPointerPoint> pointerPoint; if (FAILED(args->get_CurrentPoint(&pointerPoint))) return E_INVALIDARG; @@ -812,27 +885,18 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a if (modifiers & VirtualKeyModifiers_Windows) mods |= Qt::MetaModifier; - IPointerPointProperties *properties; + ComPtr<IPointerPointProperties> properties; if (FAILED(pointerPoint->get_Properties(&properties))) return E_INVALIDARG; - PointerDeviceType pointerDeviceType; -#if defined(Q_OS_WINPHONE) && _MSC_VER <= 1700 - pointerDeviceType = PointerDeviceType_Touch; -#else ComPtr<IPointerDevice> pointerDevice; HRESULT hr = pointerPoint->get_PointerDevice(&pointerDevice); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get pointer device."); - return S_OK; - } + RETURN_OK_IF_FAILED("Failed to get pointer device."); + PointerDeviceType pointerDeviceType; hr = pointerDevice->get_PointerDeviceType(&pointerDeviceType); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get pointer device type."); - return S_OK; - } -#endif + RETURN_OK_IF_FAILED("Failed to get pointer device type."); + switch (pointerDeviceType) { case PointerDeviceType_Mouse: { qint32 delta; @@ -872,12 +936,12 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a break; } case PointerDeviceType_Touch: { - if (!m_touchDevice) { - m_touchDevice = new QTouchDevice; - m_touchDevice->setName(QStringLiteral("WinRTTouchScreen")); - m_touchDevice->setType(QTouchDevice::TouchScreen); - m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition); - QWindowSystemInterface::registerTouchDevice(m_touchDevice); + if (!d->touchDevice) { + d->touchDevice = new QTouchDevice; + d->touchDevice->setName(QStringLiteral("WinRTTouchScreen")); + d->touchDevice->setType(QTouchDevice::TouchScreen); + d->touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition); + QWindowSystemInterface::registerTouchDevice(d->touchDevice); } quint32 id; @@ -889,8 +953,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a float pressure; properties->get_Pressure(&pressure); - QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator it = m_touchPoints.find(id); - if (it != m_touchPoints.end()) { + QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator it = d->touchPoints.find(id); + if (it != d->touchPoints.end()) { boolean isPressed; #ifndef Q_OS_WINPHONE pointerPoint->get_IsInContact(&isPressed); @@ -899,20 +963,20 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a #endif it.value().state = isPressed ? Qt::TouchPointMoved : Qt::TouchPointReleased; } else { - it = m_touchPoints.insert(id, QWindowSystemInterface::TouchPoint()); + it = d->touchPoints.insert(id, QWindowSystemInterface::TouchPoint()); it.value().state = Qt::TouchPointPressed; it.value().id = id; } it.value().area = QRectF(area.X, area.Y, area.Width, area.Height); - it.value().normalPosition = QPointF(pos.x()/m_geometry.width(), pos.y()/m_geometry.height()); + it.value().normalPosition = QPointF(pos.x()/d->geometry.width(), pos.y()/d->geometry.height()); it.value().pressure = pressure; - QWindowSystemInterface::handleTouchEvent(topWindow(), m_touchDevice, m_touchPoints.values(), mods); + QWindowSystemInterface::handleTouchEvent(topWindow(), d->touchDevice, d->touchPoints.values(), mods); // Remove released points, station others - for (QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator i = m_touchPoints.begin(); i != m_touchPoints.end();) { + for (QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator i = d->touchPoints.begin(); i != d->touchPoints.end();) { if (i.value().state == Qt::TouchPointReleased) - i = m_touchPoints.erase(i); + i = d->touchPoints.erase(i); else (i++).value().state = Qt::TouchPointStationary; } @@ -950,46 +1014,42 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a } } - properties->Release(); - pointerPoint->Release(); - return S_OK; } HRESULT QWinRTScreen::onAutomationProviderRequested(ICoreWindow *, IAutomationProviderRequestedEventArgs *args) { + Q_D(const QWinRTScreen); #ifndef Q_OS_WINPHONE - args->put_AutomationProvider(m_inputContext); + args->put_AutomationProvider(d->inputContext.Get()); #else Q_UNUSED(args) #endif return S_OK; } -HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *window, IWindowSizeChangedEventArgs *args) +HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *args) { - Q_UNUSED(window); + Q_D(QWinRTScreen); Size size; - if (FAILED(args->get_Size(&size))) { - qWarning(Q_FUNC_INFO ": failed to get size"); - return S_OK; - } + HRESULT hr = args->get_Size(&size); + RETURN_OK_IF_FAILED("Failed to get window size."); // Regardless of state, all top-level windows are viewport-sized - this might change if // a more advanced compositor is written. - m_geometry.setSize(QSizeF(size.Width, size.Height)); - QWindowSystemInterface::handleScreenGeometryChange(screen(), m_geometry.toRect()); - QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), m_geometry.toRect()); + d->geometry.setSize(QSizeF(size.Width, size.Height)); + QWindowSystemInterface::handleScreenGeometryChange(screen(), d->geometry.toRect()); + QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), d->geometry.toRect()); QPlatformScreen::resizeMaximizedWindows(); handleExpose(); return S_OK; } -HRESULT QWinRTScreen::onActivated(ICoreWindow *window, IWindowActivatedEventArgs *args) +HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args) { - Q_UNUSED(window); + Q_D(QWinRTScreen); CoreWindowActivationState activationState; args->get_WindowActivationState(&activationState); @@ -999,7 +1059,7 @@ HRESULT QWinRTScreen::onActivated(ICoreWindow *window, IWindowActivatedEventArgs } // Activate topWindow - if (!m_visibleWindows.isEmpty()) { + if (!d->visibleWindows.isEmpty()) { Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated ? Qt::MouseFocusReason : Qt::ActiveWindowFocusReason; QWindowSystemInterface::handleWindowActivated(topWindow(), focusReason); @@ -1022,21 +1082,15 @@ HRESULT QWinRTScreen::onResume(IInspectable *, IInspectable *) return S_OK; } -HRESULT QWinRTScreen::onClosed(ICoreWindow *window, ICoreWindowEventArgs *args) +HRESULT QWinRTScreen::onClosed(ICoreWindow *, ICoreWindowEventArgs *) { - Q_UNUSED(window); - Q_UNUSED(args); - foreach (QWindow *w, QGuiApplication::topLevelWindows()) QWindowSystemInterface::handleCloseEvent(w); return S_OK; } -HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *window, IVisibilityChangedEventArgs *args) +HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *, IVisibilityChangedEventArgs *args) { - Q_UNUSED(window); - Q_UNUSED(args); - boolean visible; args->get_Visible(&visible); QWindowSystemInterface::handleApplicationStateChanged(visible ? Qt::ApplicationActive : Qt::ApplicationHidden); @@ -1045,60 +1099,48 @@ HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *window, IVisibilityChange return S_OK; } -#if _MSC_VER<=1700 -HRESULT QWinRTScreen::onOrientationChanged(IInspectable *) -#else HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable *) -#endif { + Q_D(QWinRTScreen); + DisplayOrientations displayOrientation; - m_displayInformation->get_CurrentOrientation(&displayOrientation); + HRESULT hr = d->displayInformation->get_CurrentOrientation(&displayOrientation); + RETURN_OK_IF_FAILED("Failed to get current orientations."); + Qt::ScreenOrientation newOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation))); - if (m_orientation != newOrientation) { - m_orientation = newOrientation; - QWindowSystemInterface::handleScreenOrientationChange(screen(), m_orientation); + if (d->orientation != newOrientation) { + d->orientation = newOrientation; + QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation); } return S_OK; } -#if _MSC_VER<=1700 -HRESULT QWinRTScreen::onDpiChanged(IInspectable *) -#else HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *) -#endif { -#if defined(Q_OS_WINPHONE) && _MSC_VER>=1800 // WP 8.1 + Q_D(QWinRTScreen); + + HRESULT hr; +#ifdef Q_OS_WINPHONE ComPtr<IDisplayInformation2> displayInformation; - HRESULT hr = m_displayInformation->QueryInterface(IID_IDisplayInformation2, &displayInformation); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to cast display information."); - return S_OK; - } - hr = displayInformation->get_RawPixelsPerViewPixel(&m_devicePixelRatio); + hr = d->displayInformation.As(&displayInformation); + RETURN_OK_IF_FAILED("Failed to cast display information."); + hr = displayInformation->get_RawPixelsPerViewPixel(&d->devicePixelRatio); #else ResolutionScale resolutionScale; - HRESULT hr = m_displayInformation->get_ResolutionScale(&resolutionScale); -#endif - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get display resolution scale."); - return S_OK; - } -#if !(defined(Q_OS_WINPHONE) && _MSC_VER>=1800) // !WP8.1 - m_devicePixelRatio = qreal(resolutionScale) / 100; + hr = d->displayInformation->get_ResolutionScale(&resolutionScale); + d->devicePixelRatio = qreal(resolutionScale) / 100; #endif + RETURN_OK_IF_FAILED("Failed to get resolution scale"); // Correct the scale factor for integer window size - m_devicePixelRatio = m_devicePixelRatio * ((m_geometry.width()/qRound(m_geometry.width()) + - m_geometry.height()/qRound(m_geometry.height())) / 2.0); + d->devicePixelRatio = d->devicePixelRatio * ((d->geometry.width()/qRound(d->geometry.width()) + + d->geometry.height()/qRound(d->geometry.height())) / 2.0); FLOAT dpi; - hr = m_displayInformation->get_LogicalDpi(&dpi); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get logical DPI."); - return S_OK; - } - m_dpi = dpi; + hr = d->displayInformation->get_LogicalDpi(&dpi); + RETURN_OK_IF_FAILED("Failed to get logical DPI."); + d->dpi = dpi; return S_OK; } @@ -1106,14 +1148,16 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *) #ifdef Q_OS_WINPHONE HRESULT QWinRTScreen::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args) { + Q_D(QWinRTScreen); + QKeyEvent backPress(QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier); QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier); backPress.setAccepted(false); backRelease.setAccepted(false); - QObject *receiver = m_visibleWindows.isEmpty() + QObject *receiver = d->visibleWindows.isEmpty() ? static_cast<QObject *>(QGuiApplication::instance()) - : static_cast<QObject *>(m_visibleWindows.first()); + : static_cast<QObject *>(d->visibleWindows.first()); // If the event is ignored, the app will suspend QGuiApplication::sendEvent(receiver, &backPress); diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index d39683a960..18745f1017 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -45,19 +45,12 @@ #include <qpa/qplatformscreen.h> #include <qpa/qwindowsysteminterface.h> -#include <QtCore/QHash> -#include <QtGui/QSurfaceFormat> #include <EGL/egl.h> -#include <EventToken.h> - namespace ABI { namespace Windows { namespace ApplicationModel { struct ISuspendingEventArgs; - namespace Core { - struct ICoreApplication; - } } namespace UI { namespace Core { @@ -71,14 +64,9 @@ namespace ABI { struct IWindowActivatedEventArgs; struct IWindowSizeChangedEventArgs; } - namespace ViewManagement { - struct IApplicationViewStatics; - } } namespace Graphics { namespace Display { - struct IDisplayPropertiesStatics; - struct IDisplayInformationStatics; struct IDisplayInformation; } } @@ -99,14 +87,14 @@ QT_BEGIN_NAMESPACE class QTouchDevice; class QWinRTEGLContext; -class QWinRTPageFlipper; class QWinRTCursor; class QWinRTInputContext; - +class QWinRTScreenPrivate; class QWinRTScreen : public QPlatformScreen { public: - explicit QWinRTScreen(ABI::Windows::UI::Core::ICoreWindow *window); + explicit QWinRTScreen(); + ~QWinRTScreen(); QRect geometry() const; int depth() const; QImage::Format format() const; @@ -135,69 +123,31 @@ public: private: void handleExpose(); - // Event handlers - QHash<QEvent::Type, EventRegistrationToken> m_tokens; - QHash<Qt::ApplicationState, EventRegistrationToken> m_suspendTokens; + HRESULT onKeyDown(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *); + HRESULT onKeyUp(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *); + HRESULT onCharacterReceived(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICharacterReceivedEventArgs *); + HRESULT onPointerEntered(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *); + HRESULT onPointerExited(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *); + HRESULT onPointerUpdated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *); + HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); - HRESULT onKeyDown(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args); - HRESULT onKeyUp(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args); - HRESULT onCharacterReceived(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::ICharacterReceivedEventArgs *args); - HRESULT onPointerEntered(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IPointerEventArgs *args); - HRESULT onPointerExited(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IPointerEventArgs *args); - HRESULT onPointerUpdated(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IPointerEventArgs *args); - HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *args); - - HRESULT onActivated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowActivatedEventArgs *args); + HRESULT onActivated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowActivatedEventArgs *); HRESULT onSuspended(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *); HRESULT onResume(IInspectable *, IInspectable *); - HRESULT onClosed(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICoreWindowEventArgs *args); - HRESULT onVisibilityChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IVisibilityChangedEventArgs *args); - HRESULT onAutomationProviderRequested(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IAutomationProviderRequestedEventArgs *args); + HRESULT onClosed(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICoreWindowEventArgs *); + HRESULT onVisibilityChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IVisibilityChangedEventArgs *); + HRESULT onAutomationProviderRequested(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IAutomationProviderRequestedEventArgs *); -#if _MSC_VER<=1700 - HRESULT onOrientationChanged(IInspectable *); - HRESULT onDpiChanged(IInspectable *); -#else HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); -#endif #ifdef Q_OS_WINPHONE HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args); #endif - ABI::Windows::UI::Core::ICoreWindow *m_coreWindow; - ABI::Windows::UI::ViewManagement::IApplicationViewStatics *m_applicationView; - ABI::Windows::ApplicationModel::Core::ICoreApplication *m_application; - - QRectF m_geometry; - QImage::Format m_format; - QSurfaceFormat m_surfaceFormat; - qreal m_dpi; - int m_depth; - QWinRTInputContext *m_inputContext; - QWinRTCursor *m_cursor; - QList<QWindow *> m_visibleWindows; - - EGLDisplay m_eglDisplay; - EGLSurface m_eglSurface; - -#if _MSC_VER<=1700 - ABI::Windows::Graphics::Display::IDisplayPropertiesStatics *m_displayInformation; -#else - ABI::Windows::Graphics::Display::IDisplayInformationStatics *m_displayInformationFactory; - ABI::Windows::Graphics::Display::IDisplayInformation *m_displayInformation; -#endif - qreal m_devicePixelRatio; - Qt::ScreenOrientation m_nativeOrientation; - Qt::ScreenOrientation m_orientation; - -#ifndef Q_OS_WINPHONE - QHash<quint32, QPair<Qt::Key, QString> > m_activeKeys; -#endif - QTouchDevice *m_touchDevice; - QHash<quint32, QWindowSystemInterface::TouchPoint> m_touchPoints; + QScopedPointer<QWinRTScreenPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTScreen) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtservices.cpp b/src/plugins/platforms/winrt/qwinrtservices.cpp index b0f9247d36..6272b46f44 100644 --- a/src/plugins/platforms/winrt/qwinrtservices.cpp +++ b/src/plugins/platforms/winrt/qwinrtservices.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -43,6 +43,7 @@ #include <QtCore/QUrl> #include <QtCore/QDir> #include <QtCore/QCoreApplication> +#include <QtCore/qfunctions_winrt.h> #include <wrl.h> #include <windows.foundation.h> @@ -56,83 +57,84 @@ using namespace ABI::Windows::System; QT_BEGIN_NAMESPACE +class QWinRTServicesPrivate +{ +public: + ComPtr<IUriRuntimeClassFactory> uriFactory; + ComPtr<IStorageFileStatics> fileFactory; + ComPtr<ILauncherStatics> launcher; +}; + QWinRTServices::QWinRTServices() + : d_ptr(new QWinRTServicesPrivate) { - GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Uri).Get(), &m_uriFactory); - GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_StorageFile).Get(), &m_fileFactory); - GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Launcher).Get(), &m_launcher); + Q_D(QWinRTServices); + + HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Uri).Get(), + IID_PPV_ARGS(&d->uriFactory)); + Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr))); + + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_StorageFile).Get(), + IID_PPV_ARGS(&d->fileFactory)); + Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr))); + + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Launcher).Get(), + IID_PPV_ARGS(&d->launcher)); + Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr))); } QWinRTServices::~QWinRTServices() { - if (m_uriFactory) - m_uriFactory->Release(); - - if (m_fileFactory) - m_fileFactory->Release(); - - if (m_launcher) - m_launcher->Release(); } bool QWinRTServices::openUrl(const QUrl &url) { - if (!(m_uriFactory && m_launcher)) - return QPlatformServices::openUrl(url); + Q_D(QWinRTServices); - IUriRuntimeClass *uri; + ComPtr<IUriRuntimeClass> uri; QString urlString = url.toString(); - // ### TODO: Replace with HStringReference when WP8.0 support is removed - HString uriString; - uriString.Set((const wchar_t*)urlString.utf16(), urlString.length()); - m_uriFactory->CreateUri(uriString.Get(), &uri); - if (!uri) - return false; - - IAsyncOperation<bool> *launchOp; - m_launcher->LaunchUriAsync(uri, &launchOp); - uri->Release(); - if (!launchOp) - return false; - - boolean result = false; - while (launchOp->GetResults(&result) == E_ILLEGAL_METHOD_CALL) - QCoreApplication::processEvents(); - launchOp->Release(); + HStringReference uriString(reinterpret_cast<LPCWSTR>(urlString.utf16()), urlString.length()); + HRESULT hr = d->uriFactory->CreateUri(uriString.Get(), &uri); + RETURN_FALSE_IF_FAILED("Failed to create URI from QUrl."); + + ComPtr<IAsyncOperation<bool>> op; + hr = d->launcher->LaunchUriAsync(uri.Get(), &op); + RETURN_FALSE_IF_FAILED("Failed to start URI launch."); + + boolean result; + hr = QWinRTFunctions::await(op, &result); + RETURN_FALSE_IF_FAILED("Failed to launch URI."); return result; } bool QWinRTServices::openDocument(const QUrl &url) { - if (!(m_fileFactory && m_launcher)) - return QPlatformServices::openDocument(url); - - const QString pathString = QDir::toNativeSeparators(url.toLocalFile()); - // ### TODO: Replace with HStringReference when WP8.0 support is removed - HString path; - path.Set((const wchar_t*)pathString.utf16(), pathString.length()); - IAsyncOperation<StorageFile*> *fileOp; - m_fileFactory->GetFileFromPathAsync(path.Get(), &fileOp); - if (!fileOp) - return false; - - IStorageFile *file = nullptr; - while (fileOp->GetResults(&file) == E_ILLEGAL_METHOD_CALL) - QCoreApplication::processEvents(); - fileOp->Release(); - if (!file) - return false; - - IAsyncOperation<bool> *launchOp; - m_launcher->LaunchFileAsync(file, &launchOp); - if (!launchOp) - return false; - - boolean result = false; - while (launchOp->GetResults(&result) == E_ILLEGAL_METHOD_CALL) - QCoreApplication::processEvents(); - launchOp->Release(); + Q_D(QWinRTServices); + + HRESULT hr; + ComPtr<IStorageFile> file; + { + const QString pathString = QDir::toNativeSeparators(url.toLocalFile()); + HStringReference path(reinterpret_cast<LPCWSTR>(pathString.utf16()), pathString.length()); + ComPtr<IAsyncOperation<StorageFile *>> op; + hr = d->fileFactory->GetFileFromPathAsync(path.Get(), &op); + RETURN_FALSE_IF_FAILED("Failed to initialize file URI."); + + hr = QWinRTFunctions::await(op, file.GetAddressOf()); + RETURN_FALSE_IF_FAILED("Failed to get file URI."); + } + + boolean result; + { + ComPtr<IAsyncOperation<bool>> op; + hr = d->launcher->LaunchFileAsync(file.Get(), &op); + RETURN_FALSE_IF_FAILED("Failed to start file launch."); + + hr = QWinRTFunctions::await(op, &result); + RETURN_FALSE_IF_FAILED("Failed to launch file."); + } return result; } diff --git a/src/plugins/platforms/winrt/qwinrtservices.h b/src/plugins/platforms/winrt/qwinrtservices.h index 9cc917030a..d3abe6f2bd 100644 --- a/src/plugins/platforms/winrt/qwinrtservices.h +++ b/src/plugins/platforms/winrt/qwinrtservices.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 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. @@ -43,23 +43,11 @@ #define QWINRTSERVICES_H #include <qpa/qplatformservices.h> +#include <QtCore/QScopedPointer> -namespace ABI { - namespace Windows { - namespace Foundation { - struct IUriRuntimeClassFactory; - } - namespace Storage { - struct IStorageFileStatics; - } - namespace System { - struct ILauncherStatics; - } - } -} - -QT_BEGIN_NAMESPACE +QT_USE_NAMESPACE +class QWinRTServicesPrivate; class QWinRTServices : public QPlatformServices { public: @@ -70,11 +58,8 @@ public: bool openDocument(const QUrl &url); private: - ABI::Windows::Foundation::IUriRuntimeClassFactory *m_uriFactory; - ABI::Windows::Storage::IStorageFileStatics *m_fileFactory; - ABI::Windows::System::ILauncherStatics *m_launcher; + QScopedPointer<QWinRTServicesPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTServices) }; -QT_END_NAMESPACE - #endif // QWINRTSERVICES_H diff --git a/src/plugins/platforms/winrt/qwinrttheme.cpp b/src/plugins/platforms/winrt/qwinrttheme.cpp new file mode 100644 index 0000000000..f9c2e21676 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrttheme.cpp @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 "qwinrttheme.h" +#include "qwinrtmessagedialoghelper.h" + +#include <QtCore/qfunctions_winrt.h> +#include <QtGui/QPalette> + +#include <wrl.h> +#include <windows.ui.h> +#include <windows.ui.viewmanagement.h> +using namespace Microsoft::WRL; +using namespace ABI::Windows::UI; +using namespace ABI::Windows::UI::ViewManagement; + +QT_BEGIN_NAMESPACE + +static IUISettings *uiSettings() +{ + static ComPtr<IUISettings> settings; + if (!settings) { + HRESULT hr; + hr = RoActivateInstance(Wrappers::HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_UISettings).Get(), + &settings); + Q_ASSERT_SUCCEEDED(hr); + } + return settings.Get(); +} + +class QWinRTThemePrivate +{ +public: + QPalette palette; +}; + +QWinRTTheme::QWinRTTheme() + : d_ptr(new QWinRTThemePrivate) +{ + Q_D(QWinRTTheme); + + HRESULT hr; + union { Color ui; QRgb qt; } color; + + hr = uiSettings()->UIElementColor(UIElementType_ActiveCaption, &color.ui); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::ToolTipBase, color.qt); + + hr = uiSettings()->UIElementColor(UIElementType_Background, &color.ui); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::AlternateBase, color.qt); + + hr = uiSettings()->UIElementColor(UIElementType_ButtonFace, &color.ui); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Button, color.qt); + d->palette.setColor(QPalette::Midlight, QColor(color.qt).lighter(110)); + d->palette.setColor(QPalette::Light, QColor(color.qt).lighter(150)); + d->palette.setColor(QPalette::Mid, QColor(color.qt).dark(130)); + d->palette.setColor(QPalette::Dark, QColor(color.qt).dark(150)); + + hr = uiSettings()->UIElementColor(UIElementType_ButtonText, &color.ui); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::ButtonText, color.qt); + d->palette.setColor(QPalette::Text, color.qt); + + hr = uiSettings()->UIElementColor(UIElementType_CaptionText, &color.ui); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::ToolTipText, color.qt); + + hr = uiSettings()->UIElementColor(UIElementType_Highlight, &color.ui); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Highlight, color.qt); + + hr = uiSettings()->UIElementColor(UIElementType_HighlightText, &color.ui); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::HighlightedText, color.qt); + + hr = uiSettings()->UIElementColor(UIElementType_Window, &color.ui); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::Window, color.qt); + d->palette.setColor(QPalette::Base, color.qt); + +#ifdef Q_OS_WINPHONE + hr = uiSettings()->UIElementColor(UIElementType_TextHigh, &color.ui); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::BrightText, color.qt); +#else + hr = uiSettings()->UIElementColor(UIElementType_Hotlight, &color.ui); + Q_ASSERT_SUCCEEDED(hr); + d->palette.setColor(QPalette::BrightText, color.qt); +#endif +} + +bool QWinRTTheme::usePlatformNativeDialog(DialogType type) const +{ + static bool useNativeDialogs = qEnvironmentVariableIsSet("QT_USE_WINRT_NATIVE_DIALOGS") + ? qgetenv("QT_USE_WINRT_NATIVE_DIALOGS").toInt() : true; + + if (type == MessageDialog) + return useNativeDialogs; + return false; +} + +QPlatformDialogHelper *QWinRTTheme::createPlatformDialogHelper(DialogType type) const +{ + switch (type) { + case MessageDialog: + return new QWinRTMessageDialogHelper(this); + default: + break; + } + return QPlatformTheme::createPlatformDialogHelper(type); +} + +QVariant QWinRTTheme::styleHint(QPlatformIntegration::StyleHint hint) +{ + HRESULT hr; + switch (hint) { + case QPlatformIntegration::CursorFlashTime: { + quint32 blinkRate; + hr = uiSettings()->get_CaretBlinkRate(&blinkRate); + RETURN_IF_FAILED("Failed to get caret blink rate", return defaultThemeHint(CursorFlashTime)); + return blinkRate; + } + case QPlatformIntegration::KeyboardInputInterval: + return defaultThemeHint(KeyboardInputInterval); + case QPlatformIntegration::MouseDoubleClickInterval: { + quint32 doubleClickTime; + hr = uiSettings()->get_DoubleClickTime(&doubleClickTime); + RETURN_IF_FAILED("Failed to get double click time", return defaultThemeHint(MouseDoubleClickInterval)); + return doubleClickTime; + } + case QPlatformIntegration::StartDragDistance: + return defaultThemeHint(StartDragDistance); + case QPlatformIntegration::StartDragTime: + return defaultThemeHint(StartDragTime); + case QPlatformIntegration::KeyboardAutoRepeatRate: + return defaultThemeHint(KeyboardAutoRepeatRate); + case QPlatformIntegration::ShowIsFullScreen: + return true; + case QPlatformIntegration::PasswordMaskDelay: + return defaultThemeHint(PasswordMaskDelay); + case QPlatformIntegration::FontSmoothingGamma: + return qreal(1.7); + case QPlatformIntegration::StartDragVelocity: + return defaultThemeHint(StartDragVelocity); + case QPlatformIntegration::UseRtlExtensions: + return false; + case QPlatformIntegration::SynthesizeMouseFromTouchEvents: + return true; + case QPlatformIntegration::PasswordMaskCharacter: + return defaultThemeHint(PasswordMaskCharacter); + case QPlatformIntegration::SetFocusOnTouchRelease: + return false; + case QPlatformIntegration::ShowIsMaximized: + return false; + case MousePressAndHoldInterval: + return defaultThemeHint(MousePressAndHoldInterval); + default: + break; + } + return QVariant(); +} + +const QPalette *QWinRTTheme::palette(Palette type) const +{ + Q_D(const QWinRTTheme); + if (type == SystemPalette) + return &d->palette; + return QPlatformTheme::palette(type); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrttheme.h b/src/plugins/platforms/winrt/qwinrttheme.h new file mode 100644 index 0000000000..f7fd07c70d --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrttheme.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 QWINRTTHEME_H +#define QWINRTTHEME_H + +#include <qpa/qplatformtheme.h> +#include <qpa/qplatformintegration.h> + +QT_BEGIN_NAMESPACE + +class QWinRTThemePrivate; +class QWinRTTheme : public QPlatformTheme +{ +public: + QWinRTTheme(); + + bool usePlatformNativeDialog(DialogType type) const; + QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const; + + const QPalette *palette(Palette type = SystemPalette) const Q_DECL_OVERRIDE; + + static QVariant styleHint(QPlatformIntegration::StyleHint hint); + +private: + QScopedPointer<QWinRTThemePrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTTheme) +}; + +QT_END_NAMESPACE + +#endif // QWINRTTHEME_H diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 349cdf11c9..427920a670 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -35,12 +35,13 @@ SOURCES = \ qwinrtfontdatabase.cpp \ qwinrtinputcontext.cpp \ qwinrtintegration.cpp \ - qwinrtplatformmessagedialoghelper.cpp \ - qwinrtplatformtheme.cpp \ + qwinrtmessagedialoghelper.cpp \ qwinrtscreen.cpp \ qwinrtservices.cpp \ + qwinrttheme.cpp \ qwinrtwindow.cpp + HEADERS = \ qwinrtbackingstore.h \ qwinrtcursor.h \ @@ -49,12 +50,13 @@ HEADERS = \ qwinrtfontdatabase.h \ qwinrtinputcontext.h \ qwinrtintegration.h \ - qwinrtplatformmessagedialoghelper.h \ - qwinrtplatformtheme.h \ + qwinrtmessagedialoghelper.h \ qwinrtscreen.h \ qwinrtservices.h \ + qwinrttheme.h \ qwinrtwindow.h + BLIT_INPUT = $$PWD/blit.hlsl fxc_blitps.commands = fxc.exe /nologo /T ps_4_0_level_9_1 /E blitps /Vn q_blitps /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} fxc_blitps.output = $$OUT_PWD/blitps.h diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index 9a56455940..3ce0041aeb 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -54,6 +54,7 @@ #include "qglxintegration.h" #include <QtPlatformSupport/private/qglxconvenience_p.h> +#include <QtPlatformHeaders/QGLXNativeContext> #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) #include <dlfcn.h> @@ -83,31 +84,32 @@ typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXC #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 #endif -static Window createDummyWindow(QXcbScreen *screen, XVisualInfo *visualInfo) +static Window createDummyWindow(Display *dpy, XVisualInfo *visualInfo, int screenNumber, Window rootWin) { - Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(screen), screen->root(), visualInfo->visual, AllocNone); + Colormap cmap = XCreateColormap(dpy, rootWin, visualInfo->visual, AllocNone); XSetWindowAttributes a; - a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(screen), screen->screenNumber()); - a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(screen), screen->screenNumber()); + a.background_pixel = WhitePixel(dpy, screenNumber); + a.border_pixel = BlackPixel(dpy, screenNumber); a.colormap = cmap; + a.override_redirect = true; - Window window = XCreateWindow(DISPLAY_FROM_XCB(screen), screen->root(), + Window window = XCreateWindow(dpy, rootWin, 0, 0, 100, 100, 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWBackPixel|CWBorderPixel|CWColormap, &a); + CWBackPixel|CWBorderPixel|CWColormap|CWOverrideRedirect, &a); #ifndef QT_NO_DEBUG - XStoreName(DISPLAY_FROM_XCB(screen), window, "Qt GLX dummy window"); + XStoreName(dpy, window, "Qt GLX dummy window"); #endif - XFreeColormap(DISPLAY_FROM_XCB(screen), cmap); + XFreeColormap(dpy, cmap); return window; } -static Window createDummyWindow(QXcbScreen *screen, GLXFBConfig config) +static Window createDummyWindow(Display *dpy, GLXFBConfig config, int screenNumber, Window rootWin) { - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(DISPLAY_FROM_XCB(screen), config); + XVisualInfo *visualInfo = glXGetVisualFromFBConfig(dpy, config); if (!visualInfo) qFatal("Could not initialize GLX"); - Window window = createDummyWindow(screen, visualInfo); + Window window = createDummyWindow(dpy, visualInfo, screenNumber, rootWin); XFree(visualInfo); return window; } @@ -160,14 +162,25 @@ static void updateFormatFromContext(QSurfaceFormat &format) } } -QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share) +QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share, + const QVariant &nativeHandle) : QPlatformOpenGLContext() , m_screen(screen) + , m_config(0) , m_context(0) , m_shareContext(0) , m_format(format) , m_isPBufferCurrent(false) , m_swapInterval(-1) + , m_ownsContext(nativeHandle.isNull()) +{ + if (nativeHandle.isNull()) + init(screen, share); + else + init(screen, share, nativeHandle); +} + +void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share) { if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType) m_format.setRenderableType(QSurfaceFormat::OpenGL); @@ -178,6 +191,7 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat m_shareContext = static_cast<const QGLXContext*>(share)->glxContext(); GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen),screen->screenNumber(),m_format); + m_config = config; XVisualInfo *visualInfo = 0; Window window = 0; // Temporary window used to query OpenGL context @@ -195,7 +209,7 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat && (m_format.renderableType() != QSurfaceFormat::OpenGLES || (supportsProfiles && glxExt.contains("GLX_EXT_create_context_es2_profile")))) { // Try to create an OpenGL context for each known OpenGL version in descending // order from the requested version. - const int requestedVersion = format.majorVersion() * 10 + qMin(format.minorVersion(), 9); + const int requestedVersion = m_format.majorVersion() * 10 + qMin(m_format.minorVersion(), 9); QVector<int> glVersions; if (m_format.renderableType() == QSurfaceFormat::OpenGL) { @@ -282,10 +296,10 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat // Get the basic surface format details if (m_context) - qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(screen), config, m_context); + qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(screen), config); // Create a temporary window so that we can make the new context current - window = createDummyWindow(screen, config); + window = createDummyWindow(DISPLAY_FROM_XCB(screen), config, screen->screenNumber(), screen->root()); } else { // requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out if (m_format.renderableType() == QSurfaceFormat::OpenGLES) @@ -303,7 +317,7 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat } // Create a temporary window so that we can make the new context current - window = createDummyWindow(screen, visualInfo); + window = createDummyWindow(DISPLAY_FROM_XCB(screen), visualInfo, screen->screenNumber(), screen->root()); XFree(visualInfo); } @@ -320,9 +334,125 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat XDestroyWindow(DISPLAY_FROM_XCB(screen), window); } +void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle) +{ + if (!nativeHandle.canConvert<QGLXNativeContext>()) { + qWarning("QGLXContext: Requires a QGLXNativeContext"); + return; + } + QGLXNativeContext handle = nativeHandle.value<QGLXNativeContext>(); + GLXContext context = handle.context(); + if (!context) { + qWarning("QGLXContext: No GLXContext given"); + return; + } + + // Use the provided Display, if available. If not, use our own. It may still work. + Display *dpy = handle.display(); + if (!dpy) + dpy = DISPLAY_FROM_XCB(screen); + + // Legacy contexts created using glXCreateContext are created using a visual + // and the FBConfig cannot be queried. The only way to adapt these contexts + // is to figure out the visual id. + XVisualInfo *vinfo = 0; + // If the VisualID is provided use it. + VisualID vid = handle.visualId(); + if (!vid) { + // In the absence of the VisualID figure it out from the window. + Window wnd = handle.window(); + if (wnd) { + XWindowAttributes attrs; + XGetWindowAttributes(dpy, wnd, &attrs); + vid = XVisualIDFromVisual(attrs.visual); + } + } + if (vid) { + XVisualInfo v; + v.screen = screen->screenNumber(); + v.visualid = vid; + int n = 0; + vinfo = XGetVisualInfo(dpy, VisualScreenMask | VisualIDMask, &v, &n); + if (n < 1) { + XFree(vinfo); + vinfo = 0; + } + } + + // For contexts created with an FBConfig using the modern functions providing the + // visual or window is not mandatory. Just query the config from the context. + GLXFBConfig config = 0; + if (!vinfo) { + int configId = 0; + if (glXQueryContext(dpy, context, GLX_FBCONFIG_ID, &configId) != Success) { + qWarning("QGLXContext: Failed to query config from the provided context"); + return; + } + + GLXFBConfig *configs; + int numConfigs = 0; + static const int attribs[] = { GLX_FBCONFIG_ID, configId, None }; + configs = glXChooseFBConfig(dpy, screen->screenNumber(), attribs, &numConfigs); + if (!configs || numConfigs < 1) { + qWarning("QGLXContext: Failed to find config"); + return; + } + if (configs && numConfigs > 1) // this is suspicious so warn but let it continue + qWarning("QGLXContext: Multiple configs for FBConfig ID %d", configId); + + config = configs[0]; + // Store the config. + m_config = config; + } + + Q_ASSERT(vinfo || config); + + int screenNumber = DefaultScreen(dpy); + Window window; + if (vinfo) + window = createDummyWindow(dpy, vinfo, screenNumber, RootWindow(dpy, screenNumber)); + else + window = createDummyWindow(dpy, config, screenNumber, RootWindow(dpy, screenNumber)); + if (!window) { + qWarning("QGLXContext: Failed to create dummy window"); + return; + } + + // Update OpenGL version and buffer sizes in our format. + if (!glXMakeCurrent(dpy, window, context)) { + qWarning("QGLXContext: Failed to make provided context current"); + return; + } + m_format = QSurfaceFormat(); + m_format.setRenderableType(QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL + ? QSurfaceFormat::OpenGL : QSurfaceFormat::OpenGLES); + updateFormatFromContext(m_format); + if (vinfo) + qglx_surfaceFormatFromVisualInfo(&m_format, dpy, vinfo); + else + qglx_surfaceFormatFromGLXFBConfig(&m_format, dpy, config); + glXMakeCurrent(dpy, 0, 0); + XDestroyWindow(dpy, window); + + if (vinfo) + XFree(vinfo); + + // Success. Store the context. From this point on isValid() is true. + m_context = context; + + if (share) + m_shareContext = static_cast<const QGLXContext*>(share)->glxContext(); +} + QGLXContext::~QGLXContext() { - glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context); + if (m_ownsContext) + glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context); +} + +QVariant QGLXContext::nativeHandle() const +{ + return QVariant::fromValue<QGLXNativeContext>(QGLXNativeContext(m_context)); } bool QGLXContext::makeCurrent(QPlatformSurface *surface) @@ -393,11 +523,11 @@ void QGLXContext::swapBuffers(QPlatformSurface *surface) if (surface->surface()->surfaceClass() == QSurface::Window) { QXcbWindow *platformWindow = static_cast<QXcbWindow *>(surface); - // OpenGL context might be bound to a non-gui thread - // use QueuedConnection to sync the window from the platformWindow's thread - // as QXcbWindow is no QObject, a wrapper slot in QXcbConnection is used. + // OpenGL context might be bound to a non-gui thread use QueuedConnection to sync + // the window from the platformWindow's thread as QXcbWindow is no QObject, an + // event is sent to QXcbConnection. (this is faster than a metacall) if (platformWindow->needsSync()) - QMetaObject::invokeMethod(m_screen->connection(), "syncWindow", Qt::QueuedConnection, Q_ARG(QXcbWindow*, platformWindow)); + platformWindow->postSyncWindowRequest(); } } diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h index 00bba94ab3..abe3216ad7 100644 --- a/src/plugins/platforms/xcb/qglxintegration.h +++ b/src/plugins/platforms/xcb/qglxintegration.h @@ -58,7 +58,8 @@ QT_BEGIN_NAMESPACE class QGLXContext : public QPlatformOpenGLContext { public: - QGLXContext(QXcbScreen *xd, const QSurfaceFormat &format, QPlatformOpenGLContext *share); + QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share, + const QVariant &nativeHandle); ~QGLXContext(); bool makeCurrent(QPlatformSurface *surface); @@ -71,17 +72,25 @@ public: bool isValid() const; GLXContext glxContext() const { return m_context; } + GLXFBConfig glxConfig() const { return m_config; } + + QVariant nativeHandle() const; static bool supportsThreading(); static void queryDummyContext(); private: + void init(QXcbScreen *screen, QPlatformOpenGLContext *share); + void init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle); + QXcbScreen *m_screen; + GLXFBConfig m_config; GLXContext m_context; GLXContext m_shareContext; QSurfaceFormat m_format; bool m_isPBufferCurrent; int m_swapInterval; + bool m_ownsContext; static bool m_queriedDummyContext; static bool m_supportsThreading; }; diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index e7f8510706..3b30274f25 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -135,9 +135,10 @@ protected: (void)formats(); // trigger update of format list - QList<xcb_atom_t> atoms; + QVector<xcb_atom_t> atoms; xcb_atom_t *targets = (xcb_atom_t *) format_atoms.data(); int size = format_atoms.size() / sizeof(xcb_atom_t); + atoms.reserve(size); for (int i = 0; i < size; ++i) atoms.append(targets[i]); @@ -524,7 +525,7 @@ xcb_atom_t QXcbClipboard::sendTargetsSelection(QMimeData *d, xcb_window_t window QVector<xcb_atom_t> types; QStringList formats = QInternalMimeData::formatsHelper(d); for (int i = 0; i < formats.size(); ++i) { - QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), formats.at(i)); + QVector<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), formats.at(i)); for (int j = 0; j < atoms.size(); ++j) { if (!types.contains(atoms.at(j))) types.append(atoms.at(j)); diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 7f23c84cb9..a2ce392151 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -1842,9 +1842,26 @@ QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() return m_systemTrayTracker; } -void QXcbConnection::syncWindow(QXcbWindow *window) +bool QXcbConnection::event(QEvent *e) { - window->updateSyncRequestCounter(); + if (e->type() == QEvent::User + 1) { + QXcbSyncWindowRequest *ev = static_cast<QXcbSyncWindowRequest *>(e); + QXcbWindow *w = ev->window(); + if (w) { + w->updateSyncRequestCounter(); + ev->invalidate(); + } + return true; + } + return QObject::event(e); +} + +void QXcbSyncWindowRequest::invalidate() +{ + if (m_window) { + m_window->clearSyncWindowRequest(); + m_window = 0; + } } QXcbConnectionGrabber::QXcbConnectionGrabber(QXcbConnection *connection) diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 60a4efff4e..9e9865a2e9 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -355,6 +355,18 @@ public: typedef QHash<xcb_window_t, QXcbWindowEventListener *> WindowMapper; +class QXcbSyncWindowRequest : public QEvent +{ +public: + QXcbSyncWindowRequest(QXcbWindow *w) : QEvent(QEvent::Type(QEvent::User + 1)), m_window(w) { } + + QXcbWindow *window() const { return m_window; } + void invalidate(); + +private: + QXcbWindow *m_window; +}; + class QAbstractEventDispatcher; class QXcbConnection : public QObject { @@ -452,6 +464,7 @@ public: void setFocusWindow(QXcbWindow *); QByteArray startupId() const { return m_startupId; } + void setStartupId(const QByteArray &nextId) { m_startupId = nextId; } void clearStartupId() { m_startupId.clear(); } void grabServer(); @@ -467,8 +480,10 @@ public: QXcbEventReader *eventReader() const { return m_reader; } +protected: + bool event(QEvent *e) Q_DECL_OVERRIDE; + public slots: - void syncWindow(QXcbWindow *window); void flush() { xcb_flush(m_connection); } private slots: @@ -508,11 +523,11 @@ private: #ifndef QT_NO_TABLETEVENT struct TabletData { TabletData() : deviceId(0), pointerType(QTabletEvent::UnknownPointer), - tool(QTabletEvent::Stylus), down(false), serialId(0), inProximity(false) { } + tool(QTabletEvent::Stylus), buttons(0), serialId(0), inProximity(false) { } int deviceId; QTabletEvent::PointerType pointerType; QTabletEvent::TabletDevice tool; - bool down; + Qt::MouseButtons buttons; qint64 serialId; bool inProximity; struct ValuatorClassInfo { diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index e21db89a20..512e574859 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -685,6 +685,19 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin #endif // XCB_USE_XINPUT21 } +static Qt::MouseButton xiToQtMouseButton(uint32_t b) { + switch (b) { + case 1: return Qt::LeftButton; + case 2: return Qt::MiddleButton; + case 3: return Qt::RightButton; + // 4-7 are for scrolling + default: break; + } + if (b >= 8 && b <= Qt::MaxMouseButton) + return static_cast<Qt::MouseButton>(Qt::BackButton << (b - 8)); + return Qt::NoButton; +} + static QTabletEvent::TabletDevice toolIdToTabletDevice(quint32 toolId) { // keep in sync with wacom_intuos_inout() in Linux kernel driver wacom_wac.c switch (toolId) { @@ -725,24 +738,22 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData) Display *xDisplay = static_cast<Display *>(m_xlib_display); xXIGenericDeviceEvent *xiEvent = static_cast<xXIGenericDeviceEvent *>(event); switch (xiEvent->evtype) { - case XI_ButtonPress: // stylus down - if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) { // ignore the physical buttons on the stylus - tabletData->down = true; - xi2ReportTabletEvent(*tabletData, xiEvent); - } else - handled = false; + case XI_ButtonPress: { + Qt::MouseButton b = xiToQtMouseButton(reinterpret_cast<xXIDeviceEvent *>(event)->detail); + tabletData->buttons |= b; + xi2ReportTabletEvent(*tabletData, xiEvent); break; - case XI_ButtonRelease: // stylus up - if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) { - tabletData->down = false; - xi2ReportTabletEvent(*tabletData, xiEvent); - } else - handled = false; + } + case XI_ButtonRelease: { + Qt::MouseButton b = xiToQtMouseButton(reinterpret_cast<xXIDeviceEvent *>(event)->detail); + tabletData->buttons ^= b; + xi2ReportTabletEvent(*tabletData, xiEvent); break; + } case XI_Motion: - // Report TabletMove only when the stylus is touching the tablet. - // No possibility to report proximity motion (no suitable Qt event exists yet). - if (tabletData->down) + // Report TabletMove only when the stylus is touching the tablet or any button is pressed. + // TODO: report proximity (hover) motion (no suitable Qt event exists yet). + if (tabletData->buttons != Qt::NoButton) xi2ReportTabletEvent(*tabletData, xiEvent); break; case XI_PropertyEvent: { @@ -862,15 +873,16 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event) } if (Q_UNLIKELY(debug_xinput)) - qDebug("XI2 event on tablet %d with tool %d type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f pressure %4.2lf tilt %d, %d rotation %6.2lf", - ev->deviceid, tabletData.tool, ev->type, ev->sequenceNumber, ev->detail, + qDebug("XI2 event on tablet %d with tool %d type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf", + ev->deviceid, tabletData.tool, ev->evtype, ev->sequenceNumber, ev->detail, fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y), fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y), - pressure, xTilt, yTilt, rotation); + (int)tabletData.buttons, pressure, xTilt, yTilt, rotation); - QWindowSystemInterface::handleTabletEvent(window, tabletData.down, local, global, + QWindowSystemInterface::handleTabletEvent(window, local, global, tabletData.tool, tabletData.pointerType, - pressure, xTilt, yTilt, tangentialPressure, + tabletData.buttons, pressure, + xTilt, yTilt, tangentialPressure, rotation, 0, tabletData.serialId); } #endif // QT_NO_TABLETEVENT diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 4f0f57c375..bd28548cba 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -183,7 +183,7 @@ void QXcbDrag::startDrag() QStringList fmts = QXcbMime::formatsHelper(drag()->mimeData()); for (int i = 0; i < fmts.size(); ++i) { - QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), fmts.at(i)); + QVector<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), fmts.at(i)); for (int j = 0; j < atoms.size(); ++j) { if (!drag_types.contains(atoms.at(j))) drag_types.append(atoms.at(j)); @@ -1010,9 +1010,6 @@ void QXcbDrag::handleFinished(const xcb_client_message_event_t *event) // current_target = 0; // current_proxy_target = 0; - if (t.drag) - t.drag->deleteLater(); - // current_target = target; // current_proxy_target = proxy_target; // current_embedding_widget = embedding_widget; @@ -1211,7 +1208,7 @@ QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QVariant::Type r return result; } - QList<xcb_atom_t> atoms = drag->xdnd_types; + QVector<xcb_atom_t> atoms = drag->xdnd_types; QByteArray encoding; xcb_atom_t a = mimeAtomForFormat(c, QLatin1String(format), requestedType, atoms, &encoding); if (a == XCB_NONE) diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h index d94c42696f..7b0d337e7c 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.h +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -46,7 +46,6 @@ #include <private/qsimpledrag_p.h> #include <qxcbobject.h> #include <xcb/xcb.h> -#include <qlist.h> #include <qpoint.h> #include <qrect.h> #include <qsharedpointer.h> @@ -127,7 +126,7 @@ private: // the types in this drop. 100 is no good, but at least it's big. enum { xdnd_max_type = 100 }; - QList<xcb_atom_t> xdnd_types; + QVector<xcb_atom_t> xdnd_types; // timestamp from XdndPosition and XdndDroptime for retrieving the data xcb_timestamp_t target_time; @@ -160,7 +159,7 @@ private: QPointer<QDrag> drag; QTime time; }; - QList<Transaction> transactions; + QVector<Transaction> transactions; int transaction_expiry_timer; void restartDropExpiryTimer(); diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp index 181d99e85b..bc800524ef 100644 --- a/src/plugins/platforms/xcb/qxcbimage.cpp +++ b/src/plugins/platforms/xcb/qxcbimage.cpp @@ -68,6 +68,14 @@ QImage::Format qt_xcb_imageFormatForVisual(QXcbConnection *connection, uint8_t d && visual->green_mask == 0xff00 && visual->blue_mask == 0xff) return QImage::Format_ARGB32_Premultiplied; + if (depth == 30 && format->bits_per_pixel == 32 && visual->red_mask == 0x3ff + && visual->green_mask == 0x0ffc00 && visual->blue_mask == 0x3ff00000) + return QImage::Format_BGR30; + + if (depth == 30 && format->bits_per_pixel == 32 && visual->blue_mask == 0x3ff + && visual->green_mask == 0x0ffc00 && visual->red_mask == 0x3ff00000) + return QImage::Format_RGB30; + if (depth == 24 && format->bits_per_pixel == 32 && visual->red_mask == 0xff0000 && visual->green_mask == 0xff00 && visual->blue_mask == 0xff) return QImage::Format_RGB32; @@ -147,6 +155,13 @@ QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap p[x] |= 0xff000000; p += bytes_per_line / 4; } + } else if (format == QImage::Format_BGR30 || format == QImage::Format_RGB30) { + QRgb *p = (QRgb *)image.bits(); + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) + p[x] |= 0xc0000000; + p += bytes_per_line / 4; + } } result = QPixmap::fromImage(image.copy()); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 1b1c20f02c..f537a38962 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -83,6 +83,7 @@ #include "qxcbeglsurface.h" #include <QtPlatformSupport/private/qeglplatformcontext_p.h> #include <QtPlatformSupport/private/qeglpbuffer_p.h> +#include <QtPlatformHeaders/QEGLNativeContext> #endif #include <QtGui/QOpenGLContext> @@ -187,8 +188,8 @@ class QEGLXcbPlatformContext : public QEGLPlatformContext { public: QEGLXcbPlatformContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share, - EGLDisplay display, QXcbConnection *c) - : QEGLPlatformContext(glFormat, share, display) + EGLDisplay display, QXcbConnection *c, const QVariant &nativeHandle) + : QEGLPlatformContext(glFormat, share, display, 0, nativeHandle) , m_connection(c) { Q_XCB_NOOP(m_connection); @@ -224,6 +225,10 @@ public: return static_cast<QEGLPbuffer *>(surface)->pbuffer(); } + QVariant nativeHandle() const { + return QVariant::fromValue<QEGLNativeContext>(QEGLNativeContext(eglContext(), eglDisplay())); + } + private: QXcbConnection *m_connection; }; @@ -234,10 +239,18 @@ QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLCont { QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle()); #if defined(XCB_USE_GLX) - return new QGLXContext(screen, context->format(), context->shareHandle()); + QGLXContext *platformContext = new QGLXContext(screen, context->format(), + context->shareHandle(), context->nativeHandle()); + context->setNativeHandle(platformContext->nativeHandle()); + return platformContext; #elif defined(XCB_USE_EGL) - return new QEGLXcbPlatformContext(context->format(), context->shareHandle(), - screen->connection()->egl_display(), screen->connection()); + QEGLXcbPlatformContext *platformContext = new QEGLXcbPlatformContext(context->format(), + context->shareHandle(), + screen->connection()->egl_display(), + screen->connection(), + context->nativeHandle()); + context->setNativeHandle(platformContext->nativeHandle()); + return platformContext; #else Q_UNUSED(screen); qWarning("QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled"); diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 4c84b19f82..c52714b456 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -198,8 +198,10 @@ #define XF86XK_MenuKB 0x1008FF65 #define XF86XK_MenuPB 0x1008FF66 #define XF86XK_MySites 0x1008FF67 +#define XF86XK_New 0x1008FF68 #define XF86XK_News 0x1008FF69 #define XF86XK_OfficeHome 0x1008FF6A +#define XF86XK_Open 0x1008FF6B #define XF86XK_Option 0x1008FF6C #define XF86XK_Paste 0x1008FF6D #define XF86XK_Phone 0x1008FF6E @@ -497,8 +499,10 @@ static const unsigned int KeyTbl[] = { XF86XK_MenuKB, Qt::Key_MenuKB, XF86XK_MenuPB, Qt::Key_MenuPB, XF86XK_MySites, Qt::Key_MySites, + XF86XK_New, Qt::Key_New, XF86XK_News, Qt::Key_News, XF86XK_OfficeHome, Qt::Key_OfficeHome, + XF86XK_Open, Qt::Key_Open, XF86XK_Option, Qt::Key_Option, XF86XK_Paste, Qt::Key_Paste, XF86XK_Phone, Qt::Key_Phone, diff --git a/src/plugins/platforms/xcb/qxcbmime.cpp b/src/plugins/platforms/xcb/qxcbmime.cpp index b205a63267..c0f6745e7f 100644 --- a/src/plugins/platforms/xcb/qxcbmime.cpp +++ b/src/plugins/platforms/xcb/qxcbmime.cpp @@ -136,9 +136,10 @@ bool QXcbMime::mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeDa return ret; } -QList<xcb_atom_t> QXcbMime::mimeAtomsForFormat(QXcbConnection *connection, const QString &format) +QVector<xcb_atom_t> QXcbMime::mimeAtomsForFormat(QXcbConnection *connection, const QString &format) { - QList<xcb_atom_t> atoms; + QVector<xcb_atom_t> atoms; + atoms.reserve(7); atoms.append(connection->internAtom(format.toLatin1())); // special cases for strings @@ -240,7 +241,7 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, } xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString &format, QVariant::Type requestedType, - const QList<xcb_atom_t> &atoms, QByteArray *requestedEncoding) + const QVector<xcb_atom_t> &atoms, QByteArray *requestedEncoding) { requestedEncoding->clear(); diff --git a/src/plugins/platforms/xcb/qxcbmime.h b/src/plugins/platforms/xcb/qxcbmime.h index 4a69a35ced..563716a75b 100644 --- a/src/plugins/platforms/xcb/qxcbmime.h +++ b/src/plugins/platforms/xcb/qxcbmime.h @@ -59,14 +59,14 @@ public: QXcbMime(); ~QXcbMime(); - static QList<xcb_atom_t> mimeAtomsForFormat(QXcbConnection *connection, const QString &format); + static QVector<xcb_atom_t> mimeAtomsForFormat(QXcbConnection *connection, const QString &format); static QString mimeAtomToString(QXcbConnection *connection, xcb_atom_t a); static bool mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeData *mimeData, QByteArray *data, xcb_atom_t *atomFormat, int *dataFormat); static QVariant mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &data, const QString &format, QVariant::Type requestedType, const QByteArray &encoding); static xcb_atom_t mimeAtomForFormat(QXcbConnection *connection, const QString &format, QVariant::Type requestedType, - const QList<xcb_atom_t> &atoms, QByteArray *requestedEncoding); + const QVector<xcb_atom_t> &atoms, QByteArray *requestedEncoding); }; #endif // !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD)) diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index b45bd6a82e..5673d41811 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -60,6 +60,8 @@ #include "qglxintegration.h" #endif +#include <QtPlatformHeaders/qxcbwindowfunctions.h> + #ifdef XCB_USE_XLIB # include <X11/Xlib.h> #else @@ -77,6 +79,8 @@ static int resourceType(const QByteArray &key) QByteArrayLiteral("display"), QByteArrayLiteral("egldisplay"), QByteArrayLiteral("connection"), QByteArrayLiteral("screen"), QByteArrayLiteral("eglcontext"), + QByteArrayLiteral("eglconfig"), + QByteArrayLiteral("glxconfig"), QByteArrayLiteral("glxcontext"), QByteArrayLiteral("apptime"), QByteArrayLiteral("appusertime"), QByteArrayLiteral("hintstyle"), QByteArrayLiteral("startupid"), QByteArrayLiteral("traywindow"), @@ -91,7 +95,9 @@ static int resourceType(const QByteArray &key) } QXcbNativeInterface::QXcbNativeInterface() : - m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t")) + m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t")), + m_sysTraySelectionAtom(XCB_ATOM_NONE), + m_systrayVisualId(XCB_NONE) { } @@ -133,6 +139,82 @@ QRect QXcbNativeInterface::systemTrayWindowGlobalGeometry(const QWindow *window) return QRect(); } +xcb_window_t QXcbNativeInterface::locateSystemTray(xcb_connection_t *conn, const QXcbScreen *screen) +{ + if (m_sysTraySelectionAtom == XCB_ATOM_NONE) { + const QByteArray net_sys_tray = QString::fromLatin1("_NET_SYSTEM_TRAY_S%1").arg(screen->screenNumber()).toLatin1(); + xcb_intern_atom_cookie_t intern_c = + xcb_intern_atom_unchecked(conn, true, net_sys_tray.length(), net_sys_tray); + + xcb_intern_atom_reply_t *intern_r = xcb_intern_atom_reply(conn, intern_c, 0); + + if (!intern_r) + return XCB_WINDOW_NONE; + + m_sysTraySelectionAtom = intern_r->atom; + free(intern_r); + } + + xcb_get_selection_owner_cookie_t sel_owner_c = xcb_get_selection_owner_unchecked(conn, m_sysTraySelectionAtom); + xcb_get_selection_owner_reply_t *sel_owner_r = xcb_get_selection_owner_reply(conn, sel_owner_c, 0); + + if (!sel_owner_r) + return XCB_WINDOW_NONE; + + xcb_window_t selection_window = sel_owner_r->owner; + free(sel_owner_r); + + return selection_window; +} + +bool QXcbNativeInterface::systrayVisualHasAlphaChannel() { + const QXcbScreen *screen = static_cast<QXcbScreen *>(QGuiApplication::primaryScreen()->handle()); + + if (m_systrayVisualId == XCB_NONE) { + xcb_connection_t *xcb_conn = screen->xcb_connection(); + xcb_atom_t tray_atom = screen->atom(QXcbAtom::_NET_SYSTEM_TRAY_VISUAL); + + xcb_window_t systray_window = locateSystemTray(xcb_conn, screen); + if (systray_window == XCB_WINDOW_NONE) + return false; + + // Get the xcb property for the _NET_SYSTEM_TRAY_VISUAL atom + xcb_get_property_cookie_t systray_atom_cookie; + xcb_get_property_reply_t *systray_atom_reply; + + systray_atom_cookie = xcb_get_property_unchecked(xcb_conn, false, systray_window, + tray_atom, XCB_ATOM_VISUALID, 0, 1); + systray_atom_reply = xcb_get_property_reply(xcb_conn, systray_atom_cookie, 0); + + if (!systray_atom_reply) + return false; + + if (systray_atom_reply->value_len > 0 && xcb_get_property_value_length(systray_atom_reply) > 0) { + xcb_visualid_t * vids = (uint32_t *)xcb_get_property_value(systray_atom_reply); + m_systrayVisualId = vids[0]; + } + + free(systray_atom_reply); + } + + if (m_systrayVisualId != XCB_NONE) { + quint8 depth = screen->depthOfVisual(m_systrayVisualId); + return depth == 32; + } else { + return false; + } +} + +void QXcbNativeInterface::clearRegion(const QWindow *qwindow, const QRect& rect) +{ + if (const QPlatformWindow *platformWindow = qwindow->handle()) { + const QXcbWindow *qxwindow = static_cast<const QXcbWindow *>(platformWindow); + xcb_connection_t *xcb_conn = qxwindow->xcb_connection(); + + xcb_clear_area(xcb_conn, false, qxwindow->xcb_window(), rect.x(), rect.y(), rect.width(), rect.height()); + } +} + void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString) { void *result = 0; @@ -160,6 +242,12 @@ void *QXcbNativeInterface::nativeResourceForContext(const QByteArray &resourceSt case EglContext: result = eglContextForContext(context); break; + case EglConfig: + result = eglConfigForContext(context); + break; + case GLXConfig: + result = glxConfigForContext(context); + break; case GLXContext: result = glxContextForContext(context); break; @@ -225,6 +313,14 @@ void *QXcbNativeInterface::nativeResourceForWindow(const QByteArray &resourceStr return result; } +QPlatformNativeInterface::NativeResourceForIntegrationFunction QXcbNativeInterface::nativeResourceFunctionForIntegration(const QByteArray &resource) +{ + QByteArray lowerCaseResource = resource.toLower(); + if (lowerCaseResource == "setstartupid") + return NativeResourceForIntegrationFunction(setStartupId); + return 0; +} + QPlatformNativeInterface::NativeResourceForScreenFunction QXcbNativeInterface::nativeResourceFunctionForScreen(const QByteArray &resource) { const QByteArray lowerCaseResource = resource.toLower(); @@ -235,6 +331,14 @@ QPlatformNativeInterface::NativeResourceForScreenFunction QXcbNativeInterface::n return 0; } +QFunctionPointer QXcbNativeInterface::platformFunction(const QByteArray &function) const +{ + if (function == QXcbWindowFunctions::setWmWindowTypeIdentifier()) { + return QFunctionPointer(QXcbWindow::setWmWindowTypeStatic); + } + return Q_NULLPTR; +} + void *QXcbNativeInterface::appTime(const QXcbScreen *screen) { return reinterpret_cast<void *>(quintptr(screen->connection()->time())); @@ -287,6 +391,15 @@ void QXcbNativeInterface::setAppUserTime(QScreen* screen, xcb_timestamp_t time) static_cast<QXcbScreen *>(screen->handle())->connection()->setNetWmUserTime(time); } +void QXcbNativeInterface::setStartupId(const char *data) +{ + QByteArray startupId(data); + QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration()); + QXcbConnection *defaultConnection = integration->defaultConnection(); + if (defaultConnection) + defaultConnection->setStartupId(startupId); +} + QPlatformNativeInterface::NativeResourceForContextFunction QXcbNativeInterface::nativeResourceFunctionForContext(const QByteArray &resource) { QByteArray lowerCaseResource = resource.toLower(); @@ -353,6 +466,18 @@ void * QXcbNativeInterface::eglContextForContext(QOpenGLContext *context) #endif } +void * QXcbNativeInterface::eglConfigForContext(QOpenGLContext *context) +{ + Q_ASSERT(context); +#if defined(XCB_USE_EGL) + QEGLPlatformContext *eglPlatformContext = static_cast<QEGLPlatformContext *>(context->handle()); + return eglPlatformContext->eglConfig(); +#else + Q_UNUSED(context); + return 0; +#endif +} + void *QXcbNativeInterface::glxContextForContext(QOpenGLContext *context) { Q_ASSERT(context); @@ -366,4 +491,17 @@ void *QXcbNativeInterface::glxContextForContext(QOpenGLContext *context) } +void *QXcbNativeInterface::glxConfigForContext(QOpenGLContext *context) +{ + Q_ASSERT(context); +#if defined(XCB_USE_GLX) + QGLXContext *glxPlatformContext = static_cast<QGLXContext *>(context->handle()); + return glxPlatformContext->glxConfig(); +#else + Q_UNUSED(context); + return 0; +#endif + +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index fb1a46014c..c63cdf0254 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -63,6 +63,8 @@ public: Connection, Screen, EglContext, + EglConfig, + GLXConfig, GLXContext, AppTime, AppUserTime, @@ -77,13 +79,16 @@ public: QXcbNativeInterface(); void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; - void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context); - void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen); - void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); + void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) Q_DECL_OVERRIDE; + void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) Q_DECL_OVERRIDE; + void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) Q_DECL_OVERRIDE; - NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource); + NativeResourceForIntegrationFunction nativeResourceFunctionForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; + NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) Q_DECL_OVERRIDE; NativeResourceForScreenFunction nativeResourceFunctionForScreen(const QByteArray &resource) Q_DECL_OVERRIDE; + QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE; + inline const QByteArray &genericEventFilterType() const { return m_genericEventFilterType; } void *displayForWindow(QWindow *window); @@ -96,13 +101,18 @@ public: void *startupId(); void *x11Screen(); void *rootWindow(); + static void setStartupId(const char *); static void setAppTime(QScreen *screen, xcb_timestamp_t time); static void setAppUserTime(QScreen *screen, xcb_timestamp_t time); static void *eglContextForContext(QOpenGLContext *context); + static void *eglConfigForContext(QOpenGLContext *context); static void *glxContextForContext(QOpenGLContext *context); + static void *glxConfigForContext(QOpenGLContext *context); Q_INVOKABLE void beep(); Q_INVOKABLE bool systemTrayAvailable(const QScreen *screen) const; + Q_INVOKABLE void clearRegion(const QWindow *qwindow, const QRect& rect); + Q_INVOKABLE bool systrayVisualHasAlphaChannel(); Q_INVOKABLE bool requestSystemTrayWindowDock(const QWindow *window); Q_INVOKABLE QRect systemTrayWindowGlobalGeometry(const QWindow *window); @@ -110,8 +120,13 @@ signals: void systemTrayWindowChanged(QScreen *screen); private: + xcb_window_t locateSystemTray(xcb_connection_t *conn, const QXcbScreen *screen); + const QByteArray m_genericEventFilterType; + xcb_atom_t m_sysTraySelectionAtom; + xcb_visualid_t m_systrayVisualId; + static QXcbScreen *qPlatformScreenForWindow(QWindow *window); }; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 01e78465b6..85f4dfbd43 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -200,6 +200,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, while (visualtype_iterator.rem) { xcb_visualtype_t *visualtype = visualtype_iterator.data; m_visuals.insert(visualtype->visual_id, *visualtype); + m_visualDepths.insert(visualtype->visual_id, depth->depth); xcb_visualtype_next(&visualtype_iterator); } @@ -296,6 +297,14 @@ const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid) const return &*it; } +quint8 QXcbScreen::depthOfVisual(xcb_visualid_t visualid) const +{ + QMap<xcb_visualid_t, quint8>::const_iterator it = m_visualDepths.find(visualid); + if (it == m_visualDepths.constEnd()) + return 0; + return *it; +} + QImage::Format QXcbScreen::format() const { return QImage::Format_RGB32; diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index c36492db64..53ac65bb09 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -93,6 +93,7 @@ public: bool syncRequestSupported() const { return m_syncRequestSupported; } const xcb_visualtype_t *visualForId(xcb_visualid_t) const; + quint8 depthOfVisual(xcb_visualid_t) const; QString name() const { return m_outputName; } @@ -127,6 +128,7 @@ private: bool m_syncRequestSupported; xcb_window_t m_clientLeader; QMap<xcb_visualid_t, xcb_visualtype_t> m_visuals; + QMap<xcb_visualid_t, quint8> m_visualDepths; QXcbCursor *m_cursor; int m_refreshRate; int m_forcedDpi; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 586068d8d9..a127ac0293 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -166,16 +166,36 @@ static inline bool isTransient(const QWindow *w) || w->type() == Qt::Popup; } -static inline QImage::Format imageFormatForDepth(int depth) +static inline QImage::Format imageFormatForVisual(int depth, quint32 red_mask, quint32 blue_mask) { switch (depth) { - case 32: return QImage::Format_ARGB32_Premultiplied; - case 24: return QImage::Format_RGB32; - case 16: return QImage::Format_RGB16; - default: - qWarning("Unsupported screen depth: %d", depth); - return QImage::Format_Invalid; + case 32: + if (blue_mask == 0xff) + return QImage::Format_ARGB32_Premultiplied; + if (red_mask == 0x3ff) + return QImage::Format_A2BGR30_Premultiplied; + if (blue_mask == 0x3ff) + return QImage::Format_A2RGB30_Premultiplied; + break; + case 30: + if (red_mask == 0x3ff) + return QImage::Format_BGR30; + if (blue_mask == 0x3ff) + return QImage::Format_RGB30; + break; + case 24: + if (blue_mask == 0xff) + return QImage::Format_RGB32; + break; + case 16: + if (blue_mask == 0x1f) + return QImage::Format_RGB16; + break; + default: + break; } + qWarning("Unsupported screen format: depth: %d, red_mask: %x, blue_mask: %x", depth, red_mask, blue_mask); + return QImage::Format_Invalid; } static inline bool positionIncludesFrame(QWindow *w) @@ -183,6 +203,8 @@ static inline bool positionIncludesFrame(QWindow *w) return qt_window_private(w)->positionPolicy == QWindowPrivate::WindowFrameInclusive; } +static const char *wm_window_type_property_id = "_q_xcb_wm_window_type"; + QXcbWindow::QXcbWindow(QWindow *window) : QPlatformWindow(window) , m_window(0) @@ -201,6 +223,7 @@ QXcbWindow::QXcbWindow(QWindow *window) #endif , m_lastWindowStateEvent(-1) , m_syncState(NoSyncNeeded) + , m_pendingSyncRequest(0) { m_screen = static_cast<QXcbScreen *>(window->screen()->handle()); @@ -225,7 +248,9 @@ void QXcbWindow::create() if (type == Qt::Desktop) { m_window = m_screen->root(); m_depth = m_screen->screen()->root_depth; - m_imageFormat = imageFormatForDepth(m_depth); + m_visualId = m_screen->screen()->root_visual; + const xcb_visualtype_t *visual = m_screen->visualForId(m_visualId); + m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask); connection()->addWindowEventListener(m_window, this); return; } @@ -315,7 +340,7 @@ void QXcbWindow::create() } if (visualInfo) { m_depth = visualInfo->depth; - m_imageFormat = imageFormatForDepth(m_depth); + m_imageFormat = imageFormatForVisual(visualInfo->depth, visualInfo->red_mask, visualInfo->blue_mask); Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), xcb_parent_id, visualInfo->visual, AllocNone); XSetWindowAttributes a; @@ -365,7 +390,8 @@ void QXcbWindow::create() } } - m_imageFormat = imageFormatForDepth(m_depth); + const xcb_visualtype_t *visual = m_screen->visualForId(m_visualId); + m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask); Q_XCB_CALL(xcb_create_window(xcb_connection(), m_depth, @@ -540,6 +566,9 @@ void QXcbWindow::destroy() delete m_eglSurface; m_eglSurface = 0; #endif + + if (m_pendingSyncRequest) + m_pendingSyncRequest->invalidate(); } void QXcbWindow::setGeometry(const QRect &rect) @@ -698,6 +727,11 @@ void QXcbWindow::show() updateNetWmStateBeforeMap(); } + if (window()->metaObject()->indexOfProperty(wm_window_type_property_id) >= 0) { + QXcbWindowFunctions::WmWindowTypes wmWindowTypes(window()->property(wm_window_type_property_id).value<int>()); + setWmWindowType(wmWindowTypes); + } + if (connection()->time() != XCB_TIME_CURRENT_TIME) updateNetWmUserTime(connection()->time()); @@ -1535,6 +1569,130 @@ QXcbEGLSurface *QXcbWindow::eglSurface() const } #endif +void QXcbWindow::setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmWindowTypes windowTypes) +{ + if (window->handle()) + static_cast<QXcbWindow *>(window->handle())->setWmWindowType(windowTypes); + else + window->setProperty(wm_window_type_property_id, QVariant::fromValue(static_cast<int>(windowTypes))); +} + +QXcbWindowFunctions::WmWindowTypes QXcbWindow::wmWindowTypes() const +{ + QXcbWindowFunctions::WmWindowTypes result(0); + + xcb_get_property_cookie_t get_cookie = + xcb_get_property_unchecked(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_WINDOW_TYPE), + XCB_ATOM_ATOM, 0, 1024); + + xcb_get_property_reply_t *reply = + xcb_get_property_reply(xcb_connection(), get_cookie, NULL); + + if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) { + const xcb_atom_t *types = static_cast<const xcb_atom_t *>(xcb_get_property_value(reply)); + const xcb_atom_t *types_end = types + reply->length; + for (; types != types_end; types++) { + QXcbAtom::Atom type = connection()->qatom(*types); + switch (type) { + case QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL: + result |= QXcbWindowFunctions::Normal; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_DESKTOP: + result |= QXcbWindowFunctions::Desktop; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_DOCK: + result |= QXcbWindowFunctions::Dock; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLBAR: + result |= QXcbWindowFunctions::Toolbar; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_MENU: + result |= QXcbWindowFunctions::Menu; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY: + result |= QXcbWindowFunctions::Utility; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH: + result |= QXcbWindowFunctions::Splash; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG: + result |= QXcbWindowFunctions::Dialog; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_DROPDOWN_MENU: + result |= QXcbWindowFunctions::DropDownMenu; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_POPUP_MENU: + result |= QXcbWindowFunctions::PopupMenu; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP: + result |= QXcbWindowFunctions::Tooltip; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_NOTIFICATION: + result |= QXcbWindowFunctions::Notification; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_COMBO: + result |= QXcbWindowFunctions::Combo; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_DND: + result |= QXcbWindowFunctions::Dnd; + break; + case QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE: + result |= QXcbWindowFunctions::KdeOverride; + break; + default: + break; + } + } + free(reply); + } + return result; +} + +void QXcbWindow::setWmWindowType(QXcbWindowFunctions::WmWindowTypes types) +{ + QVector<xcb_atom_t> atoms; + + if (types & QXcbWindowFunctions::Normal) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL)); + if (types & QXcbWindowFunctions::Desktop) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DESKTOP)); + if (types & QXcbWindowFunctions::Dock) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DOCK)); + if (types & QXcbWindowFunctions::Toolbar) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLBAR)); + if (types & QXcbWindowFunctions::Menu) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_MENU)); + if (types & QXcbWindowFunctions::Utility) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY)); + if (types & QXcbWindowFunctions::Splash) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH)); + if (types & QXcbWindowFunctions::Dialog) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG)); + if (types & QXcbWindowFunctions::DropDownMenu) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DROPDOWN_MENU)); + if (types & QXcbWindowFunctions::PopupMenu) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_POPUP_MENU)); + if (types & QXcbWindowFunctions::Tooltip) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP)); + if (types & QXcbWindowFunctions::Notification) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NOTIFICATION)); + if (types & QXcbWindowFunctions::Combo) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_COMBO)); + if (types & QXcbWindowFunctions::Dnd) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DND)); + if (types & QXcbWindowFunctions::KdeOverride) + atoms.append(atom(QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE)); + + if (atoms.isEmpty()) { + Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_WINDOW_TYPE))); + } else { + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + atom(QXcbAtom::_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32, + atoms.count(), atoms.constData())); + } + xcb_flush(xcb_connection()); +} + class ExposeCompressor { public: @@ -1687,14 +1845,10 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * QPlatformWindow::setGeometry(rect); QWindowSystemInterface::handleGeometryChange(window(), rect); - if (!m_screen->availableGeometry().intersects(rect)) { - Q_FOREACH (QPlatformScreen* screen, m_screen->virtualSiblings()) { - if (screen->availableGeometry().intersects(rect)) { - m_screen = static_cast<QXcbScreen*>(screen); - QWindowSystemInterface::handleWindowScreenChanged(window(), m_screen->QPlatformScreen::screen()); - break; - } - } + QPlatformScreen *newScreen = screenForGeometry(rect); + if (newScreen != m_screen) { + m_screen = static_cast<QXcbScreen*>(newScreen); + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); } m_configureNotifyPending = false; @@ -2221,4 +2375,13 @@ bool QXcbWindow::needsSync() const return m_syncState == SyncAndConfigureReceived; } +void QXcbWindow::postSyncWindowRequest() +{ + if (!m_pendingSyncRequest) { + QXcbSyncWindowRequest *e = new QXcbSyncWindowRequest(this); + m_pendingSyncRequest = e; + QCoreApplication::postEvent(m_screen->connection(), e); + } +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index b924ee27e5..a8cadd8e6c 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -51,11 +51,15 @@ #include "qxcbobject.h" +#include <QtPlatformHeaders/qxcbwindowfunctions.h> + QT_BEGIN_NAMESPACE class QXcbScreen; class QXcbEGLSurface; +class QXcbSyncWindowRequest; class QIcon; + class QXcbWindow : public QXcbObject, public QXcbWindowEventListener, public QPlatformWindow { public: @@ -150,8 +154,16 @@ public: QXcbEGLSurface *eglSurface() const; #endif + static void setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmWindowTypes windowTypes); + + QXcbWindowFunctions::WmWindowTypes wmWindowTypes() const; + void setWmWindowType(QXcbWindowFunctions::WmWindowTypes types); + bool needsSync() const; + void postSyncWindowRequest(); + void clearSyncWindowRequest() { m_pendingSyncRequest = 0; } + public Q_SLOTS: void updateSyncRequestCounter(); @@ -228,6 +240,8 @@ private: SyncAndConfigureReceived }; SyncState m_syncState; + + QXcbSyncWindowRequest *m_pendingSyncRequest; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbxsettings.cpp b/src/plugins/platforms/xcb/qxcbxsettings.cpp index 141a6cc0cb..17b40a45e1 100644 --- a/src/plugins/platforms/xcb/qxcbxsettings.cpp +++ b/src/plugins/platforms/xcb/qxcbxsettings.cpp @@ -42,6 +42,7 @@ #include "qxcbxsettings.h" #include <QtCore/QByteArray> +#include <QtCore/QtEndian> #include <X11/extensions/XIproto.h> @@ -149,47 +150,67 @@ public: { if (xSettings.length() < 12) return; - // we ignore byteorder for now - char byteOrder = xSettings.at(1); - Q_UNUSED(byteOrder); - uint number_of_settings = *reinterpret_cast<const uint *>(xSettings.mid(8,4).constData()); + char byteOrder = xSettings.at(0); + if (byteOrder != LSBFirst && byteOrder != MSBFirst) { + qWarning("%s ByteOrder byte %d not 0 or 1", Q_FUNC_INFO , byteOrder); + return; + } + +#define ADJUST_BO(b, t, x) \ + ((b == LSBFirst) ? \ + qFromLittleEndian<t>((const uchar *)(x)) : \ + qFromBigEndian<t>((const uchar *)(x))) +#define VALIDATE_LENGTH(x) \ + if ((size_t)xSettings.length() < (offset + local_offset + 12 + x)) { \ + qWarning("%s Length %d runs past end of data", Q_FUNC_INFO , x); \ + return; \ + } + uint number_of_settings = ADJUST_BO(byteOrder, quint32, xSettings.mid(8,4).constData()); const char *data = xSettings.constData() + 12; size_t offset = 0; for (uint i = 0; i < number_of_settings; i++) { int local_offset = 0; + VALIDATE_LENGTH(2); XSettingsType type = static_cast<XSettingsType>(*reinterpret_cast<const quint8 *>(data + offset)); local_offset += 2; - quint16 name_len = *reinterpret_cast<const quint16 *>(data + offset + local_offset); + VALIDATE_LENGTH(2); + quint16 name_len = ADJUST_BO(byteOrder, quint16, data + offset + local_offset); local_offset += 2; + VALIDATE_LENGTH(name_len); QByteArray name(data + offset + local_offset, name_len); local_offset += round_to_nearest_multiple_of_4(name_len); - int last_change_serial = *reinterpret_cast<const int *>(data + offset + local_offset); + VALIDATE_LENGTH(4); + int last_change_serial = ADJUST_BO(byteOrder, qint32, data + offset + local_offset); Q_UNUSED(last_change_serial); local_offset += 4; QVariant value; if (type == XSettingsTypeString) { - int value_length = *reinterpret_cast<const int *>(data + offset + local_offset); + VALIDATE_LENGTH(4); + int value_length = ADJUST_BO(byteOrder, qint32, data + offset + local_offset); local_offset+=4; + VALIDATE_LENGTH(value_length); QByteArray value_string(data + offset + local_offset, value_length); value.setValue(value_string); local_offset += round_to_nearest_multiple_of_4(value_length); } else if (type == XSettingsTypeInteger) { - int value_length = *reinterpret_cast<const int *>(data + offset + local_offset); + VALIDATE_LENGTH(4); + int value_length = ADJUST_BO(byteOrder, qint32, data + offset + local_offset); local_offset += 4; value.setValue(value_length); } else if (type == XSettingsTypeColor) { - quint16 red = *reinterpret_cast<const quint16 *>(data + offset + local_offset); + VALIDATE_LENGTH(2*4); + quint16 red = ADJUST_BO(byteOrder, quint16, data + offset + local_offset); local_offset += 2; - quint16 green = *reinterpret_cast<const quint16 *>(data + offset + local_offset); + quint16 green = ADJUST_BO(byteOrder, quint16, data + offset + local_offset); local_offset += 2; - quint16 blue = *reinterpret_cast<const quint16 *>(data + offset + local_offset); + quint16 blue = ADJUST_BO(byteOrder, quint16, data + offset + local_offset); local_offset += 2; - quint16 alpha= *reinterpret_cast<const quint16 *>(data + offset + local_offset); + quint16 alpha= ADJUST_BO(byteOrder, quint16, data + offset + local_offset); local_offset += 2; QColor color_value(red,green,blue,alpha); value.setValue(color_value); diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 942db329ca..d1cbff59c1 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -3,6 +3,5 @@ TEMPLATE = subdirs SUBDIRS *= sqldrivers !winrt:qtHaveModule(network): SUBDIRS += bearer qtHaveModule(gui): SUBDIRS *= imageformats platforms platforminputcontexts platformthemes generic -qtHaveModule(widgets): SUBDIRS += accessible !winrt:!wince*:qtHaveModule(widgets):SUBDIRS += printsupport |