diff options
Diffstat (limited to 'src/plugins/platforms')
20 files changed, 464 insertions, 95 deletions
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 8a3a958d3b..07bdf95bf4 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -78,10 +78,24 @@ void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteA return QtAndroid::javaVM(); if (resource == "QtActivity") return QtAndroid::activity(); - if (resource == "AndroidStylePalettes") - return &m_palettes; - if (resource == "AndroidStyleFonts") - return &m_fonts; + if (resource == "AndroidStyleData") { + if (m_androidStyle) + return &m_androidStyle->m_styleData; + else + return Q_NULLPTR; + } + if (resource == "AndroidStandardPalette") { + if (m_androidStyle) + return &m_androidStyle->m_standardPalette; + else + return Q_NULLPTR; + } + if (resource == "AndroidQWidgetFonts") { + if (m_androidStyle) + return &m_androidStyle->m_QWidgetsFonts; + else + return Q_NULLPTR; + } if (resource == "AndroidDeviceName") { static QString deviceName = QtAndroid::deviceName(); return &deviceName; diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h index 13c98442e9..7b4ab08847 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/qandroidplatformintegration.h @@ -44,6 +44,8 @@ #include "qandroidplatformscreen.h" +#include <memory> + QT_BEGIN_NAMESPACE class QDesktopWidget; @@ -51,12 +53,12 @@ class QAndroidPlatformServices; class QAndroidSystemLocale; class QPlatformAccessibility; +struct AndroidStyle; class QAndroidPlatformNativeInterface: public QPlatformNativeInterface { public: void *nativeResourceForIntegration(const QByteArray &resource); - QHash<int, QPalette> m_palettes; - QHash<int, QFont> m_fonts; + std::shared_ptr<AndroidStyle> m_androidStyle; }; class QAndroidPlatformIntegration : public QPlatformIntegration diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp index 02974018aa..f9f2e4a944 100644 --- a/src/plugins/platforms/android/qandroidplatformtheme.cpp +++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp @@ -37,17 +37,281 @@ #include "qandroidplatformmenu.h" #include "qandroidplatformmenuitem.h" #include "qandroidplatformdialoghelpers.h" -#include <QVariant> -#include <QFileInfo> + #include <QCoreApplication> +#include <QDebug> +#include <QFileInfo> +#include <QJsonDocument> +#include <QVariant> + #include <private/qguiapplication_p.h> #include <qandroidplatformintegration.h> QT_BEGIN_NAMESPACE +namespace { + const int textStyle_bold = 1; + const int textStyle_italic = 2; + + const int typeface_sans = 1; + const int typeface_serif = 2; + const int typeface_monospace = 3; +} + +static int fontType(const QString &androidControl) +{ + if (androidControl == QLatin1String("defaultStyle")) + return QPlatformTheme::SystemFont; + if (androidControl == QLatin1String("textViewStyle")) + return QPlatformTheme::LabelFont; + else if (androidControl == QLatin1String("buttonStyle")) + return QPlatformTheme::PushButtonFont; + else if (androidControl == QLatin1String("checkboxStyle")) + return QPlatformTheme::CheckBoxFont; + else if (androidControl == QLatin1String("radioButtonStyle")) + return QPlatformTheme::RadioButtonFont; + else if (androidControl == QLatin1String("simple_list_item_single_choice")) + return QPlatformTheme::ItemViewFont; + else if (androidControl == QLatin1String("simple_spinner_dropdown_item")) + return QPlatformTheme::ComboMenuItemFont; + else if (androidControl == QLatin1String("spinnerStyle")) + return QPlatformTheme::ComboLineEditFont; + else if (androidControl == QLatin1String("simple_list_item")) + return QPlatformTheme::ListViewFont; + return -1; +} + +static int paletteType(const QString &androidControl) +{ + if (androidControl == QLatin1String("defaultStyle")) + return QPlatformTheme::SystemPalette; + if (androidControl == QLatin1String("textViewStyle")) + return QPlatformTheme::LabelPalette; + else if (androidControl == QLatin1String("buttonStyle")) + return QPlatformTheme::ButtonPalette; + else if (androidControl == QLatin1String("checkboxStyle")) + return QPlatformTheme::CheckBoxPalette; + else if (androidControl == QLatin1String("radioButtonStyle")) + return QPlatformTheme::RadioButtonPalette; + else if (androidControl == QLatin1String("simple_list_item_single_choice")) + return QPlatformTheme::ItemViewPalette; + else if (androidControl == QLatin1String("editTextStyle")) + return QPlatformTheme::TextLineEditPalette; + else if (androidControl == QLatin1String("spinnerStyle")) + return QPlatformTheme::ComboBoxPalette; + return -1; +} + +static void setPaletteColor(const QVariantMap &object, + QPalette &palette, + QPalette::ColorRole role) +{ + // QPalette::Active -> ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET + palette.setColor(QPalette::Active, + role, + QRgb(object.value(QLatin1String("ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET")).toInt())); + + // QPalette::Inactive -> ENABLED_STATE_SET + palette.setColor(QPalette::Inactive, + role, + QRgb(object.value(QLatin1String("ENABLED_STATE_SET")).toInt())); + + // QPalette::Disabled -> EMPTY_STATE_SET + palette.setColor(QPalette::Disabled, + role, + QRgb(object.value(QLatin1String("EMPTY_STATE_SET")).toInt())); + + palette.setColor(QPalette::Current, role, palette.color(QPalette::Active, role)); + + if (role == QPalette::WindowText) { + // QPalette::BrightText -> PRESSED + // QPalette::Active -> PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET + palette.setColor(QPalette::Active, + QPalette::BrightText, + QRgb(object.value(QLatin1String("PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET")).toInt())); + + // QPalette::Inactive -> PRESSED_ENABLED_STATE_SET + palette.setColor(QPalette::Inactive, + QPalette::BrightText, + QRgb(object.value(QLatin1String("PRESSED_ENABLED_STATE_SET")).toInt())); + + // QPalette::Disabled -> PRESSED_STATE_SET + palette.setColor(QPalette::Disabled, + QPalette::BrightText, + QRgb(object.value(QLatin1String("PRESSED_STATE_SET")).toInt())); + + palette.setColor(QPalette::Current, QPalette::BrightText, palette.color(QPalette::Active, QPalette::BrightText)); + + // QPalette::HighlightedText -> SELECTED + // QPalette::Active -> ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET + palette.setColor(QPalette::Active, + QPalette::HighlightedText, + QRgb(object.value(QLatin1String("ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET")).toInt())); + + // QPalette::Inactive -> ENABLED_SELECTED_STATE_SET + palette.setColor(QPalette::Inactive, + QPalette::HighlightedText, + QRgb(object.value(QLatin1String("ENABLED_SELECTED_STATE_SET")).toInt())); + + // QPalette::Disabled -> SELECTED_STATE_SET + palette.setColor(QPalette::Disabled, + QPalette::HighlightedText, + QRgb(object.value(QLatin1String("SELECTED_STATE_SET")).toInt())); + + palette.setColor(QPalette::Current, + QPalette::HighlightedText, + palette.color(QPalette::Active, QPalette::HighlightedText)); + + // Same colors for Text + palette.setColor(QPalette::Active, QPalette::Text, palette.color(QPalette::Active, role)); + palette.setColor(QPalette::Inactive, QPalette::Text, palette.color(QPalette::Inactive, role)); + palette.setColor(QPalette::Disabled, QPalette::Text, palette.color(QPalette::Disabled, role)); + palette.setColor(QPalette::Current, QPalette::Text, palette.color(QPalette::Current, role)); + + // And for ButtonText + palette.setColor(QPalette::Active, QPalette::ButtonText, palette.color(QPalette::Active, role)); + palette.setColor(QPalette::Inactive, QPalette::ButtonText, palette.color(QPalette::Inactive, role)); + palette.setColor(QPalette::Disabled, QPalette::ButtonText, palette.color(QPalette::Disabled, role)); + palette.setColor(QPalette::Current, QPalette::ButtonText, palette.color(QPalette::Current, role)); + } +} + +static std::shared_ptr<AndroidStyle> loadAndroidStyle(QPalette *defaultPalette) +{ + QString stylePath(QLatin1String(qgetenv("MINISTRO_ANDROID_STYLE_PATH"))); + const QLatin1Char slashChar('/'); + if (!stylePath.isEmpty() && !stylePath.endsWith(slashChar)) + stylePath += slashChar; + + QString androidTheme = QLatin1String(qgetenv("QT_ANDROID_THEME")); + if (!androidTheme.isEmpty() && !androidTheme.endsWith(slashChar)) + androidTheme += slashChar; + + if (stylePath.isEmpty()) { + stylePath = QLatin1String("/data/data/org.kde.necessitas.ministro/files/dl/style/") + + QLatin1String(qgetenv("QT_ANDROID_THEME_DISPLAY_DPI")) + slashChar; + } + Q_ASSERT(!stylePath.isEmpty()); + + if (!androidTheme.isEmpty() && QFileInfo(stylePath + androidTheme + QLatin1String("style.json")).exists()) + stylePath += androidTheme; + + QFile f(stylePath + QLatin1String("style.json")); + if (!f.open(QIODevice::ReadOnly)) + return std::shared_ptr<AndroidStyle>(); + + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(f.readAll(), &error); + if (document.isNull()) { + qCritical() << error.errorString(); + return std::shared_ptr<AndroidStyle>(); + } + + if (!document.isObject()) { + qCritical() << "Style.json does not contain a valid style."; + return std::shared_ptr<AndroidStyle>(); + } + std::shared_ptr<AndroidStyle> style(new AndroidStyle); + style->m_styleData = document.object(); + for (QJsonObject::const_iterator objectIterator = style->m_styleData.constBegin(); + objectIterator != style->m_styleData.constEnd(); + ++objectIterator) { + QString key = objectIterator.key(); + QJsonValue value = objectIterator.value(); + if (!value.isObject()) { + qWarning("Style.json structure is unrecognized."); + continue; + } + QJsonObject item = value.toObject(); + QJsonObject::const_iterator attributeIterator = item.find(QLatin1String("qtClass")); + QByteArray qtClassName; + if (attributeIterator != item.constEnd()) { + // The item has palette and font information for a specific Qt Class (e.g. QWidget, QPushButton, etc.) + qtClassName = attributeIterator.value().toString().toLatin1(); + } + const int ft = fontType(key); + if (ft > -1 || !qtClassName.isEmpty()) { + // Extract font information + QFont font; + + // Font size (in pixels) + attributeIterator = item.find(QLatin1String("TextAppearance_textSize")); + if (attributeIterator != item.constEnd()) + font.setPixelSize(int(attributeIterator.value().toDouble())); + + // Font style + attributeIterator = item.find(QLatin1String("TextAppearance_textStyle")); + if (attributeIterator != item.constEnd()) { + const int style = int(attributeIterator.value().toDouble()); + font.setBold(style & textStyle_bold); + font.setItalic(style & textStyle_italic); + } + + // Font typeface + attributeIterator = item.find(QLatin1String("TextAppearance_typeface")); + if (attributeIterator != item.constEnd()) { + QFont::StyleHint styleHint = QFont::AnyStyle; + switch (int(attributeIterator.value().toDouble())) { + case typeface_sans: + styleHint = QFont::SansSerif; + break; + case typeface_serif: + styleHint = QFont::Serif; + break; + case typeface_monospace: + styleHint = QFont::Monospace; + break; + } + font.setStyleHint(styleHint, QFont::PreferMatch); + } + if (!qtClassName.isEmpty()) + style->m_QWidgetsFonts.insert(qtClassName, font); + + if (ft > -1) { + style->m_fonts.insert(ft, font); + if (ft == QPlatformTheme::SystemFont) + QGuiApplication::setFont(font); + } + // Extract font information + } + + const int pt = paletteType(key); + if (pt > -1 || !qtClassName.isEmpty()) { + // Extract palette information + QPalette palette; + attributeIterator = item.find(QLatin1String("defaultTextColorPrimary")); + if (attributeIterator != item.constEnd()) + palette.setColor(QPalette::WindowText, QRgb(int(attributeIterator.value().toDouble()))); + + attributeIterator = item.find(QLatin1String("defaultBackgroundColor")); + if (attributeIterator != item.constEnd()) + palette.setColor(QPalette::Background, QRgb(int(attributeIterator.value().toDouble()))); + + attributeIterator = item.find(QLatin1String("TextAppearance_textColor")); + if (attributeIterator != item.constEnd()) + setPaletteColor(attributeIterator.value().toObject().toVariantMap(), palette, QPalette::WindowText); + + attributeIterator = item.find(QLatin1String("TextAppearance_textColorLink")); + if (attributeIterator != item.constEnd()) + setPaletteColor(attributeIterator.value().toObject().toVariantMap(), palette, QPalette::Link); + + attributeIterator = item.find(QLatin1String("TextAppearance_textColorHighlight")); + if (attributeIterator != item.constEnd()) + palette.setColor(QPalette::Highlight, QRgb(int(attributeIterator.value().toDouble()))); + + if (pt == QPlatformTheme::SystemPalette) + *defaultPalette = style->m_standardPalette = palette; + + if (pt > -1) + style->m_palettes.insert(pt, palette); + // Extract palette information + } + } + return style; +} + QAndroidPlatformTheme::QAndroidPlatformTheme(QAndroidPlatformNativeInterface *androidPlatformNativeInterface) { - m_androidPlatformNativeInterface = androidPlatformNativeInterface; QColor background(229, 229, 229); QColor light = background.lighter(150); QColor mid(background.darker(130)); @@ -80,6 +344,9 @@ QAndroidPlatformTheme::QAndroidPlatformTheme(QAndroidPlatformNativeInterface *an m_defaultPalette.setBrush(QPalette::Active, QPalette::Highlight, highlight); m_defaultPalette.setBrush(QPalette::Inactive, QPalette::Highlight, highlight); m_defaultPalette.setBrush(QPalette::Disabled, QPalette::Highlight, highlight.lighter(150)); + m_androidStyleData = loadAndroidStyle(&m_defaultPalette); + QGuiApplication::setPalette(m_defaultPalette); + androidPlatformNativeInterface->m_androidStyle = m_androidStyleData; } QPlatformMenuBar *QAndroidPlatformTheme::createPlatformMenuBar() const @@ -132,9 +399,11 @@ static inline int paletteType(QPlatformTheme::Palette type) const QPalette *QAndroidPlatformTheme::palette(Palette type) const { - QHash<int, QPalette>::const_iterator it = m_androidPlatformNativeInterface->m_palettes.find(paletteType(type)); - if (it != m_androidPlatformNativeInterface->m_palettes.end()) - return &(it.value()); + if (m_androidStyleData) { + auto it = m_androidStyleData->m_palettes.find(paletteType(type)); + if (it != m_androidStyleData->m_palettes.end()) + return &(it.value()); + } return &m_defaultPalette; } @@ -154,9 +423,11 @@ static inline int fontType(QPlatformTheme::Font type) const QFont *QAndroidPlatformTheme::font(Font type) const { - QHash<int, QFont>::const_iterator it = m_androidPlatformNativeInterface->m_fonts.find(fontType(type)); - if (it != m_androidPlatformNativeInterface->m_fonts.end()) - return &(it.value()); + if (m_androidStyleData) { + auto it = m_androidStyleData->m_fonts.find(fontType(type)); + if (it != m_androidStyleData->m_fonts.end()) + return &(it.value()); + } // default in case the style has not set a font static QFont systemFont("Roboto", 14.0 * 100 / 72); // keep default size the same after changing from 100 dpi to 72 dpi @@ -165,18 +436,12 @@ const QFont *QAndroidPlatformTheme::font(Font type) const return 0; } -static const QLatin1String STYLES_PATH("/data/data/org.kde.necessitas.ministro/files/dl/style/"); -static const QLatin1String STYLE_FILE("/style.json"); - QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const { switch (hint) { case StyleNames: if (qgetenv("QT_USE_ANDROID_NATIVE_STYLE").toInt() - && (!qgetenv("MINISTRO_ANDROID_STYLE_PATH").isEmpty() - || QFileInfo(STYLES_PATH - + QLatin1String(qgetenv("QT_ANDROID_THEME_DISPLAY_DPI")) - + STYLE_FILE).exists())) { + && m_androidStyleData) { return QStringList("android"); } return QStringList("fusion"); diff --git a/src/plugins/platforms/android/qandroidplatformtheme.h b/src/plugins/platforms/android/qandroidplatformtheme.h index 01611bf9d4..334e86ad7a 100644 --- a/src/plugins/platforms/android/qandroidplatformtheme.h +++ b/src/plugins/platforms/android/qandroidplatformtheme.h @@ -37,8 +37,22 @@ #include <qpa/qplatformtheme.h> #include <QtGui/qpalette.h> +#include <QJsonObject> + +#include <memory> + QT_BEGIN_NAMESPACE +struct AndroidStyle +{ + QJsonObject m_styleData; + QPalette m_standardPalette; + QHash<int, QPalette> m_palettes; + QHash<int, QFont> m_fonts; + QHash<QByteArray, QFont> m_QWidgetsFonts; + QHash<QByteArray, QFont> m_QWidgetsPalettes; +}; + class QAndroidPlatformNativeInterface; class QAndroidPlatformTheme: public QPlatformTheme { @@ -57,7 +71,7 @@ public: private: - QAndroidPlatformNativeInterface * m_androidPlatformNativeInterface; + std::shared_ptr<AndroidStyle> m_androidStyleData; QPalette m_defaultPalette; }; diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm index f684fef233..a58514614b 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm @@ -412,7 +412,10 @@ void QMacPrintEngine::drawTextItem(const QPointF &p, const QTextItem &ti) { Q_D(QMacPrintEngine); Q_ASSERT(d->state == QPrinter::Active); - d->paintEngine->drawTextItem(p, ti); + if (!d->embedFonts) + QPaintEngine::drawTextItem(p, ti); + else + d->paintEngine->drawTextItem(p, ti); } void QMacPrintEngine::drawTiledPixmap(const QRectF &dr, const QPixmap &pixmap, const QPointF &sr) @@ -457,8 +460,6 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va break; case PPK_CustomBase: break; - case PPK_FontEmbedding: - break; case PPK_PageOrder: // TODO Check if can be supported via Cups Options break; @@ -471,6 +472,9 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va break; // The following keys are properties and settings that are supported by the Mac PrintEngine + case PPK_FontEmbedding: + d->embedFonts = value.toBool(); + break; case PPK_Resolution: { // TODO It appears the old code didn't actually set the resolution??? Can we delete all this??? int bestResolution = 0; @@ -622,9 +626,6 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const case PPK_CustomBase: // Special case, leave null break; - case PPK_FontEmbedding: - ret = false; - break; case PPK_PageOrder: // TODO Check if can be supported via Cups Options ret = QPrinter::FirstPageFirst; @@ -648,6 +649,9 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const break; // The following keys are properties and settings that are supported by the Mac PrintEngine + case PPK_FontEmbedding: + ret = d->embedFonts; + break; case PPK_CollateCopies: { Boolean status; PMGetCollate(d->settings(), &status); diff --git a/src/plugins/platforms/cocoa/qprintengine_mac_p.h b/src/plugins/platforms/cocoa/qprintengine_mac_p.h index c7307688ae..c99069b7f7 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac_p.h +++ b/src/plugins/platforms/cocoa/qprintengine_mac_p.h @@ -124,10 +124,11 @@ public: QString m_creator; QPaintEngine *paintEngine; QHash<QMacPrintEngine::PrintEnginePropertyKey, QVariant> valueCache; + uint embedFonts; QMacPrintEnginePrivate() : mode(QPrinter::ScreenResolution), state(QPrinter::Idle), m_pageLayout(QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0, 0, 0, 0))), - printInfo(0), paintEngine(0) {} + printInfo(0), paintEngine(0), embedFonts(true) {} ~QMacPrintEnginePrivate(); void initialize(); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp index 142362a065..351f94be2b 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp @@ -39,6 +39,7 @@ #include "qwindowsdirect2dwindow.h" #include "qwindowscontext.h" +#include "qwindowsguieventdispatcher.h" #include <qplatformdefs.h> #include <QtCore/QCoreApplication> @@ -47,6 +48,16 @@ QT_BEGIN_NAMESPACE +class QWindowsDirect2DEventDispatcher : public QWindowsGuiEventDispatcher +{ +public: + QWindowsDirect2DEventDispatcher(QObject *parent = 0) + : QWindowsGuiEventDispatcher(parent) + { + uninstallMessageHook(); // ### Workaround for QTBUG-42428 + } +}; + class QWindowsDirect2DIntegrationPrivate { public: @@ -237,6 +248,11 @@ QPlatformBackingStore *QWindowsDirect2DIntegration::createPlatformBackingStore(Q return new QWindowsDirect2DBackingStore(window); } +QAbstractEventDispatcher *QWindowsDirect2DIntegration::createEventDispatcher() const +{ + return new QWindowsDirect2DEventDispatcher; +} + QWindowsDirect2DContext *QWindowsDirect2DIntegration::direct2DContext() const { return &d->m_d2dContext; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h index b410464372..c72b22a6e8 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h @@ -56,6 +56,7 @@ public: QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const Q_DECL_OVERRIDE; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; + QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; QWindowsDirect2DContext *direct2DContext() const; diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index c83b894089..f5839e086d 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -103,7 +103,7 @@ void QEglFSWindow::create() if (isRaster()) { QOpenGLContext *context = new QOpenGLContext(QGuiApplication::instance()); - context->setFormat(window()->requestedFormat()); + context->setFormat(m_format); context->setScreen(window()->screen()); if (!context->create()) qFatal("EGLFS: Failed to create compositing context"); diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index 9f10c3e287..3ecd0ca61f 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -141,6 +141,11 @@ int infoPlistValue(NSString* key, int defaultValue) @end @implementation QtFirstResponderEvent +- (void) dealloc +{ + self.firstResponder = 0; + [super dealloc]; +} @end diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h index 1f1130f932..d2a9c261ba 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.h +++ b/src/plugins/platforms/ios/qiosinputcontext.h @@ -85,15 +85,12 @@ public: const ImeState &imeState() { return m_imeState; }; bool inputMethodAccepted() const; - bool isReloadingInputViewsFromUpdate() const { return m_isReloadingInputViewsFromUpdate; } - static QIOSInputContext *instance(); private: QIOSKeyboardListener *m_keyboardListener; QIOSTextInputResponder *m_textResponder; ImeState m_imeState; - bool m_isReloadingInputViewsFromUpdate; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 072a49c7c5..e417e9a1fb 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -330,7 +330,6 @@ QIOSInputContext::QIOSInputContext() : QPlatformInputContext() , m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this]) , m_textResponder(0) - , m_isReloadingInputViewsFromUpdate(false) { if (isQtApplication()) connect(qGuiApp->inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QIOSInputContext::cursorRectangleChanged); @@ -540,10 +539,11 @@ void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties) [m_textResponder autorelease]; m_textResponder = [[QIOSTextInputResponder alloc] initWithInputContext:this]; [m_textResponder becomeFirstResponder]; + } else if ([UIResponder currentFirstResponder] == m_textResponder) { + qImDebug() << "IM not enabled, resigning text responder as first responder"; + [m_textResponder resignFirstResponder]; } else { - qImDebug() << "IM not enabled, reloading input views"; - QScopedValueRollback<bool> recursionGuard(m_isReloadingInputViewsFromUpdate, true); - [[UIResponder currentFirstResponder] reloadInputViews]; + qImDebug() << "IM not enabled. Text responder not first responder. Nothing to do"; } } else { [m_textResponder notifyInputDelegate:changedProperties]; @@ -594,22 +594,3 @@ void QIOSInputContext::commit() [m_textResponder unmarkText]; [m_textResponder notifyInputDelegate:Qt::ImSurroundingText]; } - -// ------------------------------------------------------------------------- - -@interface QUIView (InputMethods) -- (void)reloadInputViews; -@end - -@implementation QUIView (InputMethods) -- (void)reloadInputViews -{ - if (QIOSInputContext::instance()->isReloadingInputViewsFromUpdate()) { - qImDebug() << "preventing recursion by reloading super"; - [super reloadInputViews]; - } else { - qImDebug() << "reseting input methods"; - qApp->inputMethod()->reset(); - } -} -@end diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm index 005b06547e..0f351f785b 100644 --- a/src/plugins/platforms/ios/qiosmenu.mm +++ b/src/plugins/platforms/ios/qiosmenu.mm @@ -153,13 +153,29 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; [self setDelegate:self]; [self setDataSource:self]; [self selectRow:m_selectedRow inComponent:0 animated:false]; + [self listenForKeyboardWillHideNotification:YES]; } return self; } +-(void)listenForKeyboardWillHideNotification:(BOOL)listen +{ + if (listen) { + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(cancelMenu) + name:@"UIKeyboardWillHideNotification" object:nil]; + } else { + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:@"UIKeyboardWillHideNotification" object:nil]; + } +} + -(void)dealloc { + [self listenForKeyboardWillHideNotification:NO]; self.toolbar = 0; [super dealloc]; } @@ -193,6 +209,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; - (void)closeMenu { + [self listenForKeyboardWillHideNotification:NO]; if (!m_visibleMenuItems.isEmpty()) QIOSMenu::currentMenu()->handleItemSelected(m_visibleMenuItems.at(m_selectedRow)); else @@ -201,6 +218,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; - (void)cancelMenu { + [self listenForKeyboardWillHideNotification:NO]; QIOSMenu::currentMenu()->dismiss(); } @@ -452,11 +470,11 @@ void QIOSMenu::toggleShowUsingUIPickerView(bool show) Q_ASSERT(!focusObjectWithPickerView); focusObjectWithPickerView = qApp->focusWindow()->focusObject(); focusObjectWithPickerView->installEventFilter(this); - qApp->inputMethod()->update(Qt::ImPlatformData); + qApp->inputMethod()->update(Qt::ImEnabled | Qt::ImPlatformData); } else { Q_ASSERT(focusObjectWithPickerView); focusObjectWithPickerView->removeEventFilter(this); - qApp->inputMethod()->update(Qt::ImPlatformData); + qApp->inputMethod()->update(Qt::ImEnabled | Qt::ImPlatformData); focusObjectWithPickerView = 0; Q_ASSERT(m_pickerView); @@ -477,6 +495,7 @@ bool QIOSMenu::eventFilter(QObject *obj, QEvent *event) imPlatformData.insert(kImePlatformDataInputView, QVariant::fromValue(static_cast<void *>(m_pickerView))); imPlatformData.insert(kImePlatformDataInputAccessoryView, QVariant::fromValue(static_cast<void *>(m_pickerView.toolbar))); queryEvent->setValue(Qt::ImPlatformData, imPlatformData); + queryEvent->setValue(Qt::ImEnabled, true); return true; } diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index e3c73f5222..2fcc7258f7 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -268,8 +268,11 @@ qImDebug() << "keyboard was closed, clearing focus object"; m_inputContext->clearCurrentFocusObject(); } else { - // We've lost responder status because another window was made active - Q_ASSERT(FirstResponderCandidate::currentCandidate()); + // We've lost responder status because another Qt window was made active, + // another QIOSTextResponder was made first-responder, another UIView was + // made first-responder, or the first-responder was cleared globally. In + // either of these cases we don't have to do anything. + qImDebug() << "lost first responder, but not clearing focus object"; } return YES; @@ -282,21 +285,6 @@ reinterpret_cast<QUIView *>(qApp->focusWindow()->handle()->winId()) : 0; } -/*! - iOS uses [UIResponder(Internal) _requiresKeyboardWhenFirstResponder] to check if the - current responder should bring up the keyboard, which in turn checks if the responder - supports the UIKeyInput protocol. By dynamically reporting our protocol conformance - we can control the keyboard visibility depending on whether or not we have a focus - object with IME enabled. -*/ -- (BOOL)conformsToProtocol:(Protocol *)protocol -{ - if (protocol == @protocol(UIKeyInput)) - return m_inputContext->inputMethodAccepted(); - - return [super conformsToProtocol:protocol]; -} - // ------------------------------------------------------------------------- - (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index 3b277c0b5a..c0d0c1f77c 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -360,10 +360,10 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create() EGLDisplay display = EGL_NO_DISPLAY; #ifdef EGL_ANGLE_platform_angle_opengl if (libEGL.eglGetPlatformDisplayEXT && qEnvironmentVariableIsSet("QT_ANGLE_PLATFORM")) { - const EGLint anglePlatformAttributes[][3] = { + const EGLint anglePlatformAttributes[][5] = { { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE }, { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, EGL_NONE }, - { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE, EGL_NONE } + { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_USE_WARP_ANGLE, EGL_TRUE, EGL_NONE } }; const EGLint *attributes = 0; const QByteArray anglePlatform = qgetenv("QT_ANGLE_PLATFORM"); diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp index 5daeee69c0..64aedb1b33 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp @@ -35,8 +35,8 @@ QT_BEGIN_NAMESPACE -QWinRTEGLContext::QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface) - : QEGLPlatformContext(format, share, display), m_eglSurface(surface) +QWinRTEGLContext::QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config) + : QEGLPlatformContext(format, share, display, &config), m_eglSurface(surface) { } diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.h b/src/plugins/platforms/winrt/qwinrteglcontext.h index fb1199a79e..142e204fc8 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.h +++ b/src/plugins/platforms/winrt/qwinrteglcontext.h @@ -41,7 +41,7 @@ QT_BEGIN_NAMESPACE class QWinRTEGLContext : public QEGLPlatformContext { public: - explicit QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface); + explicit QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config); QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index b8ca9fdc66..4fa90b4b68 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -110,7 +110,7 @@ QPlatformBackingStore *QWinRTIntegration::createPlatformBackingStore(QWindow *wi QPlatformOpenGLContext *QWinRTIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { QWinRTScreen *screen = static_cast<QWinRTScreen *>(context->screen()->handle()); - return new QWinRTEGLContext(context->format(), context->handle(), screen->eglDisplay(), screen->eglSurface()); + return new QWinRTEGLContext(context->format(), context->handle(), screen->eglDisplay(), screen->eglSurface(), screen->eglConfig()); } QPlatformFontDatabase *QWinRTIntegration::fontDatabase() const diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 3933902ae3..fadcd01b06 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -33,6 +33,11 @@ #include "qwinrtscreen.h" +#define EGL_EGLEXT_PROTOTYPES +#include <EGL/eglext.h> +#include <d3d11.h> +#include <dxgi1_2.h> + #include "qwinrtbackingstore.h" #include "qwinrtinputcontext.h" #include "qwinrtcursor.h" @@ -452,6 +457,7 @@ public: EGLDisplay eglDisplay; EGLSurface eglSurface; + EGLConfig eglConfig; QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens; QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens; @@ -467,6 +473,7 @@ QWinRTScreen::QWinRTScreen() Q_D(QWinRTScreen); d->orientation = Qt::PrimaryOrientation; d->touchDevice = Q_NULLPTR; + d->eglDisplay = EGL_NO_DISPLAY; // Obtain the WinRT Application, view, and window HRESULT hr; @@ -525,8 +532,10 @@ QWinRTScreen::QWinRTScreen() Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]); Q_ASSERT_SUCCEEDED(hr); +#ifndef Q_OS_WINPHONE hr = d->coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]); Q_ASSERT_SUCCEEDED(hr); +#endif 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]); @@ -575,7 +584,43 @@ QWinRTScreen::QWinRTScreen() if (!eglInitialize(d->eglDisplay, NULL, NULL)) qCritical("Failed to initialize EGL: 0x%x", eglGetError()); - d->eglSurface = eglCreateWindowSurface(d->eglDisplay, q_configFromGLFormat(d->eglDisplay, d->surfaceFormat), d->coreWindow.Get(), NULL); + // Check that the device properly supports depth/stencil rendering, and disable them if not + ComPtr<ID3D11Device> d3dDevice; + const EGLBoolean ok = eglQuerySurfacePointerANGLE(d->eglDisplay, EGL_NO_SURFACE, EGL_DEVICE_EXT, (void **)d3dDevice.GetAddressOf()); + if (ok && d3dDevice) { + ComPtr<IDXGIDevice> dxgiDevice; + hr = d3dDevice.As(&dxgiDevice); + if (SUCCEEDED(hr)) { + ComPtr<IDXGIAdapter> dxgiAdapter; + hr = dxgiDevice->GetAdapter(&dxgiAdapter); + if (SUCCEEDED(hr)) { + ComPtr<IDXGIAdapter2> dxgiAdapter2; + hr = dxgiAdapter.As(&dxgiAdapter2); + if (SUCCEEDED(hr)) { + DXGI_ADAPTER_DESC2 desc; + hr = dxgiAdapter2->GetDesc2(&desc); + if (SUCCEEDED(hr)) { + // The following GPUs do not render properly with depth/stencil + if ((desc.VendorId == 0x4d4f4351 && desc.DeviceId == 0x32303032)) { // Qualcomm Adreno 225 + d->surfaceFormat.setDepthBufferSize(-1); + d->surfaceFormat.setStencilBufferSize(-1); + } + } + } + } + } + } + + d->eglConfig = q_configFromGLFormat(d->eglDisplay, d->surfaceFormat); + d->surfaceFormat = q_glFormatFromConfig(d->eglDisplay, d->eglConfig, d->surfaceFormat); + const QRect bounds = geometry(); + EGLint windowAttributes[] = { + EGL_FIXED_SIZE_ANGLE, EGL_TRUE, + EGL_WIDTH, bounds.width(), + EGL_HEIGHT, bounds.height(), + EGL_NONE + }; + d->eglSurface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, d->coreWindow.Get(), windowAttributes); if (d->eglSurface == EGL_NO_SURFACE) qCritical("Failed to create EGL window surface: 0x%x", eglGetError()); } @@ -706,6 +751,12 @@ EGLSurface QWinRTScreen::eglSurface() const return d->eglSurface; } +EGLConfig QWinRTScreen::eglConfig() const +{ + Q_D(const QWinRTScreen); + return d->eglConfig; +} + QWindow *QWinRTScreen::topWindow() const { Q_D(const QWinRTScreen); @@ -1010,26 +1061,33 @@ HRESULT QWinRTScreen::onAutomationProviderRequested(ICoreWindow *, IAutomationPr return S_OK; } -HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *args) +HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *) { Q_D(QWinRTScreen); - Size size; - HRESULT hr = args->get_Size(&size); - RETURN_OK_IF_FAILED("Failed to get window size."); - + Rect size; + HRESULT hr; + hr = d->coreWindow->get_Bounds(&size); + RETURN_OK_IF_FAILED("Failed to get window bounds"); QSizeF logicalSize = QSizeF(size.Width, size.Height); +#ifndef Q_OS_WINPHONE // This handler is called from orientation changed, in which case we should always update the size if (d->logicalSize == logicalSize) return S_OK; +#endif - // Regardless of state, all top-level windows are viewport-sized - this might change if - // a more advanced compositor is written. d->logicalSize = logicalSize; - const QRect newGeometry = geometry(); - QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); - QPlatformScreen::resizeMaximizedWindows(); - handleExpose(); - + if (d->eglDisplay) { + const QRect newGeometry = geometry(); +#ifdef Q_OS_WINPHONE // Resize the EGL window + const int width = newGeometry.width() * (d->orientation == Qt::InvertedPortraitOrientation || d->orientation == Qt::LandscapeOrientation ? -1 : 1); + const int height = newGeometry.height() * (d->orientation == Qt::InvertedPortraitOrientation || d->orientation == Qt::InvertedLandscapeOrientation ? -1 : 1); + eglSurfaceAttrib(d->eglDisplay, d->eglSurface, EGL_WIDTH, width); + eglSurfaceAttrib(d->eglDisplay, d->eglSurface, EGL_HEIGHT, height); +#endif + QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); + QPlatformScreen::resizeMaximizedWindows(); + handleExpose(); + } return S_OK; } @@ -1099,6 +1157,9 @@ HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable * QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation); } +#ifdef Q_OS_WINPHONE // The size changed handler is ignored in favor of this callback + onSizeChanged(Q_NULLPTR, Q_NULLPTR); +#endif return S_OK; } diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index e70a998216..c95a2073ed 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -109,6 +109,7 @@ public: ABI::Windows::UI::Core::ICoreWindow *coreWindow() const; EGLDisplay eglDisplay() const; // To opengl context EGLSurface eglSurface() const; // To window + EGLConfig eglConfig() const; private: void handleExpose(); |