summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2013-11-26 22:30:27 +0100
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2013-11-26 22:35:48 +0100
commit4a8273a6fc2e741e811cf5dabc9a3c240306cf7f (patch)
tree2148abc88f8543eecdc0b97b2dd92594836af9b2 /src/plugins
parent036c5db468164297d213764c59a4b59daa76d90a (diff)
parent1c2be58fecaff1de5f2849192eb712984ebd59bd (diff)
Merge remote-tracking branch 'origin/stable' into dev
For the conflicts in msvc_nmake.cpp the ifdefs are extended since we need to support windows phone in the target branch while it is not there in the current stable branch (as of Qt 5.2). Conflicts: configure qmake/generators/win32/msvc_nmake.cpp src/3rdparty/angle/src/libEGL/Surface.cpp src/angle/src/common/common.pri src/corelib/global/qglobal.h src/corelib/io/qstandardpaths.cpp src/plugins/platforms/qnx/qqnxintegration.cpp src/plugins/platforms/qnx/qqnxscreeneventhandler.h src/plugins/platforms/xcb/qglxintegration.h src/widgets/kernel/win.pri tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp tools/configure/configureapp.cpp Change-Id: I00b579eefebaf61d26ab9b00046d2b5bd5958812
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/accessible/widgets/complexwidgets.cpp35
-rw-r--r--src/plugins/accessible/widgets/complexwidgets.h3
-rw-r--r--src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp64
-rw-r--r--src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h1
-rw-r--r--src/plugins/platforms/android/opengl/opengl.pro6
-rw-r--r--src/plugins/platforms/android/src/androidjniaccessibility.cpp2
-rw-r--r--src/plugins/platforms/android/src/androidjniinput.cpp51
-rw-r--r--src/plugins/platforms/android/src/androidjnimain.cpp84
-rw-r--r--src/plugins/platforms/android/src/androidjnimain.h6
-rw-r--r--src/plugins/platforms/android/src/androidjnimenu.cpp36
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp2
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglplatformscreen.cpp61
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglplatformscreen.h (renamed from src/plugins/platforms/qnx/qqnxrootwindow.h)45
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp32
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h3
-rw-r--r--src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp5
-rw-r--r--src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp73
-rw-r--r--src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h8
-rw-r--r--src/plugins/platforms/android/src/qandroidinputcontext.cpp5
-rw-r--r--src/plugins/platforms/android/src/qandroidinputcontext.h1
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformdialoghelpers.cpp204
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformdialoghelpers.h77
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformintegration.cpp24
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformintegration.h5
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenu.cpp10
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenu.h1
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenubar.cpp2
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformtheme.cpp20
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformtheme.h3
-rw-r--r--src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp7
-rw-r--r--src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp35
-rw-r--r--src/plugins/platforms/android/src/raster/qandroidplatformwindow.h4
-rw-r--r--src/plugins/platforms/android/src/src.pri2
-rw-r--r--src/plugins/platforms/cocoa/images/sizeallcursor.pngbin0 -> 703 bytes
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm13
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm3
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm1
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm79
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm95
-rw-r--r--src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm1
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm140
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm12
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm1
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm27
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm1
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaresources.qrc2
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h6
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm40
-rw-r--r--src/plugins/platforms/cocoa/qmacclipboard.mm7
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm70
-rw-r--r--src/plugins/platforms/cocoa/qnsviewaccessibility.mm2
-rw-r--r--src/plugins/platforms/eglfs/qeglfsbackingstore.cpp5
-rw-r--r--src/plugins/platforms/eglfs/qeglfsbackingstore.h3
-rw-r--r--src/plugins/platforms/eglfs/qeglfscompositor.cpp7
-rw-r--r--src/plugins/platforms/eglfs/qeglfscompositor.h6
-rw-r--r--src/plugins/platforms/eglfs/qeglfscursor.cpp5
-rw-r--r--src/plugins/platforms/eglfs/qeglfscursor.h7
-rw-r--r--src/plugins/platforms/eglfs/qeglfsintegration.cpp58
-rw-r--r--src/plugins/platforms/eglfs/qeglfsintegration.h3
-rw-r--r--src/plugins/platforms/eglfs/qeglfsscreen.cpp17
-rw-r--r--src/plugins/platforms/eglfs/qeglfsscreen.h1
-rw-r--r--src/plugins/platforms/eglfs/qeglfswindow.cpp6
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.h1
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.mm26
-rw-r--r--src/plugins/platforms/ios/qiosbackingstore.mm10
-rw-r--r--src/plugins/platforms/ios/qioscontext.h8
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm24
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.h2
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm38
-rw-r--r--src/plugins/platforms/ios/qiosglobal.h10
-rw-r--r--src/plugins/platforms/ios/qiosglobal.mm23
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.h9
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm156
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm7
-rw-r--r--src/plugins/platforms/ios/qiosscreen.h11
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm146
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.h1
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm52
-rw-r--r--src/plugins/platforms/ios/qioswindow.h20
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm384
-rw-r--r--src/plugins/platforms/kms/qkmsbackingstore.cpp6
-rw-r--r--src/plugins/platforms/kms/qkmsbackingstore.h4
-rw-r--r--src/plugins/platforms/kms/qkmsscreen.h3
-rw-r--r--src/plugins/platforms/qnx/qnx.pro19
-rw-r--r--src/plugins/platforms/qnx/qqnxeglwindow.cpp29
-rw-r--r--src/plugins/platforms/qnx/qqnxeglwindow.h6
-rw-r--r--src/plugins/platforms/qnx/qqnxglcontext.h2
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp19
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.h5
-rw-r--r--src/plugins/platforms/qnx/qqnxnativeinterface.cpp19
-rw-r--r--src/plugins/platforms/qnx/qqnxnativeinterface.h2
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterwindow.cpp16
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterwindow.h7
-rw-r--r--src/plugins/platforms/qnx/qqnxrootwindow.cpp268
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.cpp151
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.h10
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp108
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.h17
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventthread.cpp40
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventthread.h13
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.cpp182
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.h32
-rw-r--r--src/plugins/platforms/windows/accessible/iaccessible2.cpp2
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp1
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp1
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h5
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.cpp18
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp19
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp13
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.h1
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.cpp91
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.h2
-rw-r--r--src/plugins/platforms/windows/qwindowssessionmanager.cpp34
-rw-r--r--src/plugins/platforms/windows/qwindowssessionmanager.h13
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp19
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.cpp80
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp27
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h4
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp12
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h1
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp25
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h4
-rw-r--r--src/plugins/platformthemes/gtk2/qgtk2theme.cpp12
128 files changed, 2665 insertions, 1159 deletions
diff --git a/src/plugins/accessible/widgets/complexwidgets.cpp b/src/plugins/accessible/widgets/complexwidgets.cpp
index c0d62ccc16..b1df6d816a 100644
--- a/src/plugins/accessible/widgets/complexwidgets.cpp
+++ b/src/plugins/accessible/widgets/complexwidgets.cpp
@@ -221,41 +221,6 @@ QString QAccessibleTabBar::text(QAccessible::Text t) const
return QString();
}
-/*!
- Selects the item with index \a child if \a on is true; otherwise
- unselects it. If \a extend is true and the selection mode is not
- \c Single and there is an existing selection, the selection is
- extended to include all the items from the existing selection up
- to and including the item with index \a child. Returns \c true if a
- selection was made or extended; otherwise returns \c false.
-
- \sa selection(), clearSelection()
-*/
-bool QAccessibleTabBar::setSelected(int child, bool on, bool extend)
-{
- if (!child || !on || extend || child > tabBar()->count())
- return false;
-
- if (!tabBar()->isTabEnabled(child - 1))
- return false;
- tabBar()->setCurrentIndex(child - 1);
- return true;
-}
-
-/*!
- Returns a (possibly empty) list of indexes of the items selected
- in the list box.
-
- \sa setSelected(), clearSelection()
-*/
-QVector<int> QAccessibleTabBar::selection() const
-{
- QVector<int> array;
- if (tabBar()->currentIndex() != -1)
- array +=tabBar()->currentIndex() + 1;
- return array;
-}
-
#endif // QT_NO_TABBAR
#ifndef QT_NO_COMBOBOX
diff --git a/src/plugins/accessible/widgets/complexwidgets.h b/src/plugins/accessible/widgets/complexwidgets.h
index 164bc5b6d9..00186282f3 100644
--- a/src/plugins/accessible/widgets/complexwidgets.h
+++ b/src/plugins/accessible/widgets/complexwidgets.h
@@ -105,9 +105,6 @@ public:
int childCount() const Q_DECL_OVERRIDE;
QString text(QAccessible::Text t) const Q_DECL_OVERRIDE;
- bool setSelected(int child, bool on, bool extend);
- QVector<int> selection() const;
-
QAccessibleInterface* child(int index) const Q_DECL_OVERRIDE;
int indexOfChild(const QAccessibleInterface *child) const Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp
index 459a450222..3d1b281620 100644
--- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp
+++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp
@@ -101,7 +101,6 @@ void TableGenerator::findComposeFile()
qDebug() << "Using Compose file from: " << composeFile;
#endif
}
-
// check if user’s home directory has a file named .XCompose
if (!found && cleanState()) {
QString composeFile = qgetenv("HOME") + QStringLiteral("/.XCompose");
@@ -112,10 +111,12 @@ void TableGenerator::findComposeFile()
qDebug() << "Using Compose file from: " << composeFile;
#endif
}
-
// check for the system provided compose files
if (!found && cleanState()) {
- QString table = readLocaleMappings(locale().toUpper().toUtf8());
+ QByteArray loc = locale().toUpper().toUtf8();
+ QString table = readLocaleMappings(loc);
+ if (table.isEmpty())
+ table = readLocaleMappings(readLocaleAliases(loc));
if (cleanState()) {
if (table.isEmpty())
@@ -178,8 +179,11 @@ QString TableGenerator::locale() const
QString TableGenerator::readLocaleMappings(const QByteArray &locale)
{
- QFile mappings(systemComposeDir() + QLatin1String("/compose.dir"));
QString file;
+ if (locale.isEmpty())
+ return file;
+
+ QFile mappings(systemComposeDir() + QLatin1String("/compose.dir"));
if (mappings.open(QIODevice::ReadOnly)) {
const int localeNameLength = locale.size();
const char * const localeData = locale.constData();
@@ -209,9 +213,8 @@ QString TableGenerator::readLocaleMappings(const QByteArray &locale)
while (*line && *line != ' ' && *line != '\t' && *line != '\n')
++line;
*line = '\0';
-
if (localeNameLength == (line - lc) && !strncasecmp(lc, localeData, line - lc)) {
- file = QString::fromUtf8(l, composeFileNameEnd - l);
+ file = QString::fromLocal8Bit(l, composeFileNameEnd - l);
break;
}
}
@@ -221,6 +224,47 @@ QString TableGenerator::readLocaleMappings(const QByteArray &locale)
return file;
}
+QByteArray TableGenerator::readLocaleAliases(const QByteArray &locale)
+{
+ QFile aliases(systemComposeDir() + QLatin1String("/locale.alias"));
+ QByteArray fullLocaleName;
+ if (aliases.exists()) {
+ aliases.open(QIODevice::ReadOnly);
+ while (!aliases.atEnd()) {
+ char l[1024];
+ int read = aliases.readLine(l, sizeof(l));
+ char *line = l;
+ if (read && ((*line >= 'a' && *line <= 'z') ||
+ (*line >= 'A' && *line <= 'Z'))) {
+ const char *alias = line;
+ while (*line && *line != ':' && *line != ' ' && *line != '\t')
+ ++line;
+ if (!*line)
+ continue;
+ *line = 0;
+ if (locale.size() == (line - alias)
+ && !strncasecmp(alias, locale.constData(), line - alias)) {
+ // found a match for alias, read the real locale name
+ ++line;
+ while (*line && (*line == ' ' || *line == '\t'))
+ ++line;
+ const char *fullName = line;
+ while (*line && *line != ' ' && *line != '\t' && *line != '\n')
+ ++line;
+ *line = 0;
+ fullLocaleName = fullName;
+#ifdef DEBUG_GENERATOR
+ qDebug() << "Alias for: " << alias << "is: " << fullLocaleName;
+ break;
+#endif
+ }
+ }
+ }
+ aliases.close();
+ }
+ return fullLocaleName;
+}
+
bool TableGenerator::processFile(QString composeFileName)
{
QFile composeFile(composeFileName);
@@ -255,7 +299,7 @@ void TableGenerator::parseComposeFile(QFile *composeFile)
if (*line == '<')
parseKeySequence(line);
else if (!strncmp(line, "include", 7))
- parseIncludeInstruction(QString::fromUtf8(line));
+ parseIncludeInstruction(QString::fromLocal8Bit(line));
}
composeFile->close();
@@ -309,7 +353,7 @@ ushort TableGenerator::keysymToUtf8(quint32 sym)
qDebug() << QString("keysym - 0x%1 : utf8 - %2").arg(QString::number(sym, 16))
.arg(codec->toUnicode(chars));
#endif
- return QString::fromUtf8(chars).at(0).unicode();
+ return QString::fromLocal8Bit(chars).at(0).unicode();
}
static inline int fromBase8(const char *s, const char *end)
@@ -378,13 +422,13 @@ void TableGenerator::parseKeySequence(char *line)
// handle direct text encoded in the locale
if (*composeValue == '\\')
++composeValue;
- elem.value = QString::fromUtf8(composeValue).at(0).unicode();
+ elem.value = QString::fromLocal8Bit(composeValue).at(0).unicode();
++composeValue;
}
#ifdef DEBUG_GENERATOR
// find the comment
- elem.comment = QString::fromUtf8(composeValueEnd + 1).trimmed();
+ elem.comment = QString::fromLocal8Bit(composeValueEnd + 1).trimmed();
#endif
// find the key sequence and convert to X11 keysym
diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h
index aa65b7b895..248c09f3ea 100644
--- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h
+++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h
@@ -122,6 +122,7 @@ protected:
ushort keysymToUtf8(quint32 sym);
QString readLocaleMappings(const QByteArray &locale);
+ QByteArray readLocaleAliases(const QByteArray &locale);
void initPossibleLocations();
bool cleanState() const { return ((m_state & NoErrors) == NoErrors); }
QString locale() const;
diff --git a/src/plugins/platforms/android/opengl/opengl.pro b/src/plugins/platforms/android/opengl/opengl.pro
index 301c8e6e4c..ea050ca3a0 100644
--- a/src/plugins/platforms/android/opengl/opengl.pro
+++ b/src/plugins/platforms/android/opengl/opengl.pro
@@ -20,11 +20,13 @@ INCLUDEPATH += $$PWD/../src/opengl/
HEADERS += \
$$PWD/../src/opengl/qandroidopenglcontext.h \
- $$PWD/../src/opengl/qandroidopenglplatformwindow.h
+ $$PWD/../src/opengl/qandroidopenglplatformwindow.h \
+ $$PWD/../src/opengl/qandroidopenglplatformscreen.h
SOURCES += \
$$PWD/../src/opengl/qandroidopenglcontext.cpp \
- $$PWD/../src/opengl/qandroidopenglplatformwindow.cpp
+ $$PWD/../src/opengl/qandroidopenglplatformwindow.cpp \
+ $$PWD/../src/opengl/qandroidopenglplatformscreen.cpp
include($$PWD/../../eglfs/eglfs.pri)
include($$PWD/../src/src.pri)
diff --git a/src/plugins/platforms/android/src/androidjniaccessibility.cpp b/src/plugins/platforms/android/src/androidjniaccessibility.cpp
index a27d9f5aed..b987c49c9c 100644
--- a/src/plugins/platforms/android/src/androidjniaccessibility.cpp
+++ b/src/plugins/platforms/android/src/androidjniaccessibility.cpp
@@ -46,7 +46,7 @@
#include "qguiapplication.h"
#include "qwindow.h"
#include "qrect.h"
-#include "private/qaccessible2_p.h"
+#include "QtGui/qaccessible.h"
#include "qdebug.h"
diff --git a/src/plugins/platforms/android/src/androidjniinput.cpp b/src/plugins/platforms/android/src/androidjniinput.cpp
index 30d4e69afe..8ce95532d3 100644
--- a/src/plugins/platforms/android/src/androidjniinput.cpp
+++ b/src/plugins/platforms/android/src/androidjniinput.cpp
@@ -47,6 +47,10 @@
#include <QTouchEvent>
#include <QPointer>
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+# include <QDebug>
+#endif
+
using namespace QtAndroid;
namespace QtAndroidInput
@@ -63,12 +67,32 @@ namespace QtAndroidInput
static QPointer<QWindow> m_mouseGrabber;
+ static int m_lastCursorPos = -1;
+
void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
{
AttachedJNIEnv env;
if (!env.jniEnv)
return;
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << ">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd;
+#endif
+ if (candidatesStart == -1 && candidatesEnd == -1 && selStart == selEnd) {
+ // Qt only gives us position inside the block, so if we move to the
+ // same position in another block, the Android keyboard will believe
+ // we have not changed position, and be terribly confused.
+ if (selStart == m_lastCursorPos) {
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << ">>> FAKEUPDATESELECTION" << selStart+1;
+#endif
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), m_updateSelectionMethodID,
+ selStart+1, selEnd+1, candidatesStart, candidatesEnd);
+ }
+ m_lastCursorPos = selStart;
+ } else {
+ m_lastCursorPos = -1;
+ }
env.jniEnv->CallStaticVoidMethod(applicationClass(), m_updateSelectionMethodID,
selStart, selEnd, candidatesStart, candidatesEnd);
}
@@ -86,6 +110,9 @@ namespace QtAndroidInput
width,
height,
inputHints);
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints;
+#endif
}
void resetSoftwareKeyboard()
@@ -95,6 +122,9 @@ namespace QtAndroidInput
return;
env.jniEnv->CallStaticVoidMethod(applicationClass(), m_resetSoftwareKeyboardMethodID);
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ RESETSOFTWAREKEYBOARD";
+#endif
}
void hideSoftwareKeyboard()
@@ -104,6 +134,9 @@ namespace QtAndroidInput
return;
env.jniEnv->CallStaticVoidMethod(applicationClass(), m_hideSoftwareKeyboardMethodID);
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ HIDESOFTWAREKEYBOARD";
+#endif
}
bool isSoftwareKeyboardVisible()
@@ -112,7 +145,11 @@ namespace QtAndroidInput
if (!env.jniEnv)
return false;
- return env.jniEnv->CallStaticBooleanMethod(applicationClass(), m_isSoftwareKeyboardVisibleMethodID);
+ bool visibility = env.jniEnv->CallStaticBooleanMethod(applicationClass(), m_isSoftwareKeyboardVisibleMethodID);
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ ISSOFTWAREKEYBOARDVISIBLE" << visibility;
+#endif
+ return visibility;
}
@@ -511,6 +548,15 @@ namespace QtAndroidInput
false);
}
+ static void keyboardVisibilityChanged(JNIEnv */*env*/, jobject /*thiz*/, jboolean /*visibility*/)
+ {
+ QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
+ if (inputContext)
+ inputContext->emitInputPanelVisibleChanged();
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
+#endif
+ }
static JNINativeMethod methods[] = {
{"touchBegin","(I)V",(void*)touchBegin},
@@ -521,7 +567,8 @@ namespace QtAndroidInput
{"mouseMove", "(III)V", (void *)mouseMove},
{"longPress", "(III)V", (void *)longPress},
{"keyDown", "(III)V", (void *)keyDown},
- {"keyUp", "(III)V", (void *)keyUp}
+ {"keyUp", "(III)V", (void *)keyUp},
+ {"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged}
};
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
diff --git a/src/plugins/platforms/android/src/androidjnimain.cpp b/src/plugins/platforms/android/src/androidjnimain.cpp
index 5c9ca798a8..3064e5d4e2 100644
--- a/src/plugins/platforms/android/src/androidjnimain.cpp
+++ b/src/plugins/platforms/android/src/androidjnimain.cpp
@@ -40,6 +40,7 @@
**
****************************************************************************/
+#include <QtGui/private/qguiapplication_p.h>
#include <dlfcn.h>
#include <pthread.h>
@@ -59,6 +60,7 @@
#include "androidjniinput.h"
#include "androidjniclipboard.h"
#include "androidjnimenu.h"
+#include "qandroidplatformdialoghelpers.h"
#include "qandroidplatformintegration.h"
#include <QtWidgets/QApplication>
@@ -97,6 +99,9 @@ static jmethodID m_createBitmapMethodID = 0;
static jobject m_ARGB_8888_BitmapConfigValue = 0;
static jobject m_RGB_565_BitmapConfigValue = 0;
+jmethodID m_setFullScreenMethodID = 0;
+static bool m_statusBarShowing = true;
+
static jclass m_bitmapDrawableClass = 0;
static jmethodID m_bitmapDrawableConstructorMethodID = 0;
@@ -111,8 +116,6 @@ static jobject m_surface = NULL;
static EGLNativeWindowType m_nativeWindow = 0;
static QSemaphore m_waitForWindowSemaphore;
static bool m_waitForWindow = false;
-
-static jfieldID m_surfaceFieldID = 0;
#endif
@@ -247,17 +250,6 @@ namespace QtAndroid
m_surfaceMutex.unlock();
return m_nativeWindow;
}
-
- QSize nativeWindowSize()
- {
- if (m_nativeWindow == 0)
- return QAndroidPlatformIntegration::defaultDesktopSize();
-
- int width = ANativeWindow_getWidth(m_nativeWindow);
- int height = ANativeWindow_getHeight(m_nativeWindow);
-
- return QSize(width, height);
- }
#endif
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
@@ -323,6 +315,36 @@ namespace QtAndroid
return m_activityObject;
}
+ void showStatusBar()
+ {
+ if (m_statusBarShowing)
+ return;
+
+ QtAndroid::AttachedJNIEnv env;
+ if (env.jniEnv == 0) {
+ qWarning("Failed to get JNI Environment.");
+ return;
+ }
+
+ env.jniEnv->CallStaticVoidMethod(m_applicationClass, m_setFullScreenMethodID, false);
+ m_statusBarShowing = true;
+ }
+
+ void hideStatusBar()
+ {
+ if (!m_statusBarShowing)
+ return;
+
+ QtAndroid::AttachedJNIEnv env;
+ if (env.jniEnv == 0) {
+ qWarning("Failed to get JNI Environment.");
+ return;
+ }
+
+ env.jniEnv->CallStaticVoidMethod(m_applicationClass, m_setFullScreenMethodID, true);
+ m_statusBarShowing = false;
+ }
+
void setApplicationActive()
{
if (m_activityActive)
@@ -564,12 +586,16 @@ static void setSurface(JNIEnv *env, jobject /*thiz*/, jobject jSurface)
m_waitForWindowSemaphore.release();
if (m_androidPlatformIntegration) {
- QSize size = QtAndroid::nativeWindowSize();
+ // Use the desktop size.
+ // On some devices, the getters for the native window size gives wrong values
+ QSize size = QAndroidPlatformIntegration::defaultDesktopSize();
QPlatformScreen *screen = m_androidPlatformIntegration->screen();
QRect geometry(QPoint(0, 0), size);
- QWindowSystemInterface::handleScreenAvailableGeometryChange(screen->screen(), geometry);
- QWindowSystemInterface::handleScreenGeometryChange(screen->screen(), geometry);
+ if (screen) {
+ QWindowSystemInterface::handleScreenAvailableGeometryChange(screen->screen(), geometry);
+ QWindowSystemInterface::handleScreenGeometryChange(screen->screen(), geometry);
+ }
if (!sameNativeWindow) {
m_surfaceMutex.unlock();
@@ -666,7 +692,7 @@ static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state
{
m_activityActive = (state == Qt::ApplicationActive);
- if (!m_androidPlatformIntegration)
+ if (!m_androidPlatformIntegration || !QGuiApplicationPrivate::platformIntegration())
return;
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState(state));
@@ -762,6 +788,7 @@ static int registerNatives(JNIEnv *env)
jclass clazz;
FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtNative");
m_applicationClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ GET_AND_CHECK_STATIC_METHOD(m_setFullScreenMethodID, m_applicationClass, "setFullScreen", "(Z)V");
if (env->RegisterNatives(m_applicationClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
__android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
@@ -770,11 +797,6 @@ static int registerNatives(JNIEnv *env)
GET_AND_CHECK_STATIC_METHOD(m_redrawSurfaceMethodID, m_applicationClass, "redrawSurface", "(IIII)V");
-#ifdef ANDROID_PLUGIN_OPENGL
- FIND_AND_CHECK_CLASS("android/view/Surface");
- GET_AND_CHECK_FIELD(m_surfaceFieldID, clazz, "mNativeSurface", "I");
-#endif
-
jmethodID methodID;
GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;");
jobject activityObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
@@ -814,6 +836,15 @@ static int registerNatives(JNIEnv *env)
return JNI_TRUE;
}
+jint androidApiLevel(JNIEnv *env)
+{
+ jclass clazz;
+ FIND_AND_CHECK_CLASS("android/os/Build$VERSION");
+ jfieldID fieldId;
+ GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "SDK_INT", "I");
+ return env->GetStaticIntField(clazz, fieldId);
+}
+
Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
{
typedef union {
@@ -836,11 +867,18 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
|| !QtAndroidInput::registerNatives(env)
|| !QtAndroidClipboard::registerNatives(env)
|| !QtAndroidMenu::registerNatives(env)
- || !QtAndroidAccessibility::registerNatives(env)) {
+ || !QtAndroidAccessibility::registerNatives(env)
+ || !QtAndroidDialogHelpers::registerNatives(env)) {
__android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
return -1;
}
+ jint apiLevel = androidApiLevel(env);
+ if (apiLevel >= 16 && !QtAndroidAccessibility::registerNatives(env)) {
+ __android_log_print(ANDROID_LOG_FATAL, "Qt A11y", "registerNatives failed");
+ return -1;
+ }
+
m_javaVM = vm;
return JNI_VERSION_1_4;
}
diff --git a/src/plugins/platforms/android/src/androidjnimain.h b/src/plugins/platforms/android/src/androidjnimain.h
index 9a3d8a9607..11d3573404 100644
--- a/src/plugins/platforms/android/src/androidjnimain.h
+++ b/src/plugins/platforms/android/src/androidjnimain.h
@@ -69,13 +69,10 @@ namespace QtAndroid
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration);
void setQtThread(QThread *thread);
- void setFullScreen(QWidget *widget);
-
#ifndef ANDROID_PLUGIN_OPENGL
void flushImage(const QPoint &pos, const QImage &image, const QRect &rect);
#else
EGLNativeWindowType nativeWindow(bool waitToCreate = true);
- QSize nativeWindowSize();
#endif
QWindow *topLevelWindowAt(const QPoint &globalPos);
@@ -90,6 +87,9 @@ namespace QtAndroid
void setApplicationActive();
+ void showStatusBar();
+ void hideStatusBar();
+
jobject createBitmap(QImage img, JNIEnv *env = 0);
jobject createBitmapDrawable(jobject bitmap, JNIEnv *env = 0);
diff --git a/src/plugins/platforms/android/src/androidjnimenu.cpp b/src/plugins/platforms/android/src/androidjnimenu.cpp
index bb180347c1..293af2b9cd 100644
--- a/src/plugins/platforms/android/src/androidjnimenu.cpp
+++ b/src/plugins/platforms/android/src/androidjnimenu.cpp
@@ -41,13 +41,14 @@
#include "androidjnimenu.h"
#include "androidjnimain.h"
-#include <qmutex.h>
-#include <qset.h>
-#include <qqueue.h>
-#include <android/log.h>
#include "qandroidplatformmenubar.h"
#include "qandroidplatformmenu.h"
-#include <qandroidplatformmenuitem.h>
+#include "qandroidplatformmenuitem.h"
+
+#include <QMutex>
+#include <QSet>
+#include <QQueue>
+#include <QWindow>
using namespace QtAndroid;
@@ -141,18 +142,17 @@ namespace QtAndroidMenu
void setActiveTopLevelWindow(QWindow *window)
{
+ Qt::WindowFlags flags = window ? window->flags() : Qt::WindowFlags();
+ bool isNonRegularWindow = flags & (Qt::Desktop | Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
+ if (isNonRegularWindow)
+ return;
+
QMutexLocker lock(&menuBarMutex);
if (activeTopLevelWindow == window)
return;
visibleMenuBar = 0;
activeTopLevelWindow = window;
-#ifdef ANDROID_PLUGIN_OPENGL
- //only one toplevel window, so the menu bar always belongs to us
- if (menuBars.size() == 1) {
- visibleMenuBar = *menuBars.constBegin(); //since QSet doesn't have first()
- } else
-#endif
foreach (QAndroidPlatformMenuBar *menuBar, menuBars) {
if (menuBar->parentWindow() == window) {
visibleMenuBar = menuBar;
@@ -173,8 +173,10 @@ namespace QtAndroidMenu
{
QMutexLocker lock(&menuBarMutex);
menuBars.remove(menuBar);
- if (visibleMenuBar == menuBar)
+ if (visibleMenuBar == menuBar) {
+ visibleMenuBar = 0;
resetMenuBar();
+ }
}
static QString removeAmpersandEscapes(QString s)
@@ -197,16 +199,18 @@ namespace QtAndroidMenu
env->CallObjectMethod(menuItem, setCheckedMenuItemMethodID, checked);
env->CallObjectMethod(menuItem, setEnabledMenuItemMethodID, enabled);
- if (!icon.isNull()) {
+ if (!icon.isNull()) { // isNull() only checks the d pointer, not the actual image data.
int sz = qMax(36, qgetenv("QT_ANDROID_APP_ICON_SIZE").toInt());
QImage img = icon.pixmap(QSize(sz,sz),
enabled
? QIcon::Normal
: QIcon::Disabled,
QIcon::On).toImage();
- env->CallObjectMethod(menuItem,
- setIconMenuItemMethodID,
- createBitmapDrawable(createBitmap(img, env), env));
+ if (!img.isNull()) { // Make sure we have a valid image.
+ env->CallObjectMethod(menuItem,
+ setIconMenuItemMethodID,
+ createBitmapDrawable(createBitmap(img, env), env));
+ }
}
env->CallObjectMethod(menuItem, setVisibleMenuItemMethodID, visible);
diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp
index 9d6d4003f7..6431914812 100644
--- a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp
@@ -71,6 +71,8 @@ void QAndroidOpenGLContext::swapBuffers(QPlatformSurface *surface)
if (size.isValid()) {
QRect geometry(QPoint(0, 0), size);
window->setGeometry(geometry);
+ QWindowSystemInterface::handleGeometryChange(window->window(), geometry);
+ QWindowSystemInterface::handleExposeEvent(window->window(), QRegion(geometry));
window->scheduleResize(QSize());
}
window->unlock();
diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformscreen.cpp b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformscreen.cpp
new file mode 100644
index 0000000000..de4075feff
--- /dev/null
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformscreen.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** 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 "qandroidopenglplatformscreen.h"
+#include "qandroidopenglplatformwindow.h"
+#include "androidjnimenu.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidOpenGLPlatformScreen::QAndroidOpenGLPlatformScreen(EGLDisplay display)
+ : QEglFSScreen(display)
+{
+}
+
+void QAndroidOpenGLPlatformScreen::topWindowChanged(QPlatformWindow *window)
+{
+ QtAndroidMenu::setActiveTopLevelWindow(window->window());
+ QAndroidOpenGLPlatformWindow *platformWindow = static_cast<QAndroidOpenGLPlatformWindow *>(window);
+ if (platformWindow != 0)
+ platformWindow->updateStatusBarVisibility();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxrootwindow.h b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformscreen.h
index ea7c7faace..e9251592aa 100644
--- a/src/plugins/platforms/qnx/qqnxrootwindow.h
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformscreen.h
@@ -1,6 +1,6 @@
-/***************************************************************************
+/****************************************************************************
**
-** Copyright (C) 2011 - 2012 Research In Motion
+** 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.
@@ -39,47 +39,22 @@
**
****************************************************************************/
-#ifndef QQNXROOTWINDOW_H
-#define QQNXROOTWINDOW_H
+#ifndef QANDROIDOPENGLPLATFORMSCREEN_H
+#define QANDROIDOPENGLPLATFORMSCREEN_H
-#include <QtCore/QByteArray>
-#include <QtCore/QRect>
-
-#include <screen/screen.h>
+#include "qeglfsscreen.h"
QT_BEGIN_NAMESPACE
-class QQnxScreen;
-
-class QQnxRootWindow
+class QAndroidOpenGLPlatformScreen : public QEglFSScreen
{
public:
- QQnxRootWindow(const QQnxScreen *screen);
- ~QQnxRootWindow();
-
- screen_window_t nativeHandle() const { return m_window; }
-
- void post() const;
- void flush() const;
-
- void setRotation(int rotation);
-
- void resize(const QSize &size);
-
- void makeTranslucent();
-
- QByteArray groupName() const { return m_windowGroupName; }
-
-private:
- void createWindowGroup();
-
- const QQnxScreen *m_screen;
- screen_window_t m_window;
- QByteArray m_windowGroupName;
+ QAndroidOpenGLPlatformScreen(EGLDisplay display);
- bool m_translucent;
+protected:
+ void topWindowChanged(QPlatformWindow *window);
};
QT_END_NAMESPACE
-#endif // QQNXROOTWINDOW_H
+#endif // QANDROIDOPENGLPLATFORMSCREEN_H
diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp
index 4934047af9..6ed805174b 100644
--- a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp
@@ -41,6 +41,7 @@
#include "qandroidopenglplatformwindow.h"
#include "androidjnimain.h"
+#include "qandroidplatformintegration.h"
#include <qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE
@@ -52,6 +53,7 @@ QBasicAtomicInt QAndroidOpenGLPlatformWindow::m_referenceCount = Q_BASIC_ATOMIC_
QAndroidOpenGLPlatformWindow::QAndroidOpenGLPlatformWindow(QWindow *window)
: QEglFSWindow(window)
+ , m_state(Qt::WindowNoState)
{
}
@@ -110,7 +112,9 @@ void QAndroidOpenGLPlatformWindow::resetSurface()
{
lock();
- scheduleResize(QtAndroid::nativeWindowSize());
+ // Use the desktop size.
+ // On some devices, the getters for the native window size gives wrong values
+ scheduleResize(QAndroidPlatformIntegration::defaultDesktopSize());
QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); // Expose event
unlock();
}
@@ -128,12 +132,38 @@ void QAndroidOpenGLPlatformWindow::destroy()
}
}
+void QAndroidOpenGLPlatformWindow::updateStatusBarVisibility()
+{
+ Qt::WindowFlags flags = window()->flags();
+ bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
+ if (!isNonRegularWindow) {
+ if (m_state & Qt::WindowFullScreen)
+ QtAndroid::hideStatusBar();
+ else if (m_state & Qt::WindowMaximized)
+ QtAndroid::showStatusBar();
+ }
+}
+
void QAndroidOpenGLPlatformWindow::raise()
{
+ updateStatusBarVisibility();
+}
+
+void QAndroidOpenGLPlatformWindow::setWindowState(Qt::WindowState state)
+{
+ if (m_state == state)
+ return;
+
+ m_state = state;
+ if (window()->isVisible())
+ updateStatusBarVisibility();
}
void QAndroidOpenGLPlatformWindow::setVisible(bool visible)
{
+ if (visible)
+ updateStatusBarVisibility();
+
QEglFSWindow::setVisible(visible);
// The Android Activity is activated before Qt is initialized, causing the application state to
diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h
index 9a25957ccd..e4ff0444d4 100644
--- a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h
@@ -66,16 +66,19 @@ public:
void invalidateSurface();
void resetSurface();
+ void setWindowState(Qt::WindowState state);
void setVisible(bool visible);
void destroy();
static void updateStaticNativeWindow();
+ void updateStatusBarVisibility();
private:
QSize m_scheduledResize;
QMutex m_lock;
+ Qt::WindowState m_state;
static QReadWriteLock m_staticSurfaceLock;
static EGLSurface m_staticSurface;
diff --git a/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp b/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp
index 338966eb40..278cd553f4 100644
--- a/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp
+++ b/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp
@@ -82,7 +82,7 @@ EGLNativeDisplayType QEglFSAndroidHooks::platformDisplay() const
QSize QEglFSAndroidHooks::screenSize() const
{
- return QtAndroid::nativeWindowSize();
+ return QAndroidPlatformIntegration::defaultDesktopSize();
}
QSizeF QEglFSAndroidHooks::physicalScreenSize() const
@@ -120,7 +120,8 @@ EGLNativeWindowType QEglFSAndroidHooks::createNativeWindow(QPlatformWindow *plat
void QEglFSAndroidHooks::destroyNativeWindow(EGLNativeWindowType window)
{
- ANativeWindow_release(window);
+ if (window != 0)
+ ANativeWindow_release(window);
}
bool QEglFSAndroidHooks::hasCapability(QPlatformIntegration::Capability capability) const
diff --git a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp
index f3cb2586cc..95844fc649 100644
--- a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp
+++ b/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp
@@ -43,20 +43,32 @@
#include "androidjnimain.h"
#include <QCoreApplication>
+#include <QVector>
+
+typedef QVector<QString> FilesList;
+
+struct AndroidAssetDir
+{
+ AndroidAssetDir(AAssetDir* ad)
+ {
+ const char *fileName;
+ while ((fileName = AAssetDir_getNextFileName(ad)))
+ m_items.push_back(QString::fromUtf8(fileName));
+ AAssetDir_close(ad);
+ }
+ FilesList m_items;
+};
class AndroidAbstractFileEngineIterator: public QAbstractFileEngineIterator
{
public:
AndroidAbstractFileEngineIterator(QDir::Filters filters,
const QStringList &nameFilters,
- AAssetDir *asset,
+ QSharedPointer<AndroidAssetDir> asset,
const QString &path)
: QAbstractFileEngineIterator(filters, nameFilters)
{
- AAssetDir_rewind(asset);
- const char *fileName;
- while ((fileName = AAssetDir_getNextFileName(asset)))
- m_items << fileName;
+ m_items = asset->m_items;
m_index = -1;
m_path = path;
}
@@ -93,7 +105,7 @@ public:
private:
QString m_path;
- QStringList m_items;
+ FilesList m_items;
int m_index;
};
@@ -102,12 +114,11 @@ class AndroidAbstractFileEngine: public QAbstractFileEngine
public:
explicit AndroidAbstractFileEngine(AAsset *asset, const QString &fileName)
{
- m_assetDir = 0;
m_assetFile = asset;
m_fileName = fileName;
}
- explicit AndroidAbstractFileEngine(AAssetDir *asset, const QString &fileName)
+ explicit AndroidAbstractFileEngine(QSharedPointer<AndroidAssetDir> asset, const QString &fileName)
{
m_assetFile = 0;
m_assetDir = asset;
@@ -119,8 +130,6 @@ public:
~AndroidAbstractFileEngine()
{
close();
- if (m_assetDir)
- AAssetDir_close(m_assetDir);
}
virtual bool open(QIODevice::OpenMode openMode)
@@ -188,7 +197,7 @@ public:
FileFlags flags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag);
if (m_assetFile)
flags |= FileType;
- if (m_assetDir)
+ if (!m_assetDir.isNull())
flags |= DirectoryType;
return type & flags;
@@ -233,19 +242,19 @@ public:
virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames)
{
- if (m_assetDir)
+ if (!m_assetDir.isNull())
return new AndroidAbstractFileEngineIterator(filters, filterNames, m_assetDir, m_fileName);
return 0;
}
private:
AAsset *m_assetFile;
- AAssetDir *m_assetDir;
+ QSharedPointer<AndroidAssetDir> m_assetDir;
QString m_fileName;
};
-AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler()
+AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler():m_assetsCache(std::max(5, qgetenv("QT_ANDROID_MAX_ASSETS_CACHE_SIZE").toInt()))
{
m_assetManager = QtAndroid::assetManager();
}
@@ -264,25 +273,37 @@ QAbstractFileEngine * AndroidAssetsFileEngineHandler::create(const QString &file
int prefixSize=8;
- m_path.clear();
+ QByteArray path;
if (!fileName.endsWith(QLatin1Char('/'))) {
- m_path = fileName.toUtf8();
+ path = fileName.toUtf8();
AAsset *asset = AAssetManager_open(m_assetManager,
- m_path.constData() + prefixSize,
+ path.constData() + prefixSize,
AASSET_MODE_BUFFER);
if (asset)
return new AndroidAbstractFileEngine(asset, fileName);
}
- if (!m_path.size())
- m_path = fileName.left(fileName.length() - 1).toUtf8();
-
- AAssetDir *assetDir = AAssetManager_openDir(m_assetManager, m_path.constData() + prefixSize);
- if (assetDir) {
- if (AAssetDir_getNextFileName(assetDir))
- return new AndroidAbstractFileEngine(assetDir, fileName);
- else
- AAssetDir_close(assetDir);
+ if (!path.size())
+ path = fileName.left(fileName.length() - 1).toUtf8();
+
+ m_assetsCacheMutext.lock();
+ QSharedPointer<AndroidAssetDir> *aad = m_assetsCache.object(path);
+ m_assetsCacheMutext.unlock();
+ if (!aad) {
+ AAssetDir *assetDir = AAssetManager_openDir(m_assetManager, path.constData() + prefixSize);
+ if (assetDir) {
+ if (AAssetDir_getNextFileName(assetDir)) {
+ aad = new QSharedPointer<AndroidAssetDir>(new AndroidAssetDir(assetDir));
+ m_assetsCacheMutext.lock();
+ m_assetsCache.insert(path, aad);
+ m_assetsCacheMutext.unlock();
+ return new AndroidAbstractFileEngine(*aad, fileName);
+ } else {
+ AAssetDir_close(assetDir);
+ }
+ }
+ } else {
+ return new AndroidAbstractFileEngine(*aad, fileName);
}
return 0;
}
diff --git a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h b/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h
index 9bff6a012e..7bd560886c 100644
--- a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h
+++ b/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h
@@ -43,8 +43,13 @@
#define QANDROIDASSETSFILEENGINEHANDLER_H
#include <QtCore/private/qabstractfileengine_p.h>
+#include <QCache>
+#include <QMutex>
+#include <QSharedPointer>
+
#include <android/asset_manager.h>
+struct AndroidAssetDir;
class AndroidAssetsFileEngineHandler: public QAbstractFileEngineHandler
{
public:
@@ -54,7 +59,8 @@ public:
private:
AAssetManager *m_assetManager;
- mutable QByteArray m_path;
+ mutable QCache<QByteArray, QSharedPointer<AndroidAssetDir>> m_assetsCache;
+ mutable QMutex m_assetsCacheMutext;
};
#endif // QANDROIDASSETSFILEENGINEHANDLER_H
diff --git a/src/plugins/platforms/android/src/qandroidinputcontext.cpp b/src/plugins/platforms/android/src/qandroidinputcontext.cpp
index 386c8e006a..8556e8ebf1 100644
--- a/src/plugins/platforms/android/src/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/src/qandroidinputcontext.cpp
@@ -381,6 +381,11 @@ QAndroidInputContext::~QAndroidInputContext()
m_textFieldID = 0;
}
+QAndroidInputContext *QAndroidInputContext::androidInputContext()
+{
+ return m_androidInputContext;
+}
+
void QAndroidInputContext::reset()
{
clear();
diff --git a/src/plugins/platforms/android/src/qandroidinputcontext.h b/src/plugins/platforms/android/src/qandroidinputcontext.h
index d19dcc384b..041bd0dc49 100644
--- a/src/plugins/platforms/android/src/qandroidinputcontext.h
+++ b/src/plugins/platforms/android/src/qandroidinputcontext.h
@@ -80,6 +80,7 @@ public:
public:
QAndroidInputContext();
~QAndroidInputContext();
+ static QAndroidInputContext * androidInputContext();
bool isValid() const { return true; }
void reset();
diff --git a/src/plugins/platforms/android/src/qandroidplatformdialoghelpers.cpp b/src/plugins/platforms/android/src/qandroidplatformdialoghelpers.cpp
new file mode 100644
index 0000000000..f379402e18
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformdialoghelpers.cpp
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 <QtWidgets/QApplication>
+#include <QtWidgets/QStyle>
+#include "qandroidplatformdialoghelpers.h"
+#include "androidjnimain.h"
+
+namespace QtAndroidDialogHelpers {
+static jclass g_messageDialogHelperClass = 0;
+
+QAndroidPlatformMessageDialogHelper::QAndroidPlatformMessageDialogHelper()
+ :m_buttonId(-1)
+ ,m_javaMessageDialog(g_messageDialogHelperClass, "(Landroid/app/Activity;)V", QtAndroid::activity())
+ ,m_shown(false)
+{
+}
+
+void QAndroidPlatformMessageDialogHelper::exec()
+{
+ if (!m_shown)
+ show(Qt::Dialog, Qt::ApplicationModal, 0);
+ m_loop.exec();
+}
+
+static QString standardButtonText(int sbutton)
+{
+ switch (sbutton) {
+ case QMessageDialogOptions::Ok:
+ return QAndroidPlatformMessageDialogHelper::tr("OK");
+ case QMessageDialogOptions::Save:
+ return QAndroidPlatformMessageDialogHelper::tr("Save");
+ case QMessageDialogOptions::Open:
+ return QAndroidPlatformMessageDialogHelper::tr("Open");
+ case QMessageDialogOptions::Cancel:
+ return QAndroidPlatformMessageDialogHelper::tr("Cancel");
+ case QMessageDialogOptions::Close:
+ return QAndroidPlatformMessageDialogHelper::tr("Close");
+ case QMessageDialogOptions::Apply:
+ return QAndroidPlatformMessageDialogHelper::tr("Apply");
+ case QMessageDialogOptions::Reset:
+ return QAndroidPlatformMessageDialogHelper::tr("Reset");
+ case QMessageDialogOptions::Help:
+ return QAndroidPlatformMessageDialogHelper::tr("Help");
+ case QMessageDialogOptions::Discard:
+ return QAndroidPlatformMessageDialogHelper::tr("Discard");
+ case QMessageDialogOptions::Yes:
+ return QAndroidPlatformMessageDialogHelper::tr("Yes");
+ case QMessageDialogOptions::YesToAll:
+ return QAndroidPlatformMessageDialogHelper::tr("Yes to All");
+ case QMessageDialogOptions::No:
+ return QAndroidPlatformMessageDialogHelper::tr("No");
+ case QMessageDialogOptions::NoToAll:
+ return QAndroidPlatformMessageDialogHelper::tr("No to All");
+ case QMessageDialogOptions::SaveAll:
+ return QAndroidPlatformMessageDialogHelper::tr("Save All");
+ case QMessageDialogOptions::Abort:
+ return QAndroidPlatformMessageDialogHelper::tr("Abort");
+ case QMessageDialogOptions::Retry:
+ return QAndroidPlatformMessageDialogHelper::tr("Retry");
+ case QMessageDialogOptions::Ignore:
+ return QAndroidPlatformMessageDialogHelper::tr("Ignore");
+ case QMessageDialogOptions::RestoreDefaults:
+ return QAndroidPlatformMessageDialogHelper::tr("Restore Defaults");
+ } // switch
+ return QString();
+}
+
+bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags
+ , Qt::WindowModality windowModality
+ , QWindow *parent)
+{
+ Q_UNUSED(windowFlags)
+ Q_UNUSED(windowModality)
+ Q_UNUSED(parent)
+ QSharedPointer<QMessageDialogOptions> opt = options();
+ if (!opt.data())
+ return false;
+
+ m_javaMessageDialog.callMethod<void>("setIcon", "(I)V", opt->icon());
+
+ QString str = opt->windowTitle();
+ if (!str.isEmpty())
+ m_javaMessageDialog.callMethod<void>("setTile", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
+
+ str = opt->text();
+ if (!str.isEmpty())
+ m_javaMessageDialog.callMethod<void>("setText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
+
+ str = opt->informativeText();
+ if (!str.isEmpty())
+ m_javaMessageDialog.callMethod<void>("setInformativeText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
+
+ str = opt->detailedText();
+ if (!str.isEmpty())
+ m_javaMessageDialog.callMethod<void>("setDetailedText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
+
+ for (int i = QMessageDialogOptions::FirstButton; i < QMessageDialogOptions::LastButton; i<<=1) {
+ if ( opt->standardButtons() & i )
+ m_javaMessageDialog.callMethod<void>("addButton", "(ILjava/lang/String;)V", i, QJNIObjectPrivate::fromString(standardButtonText(i)).object());
+ }
+
+ m_javaMessageDialog.callMethod<void>("show", "(J)V", jlong(static_cast<QObject*>(this)));
+ m_shown = true;
+ return true;
+}
+
+void QAndroidPlatformMessageDialogHelper::hide()
+{
+ m_javaMessageDialog.callMethod<void>("hide", "()V");
+ m_shown = false;
+}
+
+void QAndroidPlatformMessageDialogHelper::dialogResult(int buttonID)
+{
+ m_buttonId = buttonID;
+ if (m_loop.isRunning())
+ m_loop.exit();
+ if (m_buttonId < 0) {
+ emit reject();
+ return;
+ }
+
+ QMessageDialogOptions::StandardButton standardButton = static_cast<QMessageDialogOptions::StandardButton>(buttonID);
+ QMessageDialogOptions::ButtonRole role = QMessageDialogOptions::buttonRole(standardButton);
+ emit clicked(standardButton, role);
+}
+
+static void dialogResult(JNIEnv * /*env*/, jobject /*thiz*/, jlong handler, int buttonID)
+{
+ QObject *object = reinterpret_cast<QObject *>(handler);
+ QMetaObject::invokeMethod(object, "dialogResult", Qt::QueuedConnection, Q_ARG(int, buttonID));
+}
+
+static JNINativeMethod methods[] = {
+ {"dialogResult", "(JI)V", (void *)dialogResult}
+};
+
+
+#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
+ clazz = env->FindClass(CLASS_NAME); \
+ if (!clazz) { \
+ __android_log_print(ANDROID_LOG_FATAL, QtAndroid::qtTagText(), QtAndroid::classErrorMsgFmt(), CLASS_NAME); \
+ return false; \
+ }
+
+bool registerNatives(JNIEnv *env)
+{
+ jclass clazz = QtAndroid::findClass("org/qtproject/qt5/android/QtMessageDialogHelper", env);
+ if (!clazz) {
+ __android_log_print(ANDROID_LOG_FATAL, QtAndroid::qtTagText(), QtAndroid::classErrorMsgFmt()
+ , "org/qtproject/qt5/android/QtMessageDialogHelper");
+ return false;
+ }
+ g_messageDialogHelperClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtNativeDialogHelper");
+ jclass appClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+ if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ __android_log_print(ANDROID_LOG_FATAL, "Qt", "RegisterNatives failed");
+ return false;
+ }
+
+ return true;
+}
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformdialoghelpers.h b/src/plugins/platforms/android/src/qandroidplatformdialoghelpers.h
new file mode 100644
index 0000000000..88ec91d936
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformdialoghelpers.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 QANDROIDPLATFORMDIALOGHELPERS_H
+#define QANDROIDPLATFORMDIALOGHELPERS_H
+#include <jni.h>
+#include <qpa/qplatformdialoghelper.h>
+#include <QEventLoop>
+#include <private/qjni_p.h>
+
+namespace QtAndroidDialogHelpers {
+
+class QAndroidPlatformMessageDialogHelper: public QPlatformMessageDialogHelper
+{
+ Q_OBJECT
+public:
+ QAndroidPlatformMessageDialogHelper();
+ void exec();
+ bool show(Qt::WindowFlags windowFlags,
+ Qt::WindowModality windowModality,
+ QWindow *parent);
+ void hide();
+
+public slots:
+ void dialogResult(int buttonID);
+
+private:
+ int m_buttonId;
+ QEventLoop m_loop;
+ QJNIObjectPrivate m_javaMessageDialog;
+ bool m_shown;
+};
+
+
+bool registerNatives(JNIEnv *env);
+
+}
+
+#endif // QANDROIDPLATFORMDIALOGHELPERS_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp
index a3db421de9..ae3e257d3c 100644
--- a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp
@@ -61,6 +61,7 @@
# include "androidjnimenu.h"
# include "qandroidopenglcontext.h"
# include "qandroidopenglplatformwindow.h"
+# include "qandroidopenglplatformscreen.h"
# include "qeglfshooks.h"
# include <QtGui/qopenglcontext.h>
#endif
@@ -123,7 +124,6 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
switch (cap) {
case ThreadedPixmaps: return true;
case ApplicationState: return true;
- case NonFullScreenWindows: return false;
case NativeWidgets: return false;
default:
#ifndef ANDROID_PLUGIN_OPENGL
@@ -142,7 +142,10 @@ QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(Q
QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const
{
- return new QAndroidPlatformWindow(window);
+ QAndroidPlatformWindow *platformWindow = new QAndroidPlatformWindow(window);
+ platformWindow->setWindowState(window->windowState());
+
+ return platformWindow;
}
QAbstractEventDispatcher *QAndroidPlatformIntegration::createEventDispatcher() const
@@ -155,6 +158,7 @@ QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *wind
QAndroidOpenGLPlatformWindow *platformWindow = new QAndroidOpenGLPlatformWindow(window);
platformWindow->create();
platformWindow->requestActivateWindow();
+ platformWindow->setWindowState(window->windowState());
QtAndroidMenu::setActiveTopLevelWindow(window);
return platformWindow;
@@ -231,13 +235,22 @@ QPlatformServices *QAndroidPlatformIntegration::services() const
QVariant QAndroidPlatformIntegration::styleHint(StyleHint hint) const
{
switch (hint) {
- case ShowIsFullScreen:
+ case ShowIsMaximized:
return true;
default:
return QPlatformIntegration::styleHint(hint);
}
}
+Qt::WindowState QAndroidPlatformIntegration::defaultWindowState(Qt::WindowFlags flags) const
+{
+ // Don't maximize dialogs on Android
+ if (flags & Qt::Dialog & ~Qt::Window)
+ return Qt::WindowNoState;
+
+ return QPlatformIntegration::defaultWindowState(flags);
+}
+
static const QLatin1String androidThemeName("android");
QStringList QAndroidPlatformIntegration::themeNames() const
{
@@ -308,6 +321,11 @@ void QAndroidPlatformIntegration::setDisplayMetrics(int width, int height)
m_defaultPhysicalSizeHeight = height;
}
+QEglFSScreen *QAndroidPlatformIntegration::createScreen() const
+{
+ return new QAndroidOpenGLPlatformScreen(display());
+}
+
#endif
void QAndroidPlatformIntegration::pauseApp()
diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.h b/src/plugins/platforms/android/src/qandroidplatformintegration.h
index 5ebdf9e65c..bd08ad694c 100644
--- a/src/plugins/platforms/android/src/qandroidplatformintegration.h
+++ b/src/plugins/platforms/android/src/qandroidplatformintegration.h
@@ -121,6 +121,7 @@ public:
#endif
QVariant styleHint(StyleHint hint) const;
+ Qt::WindowState defaultWindowState(Qt::WindowFlags flags) const Q_DECL_OVERRIDE;
QStringList themeNames() const;
QPlatformTheme *createPlatformTheme(const QString &name) const;
@@ -140,6 +141,10 @@ public:
QTouchDevice *touchDevice() const { return m_touchDevice; }
void setTouchDevice(QTouchDevice *touchDevice) { m_touchDevice = touchDevice; }
+#ifdef ANDROID_PLUGIN_OPENGL
+ QEglFSScreen *createScreen() const;
+#endif
+
private:
friend class QEglFSAndroidHooks;
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenu.cpp b/src/plugins/platforms/android/src/qandroidplatformmenu.cpp
index 253c22a12f..1ecabb25e2 100644
--- a/src/plugins/platforms/android/src/qandroidplatformmenu.cpp
+++ b/src/plugins/platforms/android/src/qandroidplatformmenu.cpp
@@ -141,6 +141,15 @@ bool QAndroidPlatformMenu::isVisible() const
return m_isVisible;
}
+void QAndroidPlatformMenu::showPopup(const QWindow *parentWindow, QPoint pos, const QPlatformMenuItem *item)
+{
+ Q_UNUSED(parentWindow);
+ Q_UNUSED(pos);
+ Q_UNUSED(item);
+ setVisible(true);
+ QtAndroidMenu::showContextMenu(this);
+}
+
QPlatformMenuItem *QAndroidPlatformMenu::menuItemAt(int position) const
{
if (position < m_menuItems.size())
@@ -154,7 +163,6 @@ QPlatformMenuItem *QAndroidPlatformMenu::menuItemForTag(quintptr tag) const
if (menuItem->tag() == tag)
return menuItem;
}
-
return 0;
}
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenu.h b/src/plugins/platforms/android/src/qandroidplatformmenu.h
index 20236cb636..305b64168a 100644
--- a/src/plugins/platforms/android/src/qandroidplatformmenu.h
+++ b/src/plugins/platforms/android/src/qandroidplatformmenu.h
@@ -71,6 +71,7 @@ public:
bool isEnabled() const;
void setVisible(bool visible);
bool isVisible() const;
+ void showPopup(const QWindow *parentWindow, QPoint pos, const QPlatformMenuItem *item);
QPlatformMenuItem *menuItemAt(int position) const;
QPlatformMenuItem *menuItemForTag(quintptr tag) const;
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenubar.cpp b/src/plugins/platforms/android/src/qandroidplatformmenubar.cpp
index ef1ac61356..134062fb32 100644
--- a/src/plugins/platforms/android/src/qandroidplatformmenubar.cpp
+++ b/src/plugins/platforms/android/src/qandroidplatformmenubar.cpp
@@ -79,6 +79,8 @@ void QAndroidPlatformMenuBar::syncMenu(QPlatformMenu *menu)
void QAndroidPlatformMenuBar::handleReparent(QWindow *newParentWindow)
{
+ if (m_parentWindow == newParentWindow)
+ return;
m_parentWindow = newParentWindow;
QtAndroidMenu::setMenuBar(this, newParentWindow);
}
diff --git a/src/plugins/platforms/android/src/qandroidplatformtheme.cpp b/src/plugins/platforms/android/src/qandroidplatformtheme.cpp
index 79fbc440fc..308bb70faf 100644
--- a/src/plugins/platforms/android/src/qandroidplatformtheme.cpp
+++ b/src/plugins/platforms/android/src/qandroidplatformtheme.cpp
@@ -43,6 +43,7 @@
#include "qandroidplatformmenubar.h"
#include "qandroidplatformmenu.h"
#include "qandroidplatformmenuitem.h"
+#include "qandroidplatformdialoghelpers.h"
#include <QVariant>
#include <QFileInfo>
#include <qandroidplatformintegration.h>
@@ -124,7 +125,7 @@ const QFont *QAndroidPlatformTheme::font(Font type) const
return &(it.value());
// default in case the style has not set a font
- static QFont systemFont("Roboto", 12.0 * 100 / 72); // keep default size the same after changing from 100 dpi to 72 dpi
+ static QFont systemFont("Roboto", 14.0 * 100 / 72); // keep default size the same after changing from 100 dpi to 72 dpi
if (type == QPlatformTheme::SystemFont)
return &systemFont;
return 0;
@@ -150,3 +151,20 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
return QPlatformTheme::themeHint(hint);
}
}
+
+bool QAndroidPlatformTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const
+{
+ if (type == MessageDialog)
+ return qgetenv("QT_USE_ANDROID_NATIVE_DIALOGS").toInt() == 1;
+ return false;
+}
+
+QPlatformDialogHelper *QAndroidPlatformTheme::createPlatformDialogHelper(QPlatformTheme::DialogType type) const
+{
+ switch (type) {
+ case MessageDialog:
+ return new QtAndroidDialogHelpers::QAndroidPlatformMessageDialogHelper;
+ default:
+ return 0;
+ }
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformtheme.h b/src/plugins/platforms/android/src/qandroidplatformtheme.h
index 15d2cb2000..ec259a9b0a 100644
--- a/src/plugins/platforms/android/src/qandroidplatformtheme.h
+++ b/src/plugins/platforms/android/src/qandroidplatformtheme.h
@@ -54,6 +54,9 @@ public:
virtual const QPalette *palette(Palette type = SystemPalette) const;
virtual const QFont *font(Font type = SystemFont) const;
virtual QVariant themeHint(ThemeHint hint) const;
+ virtual bool usePlatformNativeDialog(DialogType type) const;
+ virtual QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const;
+
private:
QAndroidPlatformNativeInterface * m_androidPlatformNativeInterface;
diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp b/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp
index 0250a6122c..2e59c307c3 100644
--- a/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp
+++ b/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp
@@ -43,6 +43,7 @@
#include "qandroidplatformintegration.h"
#include "androidjnimain.h"
#include "androidjnimenu.h"
+#include "qandroidplatformwindow.h"
QAndroidPlatformScreen::QAndroidPlatformScreen():QFbScreen()
{
@@ -57,6 +58,12 @@ QAndroidPlatformScreen::QAndroidPlatformScreen():QFbScreen()
void QAndroidPlatformScreen::topWindowChanged(QWindow *w)
{
QtAndroidMenu::setActiveTopLevelWindow(w);
+
+ if (w != 0) {
+ QAndroidPlatformWindow *platformWindow = static_cast<QAndroidPlatformWindow *>(w->handle());
+ if (platformWindow != 0)
+ platformWindow->updateStatusBarVisibility();
+ }
}
QRegion QAndroidPlatformScreen::doRedraw()
diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp
index f5fce0ae34..7ff18526d9 100644
--- a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp
+++ b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp
@@ -44,7 +44,8 @@
#include "androidjnimain.h"
#include <qpa/qwindowsysteminterface.h>
-QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) : QFbWindow(window)
+QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
+ : QFbWindow(window)
{
}
@@ -58,8 +59,40 @@ void QAndroidPlatformWindow::propagateSizeHints()
//shut up warning from default implementation
}
+void QAndroidPlatformWindow::updateStatusBarVisibility()
+{
+ Qt::WindowFlags flags = window()->flags();
+ bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
+ if (!isNonRegularWindow) {
+ if (mWindowState & Qt::WindowFullScreen)
+ QtAndroid::hideStatusBar();
+ else if (mWindowState & Qt::WindowMaximized)
+ QtAndroid::showStatusBar();
+ }
+}
+
+void QAndroidPlatformWindow::raise()
+{
+ updateStatusBarVisibility();
+ QFbWindow::raise();
+}
+
+void QAndroidPlatformWindow::setWindowState(Qt::WindowState state)
+{
+ if (mWindowState == state)
+ return;
+
+ if (window()->isVisible())
+ updateStatusBarVisibility();
+
+ QFbWindow::setWindowState(state);
+}
+
void QAndroidPlatformWindow::setVisible(bool visible)
{
+ if (visible)
+ updateStatusBarVisibility();
+
QFbWindow::setVisible(visible);
// The Android Activity is activated before Qt is initialized, causing the application state to
diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h
index 58e6451ea1..9e3f203201 100644
--- a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h
+++ b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h
@@ -52,11 +52,13 @@ public:
void propagateSizeHints();
+ void raise();
+ void setWindowState(Qt::WindowState state);
void setVisible(bool visible);
+ void updateStatusBarVisibility();
public slots:
void setGeometry(const QRect &rect);
-
};
#endif // ANDROIDPLATFORMWINDOW_H
diff --git a/src/plugins/platforms/android/src/src.pri b/src/plugins/platforms/android/src/src.pri
index 6cc41c3e68..9b64e846f7 100644
--- a/src/plugins/platforms/android/src/src.pri
+++ b/src/plugins/platforms/android/src/src.pri
@@ -21,6 +21,7 @@ SOURCES += $$PWD/androidplatformplugin.cpp \
$$PWD/qandroidinputcontext.cpp \
$$PWD/qandroidplatformaccessibility.cpp \
$$PWD/qandroidplatformfontdatabase.cpp \
+ $$PWD/qandroidplatformdialoghelpers.cpp \
$$PWD/qandroidplatformclipboard.cpp \
$$PWD/qandroidplatformtheme.cpp \
$$PWD/qandroidplatformmenubar.cpp \
@@ -41,6 +42,7 @@ HEADERS += $$PWD/qandroidplatformintegration.h \
$$PWD/qandroidplatformaccessibility.h \
$$PWD/qandroidplatformfontdatabase.h \
$$PWD/qandroidplatformclipboard.h \
+ $$PWD/qandroidplatformdialoghelpers.h \
$$PWD/qandroidplatformtheme.h \
$$PWD/qandroidplatformmenubar.h \
$$PWD/qandroidplatformmenu.h \
diff --git a/src/plugins/platforms/cocoa/images/sizeallcursor.png b/src/plugins/platforms/cocoa/images/sizeallcursor.png
new file mode 100644
index 0000000000..bb5381ba32
--- /dev/null
+++ b/src/plugins/platforms/cocoa/images/sizeallcursor.png
Binary files differ
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index e135f36e78..1371eb3658 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -40,8 +40,7 @@
****************************************************************************/
#include "qcocoaaccessibility.h"
#include "qcocoaaccessibilityelement.h"
-#include <qaccessible.h>
-#include <QtGui/private/qaccessible2_p.h>
+#include <QtGui/qaccessible.h>
#include <private/qcore_mac_p.h>
QCocoaAccessibility::QCocoaAccessibility()
@@ -56,12 +55,8 @@ QCocoaAccessibility::~QCocoaAccessibility()
void QCocoaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
{
- QObject *object = event->object();
- if (!object)
- return;
-
- QAccessibleInterface *interface = event->accessibleInterface();
- if (!interface)
+ QAccessible::Id interfaceId = event->uniqueId();
+ if (!interfaceId)
return;
switch (event->type()) {
@@ -69,7 +64,7 @@ void QCocoaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
case QAccessible::TextInserted :
case QAccessible::TextRemoved :
case QAccessible::TextUpdated : {
- QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithId : QAccessible::uniqueId(interface) parent : nil];
+ QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithId : interfaceId parent : nil];
[element autorelease];
NSAccessibilityPostNotification(element, NSAccessibilityValueChangedNotification);
break; }
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index 7eae22f720..8e20a96a48 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -42,8 +42,7 @@
#include "qcocoaaccessibility.h"
#include "qcocoahelpers.h"
-#include <QAccessible>
-#include <QtGui/private/qaccessible2_p.h>
+#include <QtGui/qaccessible.h>
#import <AppKit/NSAccessibility.h>
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm
index c293f4cd52..551a59823c 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm
@@ -115,8 +115,8 @@ QT_USE_NAMESPACE
QCocoaPostMessageArgs *args = reinterpret_cast<QCocoaPostMessageArgs *>(lower | (upper << 32));
// Special case for convenience: if the argument is an NSNumber, we unbox it directly.
// Use NSValue instead if this behaviour is unwanted.
- id a1 = ([args->arg1 isKindOfClass:[NSNumber class]]) ? (id)[args->arg1 intValue] : args->arg1;
- id a2 = ([args->arg2 isKindOfClass:[NSNumber class]]) ? (id)[args->arg2 intValue] : args->arg2;
+ id a1 = ([args->arg1 isKindOfClass:[NSNumber class]]) ? (id)[args->arg1 longValue] : args->arg1;
+ id a2 = ([args->arg2 isKindOfClass:[NSNumber class]]) ? (id)[args->arg2 longValue] : args->arg2;
switch (args->argCount) {
case 0:
[args->target performSelector:args->selector];
diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
index d90d77ec1d..be2bab8ce7 100644
--- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
@@ -82,6 +82,7 @@ static NSButton *macCreateButton(const char *text, NSView *superview)
BOOL mDialogIsExecuting;
BOOL mResultSet;
};
+- (void)restoreOriginalContentView;
- (void)relayout;
- (void)updateQtColor;
- (void)finishOffWithCode:(NSInteger)code;
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.h b/src/plugins/platforms/cocoa/qcocoacursor.h
index dfa1fcff81..f332240724 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.h
+++ b/src/plugins/platforms/cocoa/qcocoacursor.h
@@ -55,12 +55,13 @@ public:
QCocoaCursor();
~QCocoaCursor();
- virtual void changeCursor(QCursor * widgetCursor, QWindow * widget);
+ virtual void changeCursor(QCursor *cursor, QWindow *window);
virtual QPoint pos() const;
virtual void setPos(const QPoint &position);
private:
QHash<Qt::CursorShape, NSCursor *> m_cursors;
- NSCursor *createCursorData(QCursor *);
+ NSCursor *convertCursor(QCursor *cursor);
+ NSCursor *createCursorData(QCursor * cursor);
NSCursor *createCursorFromBitmap(const QBitmap *bitmap, const QBitmap *mask, const QPoint hotspot = QPoint());
NSCursor *createCursorFromPixmap(const QPixmap pixmap, const QPoint hotspot = QPoint());
};
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index e5b41e7a88..13f6423701 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qcocoacursor.h"
+#include "qcocoawindow.h"
#include "qcocoahelpers.h"
#include "qcocoaautoreleasepool.h"
@@ -63,82 +64,90 @@ QCocoaCursor::~QCocoaCursor()
void QCocoaCursor::changeCursor(QCursor *cursor, QWindow *window)
{
- Q_UNUSED(window);
+ NSCursor * cocoaCursor = convertCursor(cursor);
+ if (QPlatformWindow * platformWindow = window->handle())
+ static_cast<QCocoaWindow *>(platformWindow)->setWindowCursor(cocoaCursor);
+}
+
+QPoint QCocoaCursor::pos() const
+{
+ return qt_mac_flipPoint([NSEvent mouseLocation]).toPoint();
+}
+
+void QCocoaCursor::setPos(const QPoint &position)
+{
+ CGPoint pos;
+ pos.x = position.x();
+ pos.y = position.y();
+
+ CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0);
+ CGEventPost(kCGHIDEventTap, e);
+ CFRelease(e);
+}
+
+NSCursor *QCocoaCursor::convertCursor(QCursor * cursor)
+{
const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
+ NSCursor *cocoaCursor;
+
// Check for a suitable built-in NSCursor first:
switch (newShape) {
case Qt::ArrowCursor:
- [[NSCursor arrowCursor] set];
+ cocoaCursor= [NSCursor arrowCursor];
break;
case Qt::CrossCursor:
- [[NSCursor crosshairCursor] set];
+ cocoaCursor = [NSCursor crosshairCursor];
break;
case Qt::IBeamCursor:
- [[NSCursor IBeamCursor] set];
+ cocoaCursor = [NSCursor IBeamCursor];
break;
case Qt::WhatsThisCursor: //for now just use the pointing hand
case Qt::PointingHandCursor:
- [[NSCursor pointingHandCursor] set];
+ cocoaCursor = [NSCursor pointingHandCursor];
break;
case Qt::SplitVCursor:
- [[NSCursor resizeUpDownCursor] set];
+ cocoaCursor = [NSCursor resizeUpDownCursor];
break;
case Qt::SplitHCursor:
- [[NSCursor resizeLeftRightCursor] set];
+ cocoaCursor = [NSCursor resizeLeftRightCursor];
break;
case Qt::OpenHandCursor:
- [[NSCursor openHandCursor] set];
+ cocoaCursor = [NSCursor openHandCursor];
break;
case Qt::ClosedHandCursor:
- [[NSCursor closedHandCursor] set];
+ cocoaCursor = [NSCursor closedHandCursor];
break;
case Qt::DragMoveCursor:
- [[NSCursor crosshairCursor] set];
+ cocoaCursor = [NSCursor crosshairCursor];
break;
case Qt::DragCopyCursor:
- [[NSCursor crosshairCursor] set];
+ cocoaCursor = [NSCursor crosshairCursor];
break;
case Qt::DragLinkCursor:
- [[NSCursor dragLinkCursor] set];
+ cocoaCursor = [NSCursor dragLinkCursor];
break;
default : {
// No suitable OS cursor exist, use cursors provided
// by Qt for the rest. Check for a cached cursor:
- NSCursor *cocoaCursor = m_cursors.value(newShape);
+ cocoaCursor = m_cursors.value(newShape);
if (cocoaCursor && cursor->shape() == Qt::BitmapCursor) {
[cocoaCursor release];
cocoaCursor = 0;
}
if (cocoaCursor == 0) {
cocoaCursor = createCursorData(cursor);
- if (cocoaCursor == 0) {
- [[NSCursor arrowCursor] set];
- return;
- }
+ if (cocoaCursor == 0)
+ return [NSCursor arrowCursor];
+
m_cursors.insert(newShape, cocoaCursor);
}
- [cocoaCursor set];
break; }
}
+ return cocoaCursor;
}
-QPoint QCocoaCursor::pos() const
-{
- return qt_mac_flipPoint([NSEvent mouseLocation]).toPoint();
-}
-
-void QCocoaCursor::setPos(const QPoint &position)
-{
- CGPoint pos;
- pos.x = position.x();
- pos.y = position.y();
-
- CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0);
- CGEventPost(kCGHIDEventTap, e);
- CFRelease(e);
-}
// Creates an NSCursor for the given QCursor.
NSCursor *QCocoaCursor::createCursorData(QCursor *cursor)
@@ -218,8 +227,8 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor)
return createCursorFromPixmap(pixmap, hotspot);
break; }
case Qt::SizeAllCursor: {
- QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/pluscursor.png"));
- return createCursorFromPixmap(pixmap, hotspot);
+ QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/sizeallcursor.png"));
+ return createCursorFromPixmap(pixmap, QPoint(8, 8));
break; }
case Qt::BusyCursor: {
QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/waitcursor.png"));
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index b3bc4a8ebf..1ad833ee44 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -61,12 +61,12 @@
#include <stdlib.h>
#include <qabstracteventdispatcher.h>
#include "qcocoaautoreleasepool.h"
-#include <QFileSystemWatcher>
#include <QDir>
#include <qpa/qplatformnativeinterface.h>
#import <AppKit/NSSavePanel.h>
+#import <CoreFoundation/CFNumber.h>
QT_FORWARD_DECLARE_CLASS(QString)
QT_FORWARD_DECLARE_CLASS(QStringList)
@@ -74,30 +74,6 @@ QT_FORWARD_DECLARE_CLASS(QFileInfo)
QT_FORWARD_DECLARE_CLASS(QWindow)
QT_USE_NAMESPACE
-class CachedEntries: public QObject {
-public:
- CachedEntries(QDir::Filters filters) : mFilters(filters) {
- QObject::connect(&mFSWatcher, &QFileSystemWatcher::directoryChanged, this, &CachedEntries::updateDirCache);
- }
- QString directory() const {
- const QStringList &dirs = mFSWatcher.directories();
- return (dirs.count() ? dirs[0] : QString());
- }
- QStringList entries() const {
- return mQDirFilterEntryList;
- }
- void updateDirCache(const QString &path) {
- mFSWatcher.removePaths(mFSWatcher.directories());
- mFSWatcher.addPath(path);
- mQDirFilterEntryList = QDir(path).entryList(mFilters);
- }
-
-private:
- QFileSystemWatcher mFSWatcher;
- QStringList mQDirFilterEntryList;
- QDir::Filters mFilters;
-};
-
typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
@class QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate);
@@ -117,7 +93,6 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
int mReturnCode;
SharedPointerFileDialogOptions mOptions;
- CachedEntries *mCachedEntries;
QString *mCurrentSelection;
QStringList *mNameFilterDropDownList;
QStringList *mSelectedNameFilter;
@@ -164,7 +139,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate);
[mSavePanel setDelegate:self];
mReturnCode = -1;
mHelper = helper;
- mCachedEntries = new CachedEntries(mOptions->filter());
mNameFilterDropDownList = new QStringList(mOptions->nameFilters());
QString selectedVisualNameFilter = mOptions->initiallySelectedNameFilter();
mSelectedNameFilter = new QStringList([self findStrippedFilterWithVisualFilterName:selectedVisualNameFilter]);
@@ -197,7 +171,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate);
- (void)dealloc
{
- delete mCachedEntries;
delete mNameFilterDropDownList;
delete mSelectedNameFilter;
delete mCurrentSelection;
@@ -308,6 +281,22 @@ static QString strippedText(QString s)
}];
}
+- (BOOL)isHiddenFile:(NSString *)filename isDir:(BOOL)isDir
+{
+ CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)filename, kCFURLPOSIXPathStyle, isDir);
+ CFBooleanRef isHidden;
+ Boolean errorOrHidden = false;
+ if (!CFURLCopyResourcePropertyForKey(url, kCFURLIsHiddenKey, &isHidden, NULL)) {
+ errorOrHidden = true;
+ } else {
+ if (CFBooleanGetValue(isHidden))
+ errorOrHidden = true;
+ CFRelease(isHidden);
+ }
+ CFRelease(url);
+ return errorOrHidden;
+}
+
- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
{
Q_UNUSED(sender);
@@ -316,8 +305,13 @@ static QString strippedText(QString s)
return NO;
// Always accept directories regardless of their names (unless it is a bundle):
- BOOL isDir;
- if ([[NSFileManager defaultManager] fileExistsAtPath:filename isDirectory:&isDir] && isDir) {
+ NSFileManager *fm = [NSFileManager defaultManager];
+ NSDictionary *fileAttrs = [fm attributesOfItemAtPath:filename error:nil];
+ if (!fileAttrs)
+ return NO; // Error accessing the file means 'no'.
+ NSString *fileType = [fileAttrs fileType];
+ bool isDir = [fileType isEqualToString:NSFileTypeDirectory];
+ if (isDir) {
if ([mSavePanel treatsFilePackagesAsDirectories] == NO) {
if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename] == NO)
return YES;
@@ -325,24 +319,35 @@ static QString strippedText(QString s)
}
QString qtFileName = QCFString::toQString(filename);
- QFileInfo info(qtFileName.normalized(QString::NormalizationForm_C));
- QString path = info.absolutePath();
- if (mCachedEntries->directory() != path) {
- mCachedEntries->updateDirCache(path);
- }
- // Check if the QDir filter accepts the file:
- if (!mCachedEntries->entries().contains(info.fileName()))
- return NO;
-
// No filter means accept everything
- if (mSelectedNameFilter->isEmpty())
- return YES;
+ bool nameMatches = mSelectedNameFilter->isEmpty();
// Check if the current file name filter accepts the file:
- for (int i=0; i<mSelectedNameFilter->size(); ++i) {
+ for (int i = 0; !nameMatches && i < mSelectedNameFilter->size(); ++i) {
if (QDir::match(mSelectedNameFilter->at(i), qtFileName))
- return YES;
+ nameMatches = true;
+ }
+ if (!nameMatches)
+ return NO;
+
+ QDir::Filters filter = mOptions->filter();
+ if ((!(filter & (QDir::Dirs | QDir::AllDirs)) && isDir)
+ || (!(filter & QDir::Files) && [fileType isEqualToString:NSFileTypeRegular])
+ || ((filter & QDir::NoSymLinks) && [fileType isEqualToString:NSFileTypeSymbolicLink]))
+ return NO;
+
+ bool filterPermissions = ((filter & QDir::PermissionMask)
+ && (filter & QDir::PermissionMask) != QDir::PermissionMask);
+ if (filterPermissions) {
+ if ((!(filter & QDir::Readable) && [fm isReadableFileAtPath:filename])
+ || (!(filter & QDir::Writable) && [fm isWritableFileAtPath:filename])
+ || (!(filter & QDir::Executable) && [fm isExecutableFileAtPath:filename]))
+ return NO;
}
- return NO;
+ if (!(filter & QDir::Hidden)
+ && (qtFileName.startsWith(QLatin1Char('.')) || [self isHiddenFile:filename isDir:isDir]))
+ return NO;
+
+ return YES;
}
- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
@@ -461,7 +466,7 @@ static QString strippedText(QString s)
Q_UNUSED(sender);
if (!mHelper)
return;
- if ([path isEqualToString:mCurrentDir])
+ if (!(path && path.length) || [path isEqualToString:mCurrentDir])
return;
[mCurrentDir release];
diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
index 91fb52eb6d..dc22da0983 100644
--- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
@@ -121,6 +121,7 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont)
BOOL mDialogIsExecuting;
BOOL mResultSet;
};
+- (void)restoreOriginalContentView;
- (void)relayout;
- (void)relayoutToContentSize:(NSSize)frameSize;
- (void)updateQtFont;
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h
index 29affb0e4a..e1d4b602c9 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.h
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h
@@ -77,6 +77,7 @@ public:
private:
void setActiveWindow(QWindow *window);
+ void updateSurfaceFormat();
NSOpenGLContext *m_context;
NSOpenGLContext *m_shareContext;
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index 3dee137038..144144338f 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -48,6 +48,74 @@
#import <Cocoa/Cocoa.h>
+static inline QByteArray getGlString(GLenum param)
+{
+ if (const GLubyte *s = glGetString(param))
+ return QByteArray(reinterpret_cast<const char*>(s));
+ return QByteArray();
+}
+
+#if !defined(GL_CONTEXT_FLAGS)
+#define GL_CONTEXT_FLAGS 0x821E
+#endif
+
+#if !defined(GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
+#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001
+#endif
+
+#if !defined(GL_CONTEXT_PROFILE_MASK)
+#define GL_CONTEXT_PROFILE_MASK 0x9126
+#endif
+
+#if !defined(GL_CONTEXT_CORE_PROFILE_BIT)
+#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
+#endif
+
+#if !defined(GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
+#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
+#endif
+
+static void updateFormatFromContext(QSurfaceFormat *format)
+{
+ Q_ASSERT(format);
+
+ // Update the version, profile, and context bit of the format
+ int major = 0, minor = 0;
+ QByteArray versionString(getGlString(GL_VERSION));
+ if (QPlatformOpenGLContext::parseOpenGLVersion(versionString, major, minor)) {
+ format->setMajorVersion(major);
+ format->setMinorVersion(minor);
+ }
+
+ format->setProfile(QSurfaceFormat::NoProfile);
+
+ Q_ASSERT(format->renderableType() == QSurfaceFormat::OpenGL);
+ if (format->version() < qMakePair(3, 0)) {
+ format->setOption(QSurfaceFormat::DeprecatedFunctions);
+ return;
+ }
+
+ // Version 3.0 onwards - check if it includes deprecated functionality
+ GLint value = 0;
+ glGetIntegerv(GL_CONTEXT_FLAGS, &value);
+ if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT))
+ format->setOption(QSurfaceFormat::DeprecatedFunctions);
+
+ // Debug context option not supported on OS X
+
+ if (format->version() < qMakePair(3, 2))
+ return;
+
+ // Version 3.2 and newer have a profile
+ value = 0;
+ glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
+
+ if (value & GL_CONTEXT_CORE_PROFILE_BIT)
+ format->setProfile(QSurfaceFormat::CoreProfile);
+ else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
+ format->setProfile(QSurfaceFormat::CompatibilityProfile);
+}
+
QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share)
: m_context(nil),
m_shareContext(nil),
@@ -82,6 +150,8 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo
int zeroOpacity = 0;
[m_context setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity];
}
+
+ updateSurfaceFormat();
}
QCocoaGLContext::~QCocoaGLContext()
@@ -112,6 +182,8 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
QWindow *window = static_cast<QCocoaWindow *>(surface)->window();
setActiveWindow(window);
+ if (![m_context view])
+ return false;
[m_context makeCurrentContext];
update();
return true;
@@ -135,6 +207,74 @@ void QCocoaGLContext::setActiveWindow(QWindow *window)
[(QNSView *) cocoaWindow->contentView() setQCocoaGLContext:this];
}
+void QCocoaGLContext::updateSurfaceFormat()
+{
+ // At present it is impossible to turn an option off on a QSurfaceFormat (see
+ // https://codereview.qt-project.org/#change,70599). So we have to populate
+ // the actual surface format from scratch
+ QSurfaceFormat requestedFormat = m_format;
+ m_format = QSurfaceFormat();
+ m_format.setRenderableType(QSurfaceFormat::OpenGL);
+
+ // CoreGL doesn't require a drawable to make the context current
+ CGLContextObj oldContext = CGLGetCurrentContext();
+ CGLContextObj ctx = static_cast<CGLContextObj>([m_context CGLContextObj]);
+ CGLSetCurrentContext(ctx);
+
+ // Get the data that OpenGL provides
+ updateFormatFromContext(&m_format);
+
+ // Get the data contained within the pixel format
+ CGLPixelFormatObj cglPixelFormat = static_cast<CGLPixelFormatObj>(CGLGetPixelFormat(ctx));
+ NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithCGLPixelFormatObj:cglPixelFormat];
+
+ int colorSize = -1;
+ [pixelFormat getValues:&colorSize forAttribute:NSOpenGLPFAColorSize forVirtualScreen:0];
+ if (colorSize > 0) {
+ // This seems to return the total color buffer depth, including alpha
+ m_format.setRedBufferSize(colorSize / 4);
+ m_format.setGreenBufferSize(colorSize / 4);
+ m_format.setBlueBufferSize(colorSize / 4);
+ }
+
+ // The pixel format always seems to return 8 for alpha. However, the framebuffer only
+ // seems to have alpha enabled if we requested it explicitly. I can't find any other
+ // attribute to check explicitly for this so we use our best guess for alpha.
+ int alphaSize = -1;
+ [pixelFormat getValues:&alphaSize forAttribute:NSOpenGLPFAAlphaSize forVirtualScreen:0];
+ if (alphaSize > 0 && requestedFormat.alphaBufferSize() > 0)
+ m_format.setAlphaBufferSize(alphaSize);
+
+ int depthSize = -1;
+ [pixelFormat getValues:&depthSize forAttribute:NSOpenGLPFADepthSize forVirtualScreen:0];
+ if (depthSize > 0)
+ m_format.setDepthBufferSize(depthSize);
+
+ int stencilSize = -1;
+ [pixelFormat getValues:&stencilSize forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0];
+ if (stencilSize > 0)
+ m_format.setStencilBufferSize(stencilSize);
+
+ int samples = -1;
+ [pixelFormat getValues:&samples forAttribute:NSOpenGLPFASamples forVirtualScreen:0];
+ if (samples > 0)
+ m_format.setSamples(samples);
+
+ int doubleBuffered = -1;
+ [pixelFormat getValues:&doubleBuffered forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:0];
+ m_format.setSwapBehavior(doubleBuffered == 1 ? QSurfaceFormat::DoubleBuffer : QSurfaceFormat::SingleBuffer);
+
+ int steroBuffers = -1;
+ [pixelFormat getValues:&steroBuffers forAttribute:NSOpenGLPFAStereo forVirtualScreen:0];
+ if (steroBuffers == 1)
+ m_format.setOption(QSurfaceFormat::StereoBuffers);
+
+ [pixelFormat release];
+
+ // Restore the original context
+ CGLSetCurrentContext(oldContext);
+}
+
void QCocoaGLContext::doneCurrent()
{
if (m_currentWindow && m_currentWindow.data()->handle())
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index 197a2058af..4a5696b35e 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -599,7 +599,17 @@ NSRect qt_mac_flipRect(const QRect &rect, QWindow *window)
{
QPlatformScreen *onScreen = QPlatformScreen::platformScreenForWindow(window);
int flippedY = onScreen->geometry().height() - (rect.y() + rect.height());
-
+ QList<QScreen *> screens = QGuiApplication::screens();
+ if (screens.size() > 1) {
+ int height = 0;
+ foreach (QScreen *scr, screens)
+ height = qMax(height, scr->size().height());
+ int difference = height - onScreen->geometry().height();
+ if (difference > 0)
+ flippedY += difference;
+ else
+ flippedY -= difference;
+ }
// In case of automatic positioning, try to put as much of the window onscreen as possible.
if (window->isTopLevel() && qt_window_private(const_cast<QWindow*>(window))->positionAutomatic && flippedY < 0)
flippedY = onScreen->geometry().height() - onScreen->availableGeometry().height() - onScreen->availableGeometry().y();
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 2e42b9acda..0af635be6f 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -63,7 +63,6 @@
static void initResources()
{
- Q_INIT_RESOURCE_EXTERN(qcocoaresources)
Q_INIT_RESOURCE(qcocoaresources);
}
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 14b8dee101..329c7a264a 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -84,6 +84,7 @@ static inline QCocoaMenuLoader *getMenuLoader()
}
- (id) initWithMenu:(QCocoaMenu*) m;
+- (BOOL)hasShortcut:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier;
@end
@@ -465,17 +466,21 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, QPoint pos, const QPlatf
nsPos.y = screen->availableVirtualSize().height() - nsPos.y;
}
- // Finally, we need to synthesize an event.
- NSEvent *menuEvent = [NSEvent mouseEventWithType:NSRightMouseDown
- location:nsPos
- modifierFlags:0
- timestamp:0
- windowNumber:view ? view.window.windowNumber : 0
- context:nil
- eventNumber:0
- clickCount:1
- pressure:1.0];
- [NSMenu popUpContextMenu:m_nativeMenu withEvent:menuEvent forView:view];
+ if (view) {
+ // Finally, we need to synthesize an event.
+ NSEvent *menuEvent = [NSEvent mouseEventWithType:NSRightMouseDown
+ location:nsPos
+ modifierFlags:0
+ timestamp:0
+ windowNumber:view ? view.window.windowNumber : 0
+ context:nil
+ eventNumber:0
+ clickCount:1
+ pressure:1.0];
+ [NSMenu popUpContextMenu:m_nativeMenu withEvent:menuEvent forView:view];
+ } else {
+ [m_nativeMenu popUpMenuPositioningItem:nsItem atLocation:nsPos inView:0];
+ }
}
// The calls above block, and also swallow any mouse release event,
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index 0fea55ac68..5a8664747e 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -175,6 +175,7 @@ void QCocoaMenuBar::handleReparent(QWindow *newParentWindow)
if (newParentWindow == NULL) {
m_window = NULL;
} else {
+ newParentWindow->create();
m_window = static_cast<QCocoaWindow*>(newParentWindow->handle());
m_window->setMenubar(this);
}
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index 013f9931ff..3bba1ee1d5 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -338,6 +338,8 @@ QString QCocoaMenuItem::mergeText()
return qt_mac_applicationmenu_string(4);
} else if (m_native == [loader quitMenuItem]) {
return qt_mac_applicationmenu_string(5).arg(qt_mac_applicationName());
+ } else if (m_text.contains('\t')) {
+ return m_text.left(m_text.indexOf('\t'));
}
return m_text;
}
@@ -349,6 +351,8 @@ QKeySequence QCocoaMenuItem::mergeAccel()
return QKeySequence(QKeySequence::Preferences);
else if (m_native == [loader quitMenuItem])
return QKeySequence(QKeySequence::Quit);
+ else if (m_text.contains('\t'))
+ return QKeySequence(m_text.mid(m_text.indexOf('\t') + 1), QKeySequence::NativeText);
return m_shortcut;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaresources.qrc b/src/plugins/platforms/cocoa/qcocoaresources.qrc
index 392300bb03..9e0640db7d 100644
--- a/src/plugins/platforms/cocoa/qcocoaresources.qrc
+++ b/src/plugins/platforms/cocoa/qcocoaresources.qrc
@@ -4,7 +4,7 @@
<file>images/forbiddencursor.png</file>
<file>images/spincursor.png</file>
<file>images/waitcursor.png</file>
-<file>images/pluscursor.png</file>
+<file>images/sizeallcursor.png</file>
</qresource>
<qresource prefix="/qt-project.org/mac/style">
<file>images/leopard-unified-toolbar-on.png</file>
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index 7f0f07e912..4f5a208f43 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -154,6 +154,8 @@ public:
void setMenubar(QCocoaMenuBar *mb);
QCocoaMenuBar *menubar() const;
+ void setWindowCursor(NSCursor *cursor);
+
void registerTouch(bool enable);
qreal devicePixelRatio() const;
@@ -190,11 +192,13 @@ public: // for QNSView
Qt::WindowState m_synchedWindowState;
Qt::WindowModality m_windowModality;
QPointer<QWindow> m_activePopupWindow;
- QPointer<QWindow> m_underMouseWindow;
+ QPointer<QWindow> m_enterLeaveTargetWindow;
+ bool m_windowUnderMouse;
bool m_inConstructor;
QCocoaGLContext *m_glContext;
QCocoaMenuBar *m_menubar;
+ NSCursor *m_windowCursor;
bool m_hasModalSession;
bool m_frameStrutEventsEnabled;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 845cc1202f..4da47f4f1f 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -206,9 +206,11 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_nsWindowDelegate(0)
, m_synchedWindowState(Qt::WindowActive)
, m_windowModality(Qt::NonModal)
+ , m_windowUnderMouse(false)
, m_inConstructor(true)
, m_glContext(0)
, m_menubar(0)
+ , m_windowCursor(0)
, m_hasModalSession(false)
, m_frameStrutEventsEnabled(false)
, m_isExposed(false)
@@ -463,19 +465,19 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
{
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
NSInteger styleMask = NSBorderlessWindowMask;
+ if (flags & Qt::FramelessWindowHint)
+ return styleMask;
if ((type & Qt::Popup) == Qt::Popup) {
- if (!windowIsPopupType(type) && !(flags & Qt::FramelessWindowHint))
+ if (!windowIsPopupType(type))
styleMask = (NSUtilityWindowMask | NSResizableWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSTitledWindowMask);
} else {
- // Filter flags for supported properties
- flags &= Qt::WindowType_Mask | Qt::FramelessWindowHint | Qt::WindowTitleHint |
- Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::CustomizeWindowHint;
- if (flags == Qt::Window) {
+ if (type == Qt::Window && !(flags & Qt::CustomizeWindowHint)) {
styleMask = (NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask);
- } else if ((flags & Qt::Dialog) == Qt::Dialog) {
+ } else if (type == Qt::Dialog) {
if (flags & Qt::CustomizeWindowHint) {
- styleMask = NSResizableWindowMask;
+ if (flags & Qt::WindowMaximizeButtonHint)
+ styleMask = NSResizableWindowMask;
if (flags & Qt::WindowTitleHint)
styleMask |= NSTitledWindowMask;
if (flags & Qt::WindowCloseButtonHint)
@@ -485,8 +487,8 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
} else {
styleMask = NSResizableWindowMask | NSClosableWindowMask | NSTitledWindowMask;
}
- } else if (!(flags & Qt::FramelessWindowHint)) {
- if ((flags & Qt::Dialog) || (flags & Qt::WindowMaximizeButtonHint))
+ } else {
+ if (flags & Qt::WindowMaximizeButtonHint)
styleMask |= NSResizableWindowMask;
if (flags & Qt::WindowTitleHint)
styleMask |= NSTitledWindowMask;
@@ -711,7 +713,10 @@ WId QCocoaWindow::winId() const
void QCocoaWindow::setParent(const QPlatformWindow *parentWindow)
{
// recreate the window for compatibility
+ bool unhideAfterRecreate = parentWindow && !m_contentViewIsToBeEmbedded && ![m_contentView isHidden];
recreateWindow(parentWindow);
+ if (unhideAfterRecreate)
+ [m_contentView setHidden:NO];
setCocoaGeometry(geometry());
}
@@ -1030,6 +1035,23 @@ QCocoaMenuBar *QCocoaWindow::menubar() const
return m_menubar;
}
+void QCocoaWindow::setWindowCursor(NSCursor *cursor)
+{
+ // This function is called (via QCocoaCursor) by Qt to set
+ // the cursor for this window. It can be called for a window
+ // that is not currenly under the mouse pointer (for example
+ // for a popup window.) Qt expects the set cursor to "stick":
+ // it should be accociated with the window until a different
+ // cursor is set.
+
+ // Cocoa has different abstractions. We can set the cursor *now*:
+ if (m_windowUnderMouse)
+ [cursor set];
+ // or we can set the cursor on mouse enter/leave using tracking
+ // areas. This is done in QNSView, save the cursor:
+ m_windowCursor = cursor;
+}
+
void QCocoaWindow::registerTouch(bool enable)
{
m_registerTouchCount += enable ? 1 : -1;
diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm
index 95143fd8ea..b5c50d676f 100644
--- a/src/plugins/platforms/cocoa/qmacclipboard.mm
+++ b/src/plugins/platforms/cocoa/qmacclipboard.mm
@@ -105,7 +105,8 @@ QMacPasteboard::~QMacPasteboard()
for (int i = 0; i < promises.count(); ++i) {
const Promise &promise = promises.at(i);
QCFString flavor = QCFString(promise.convertor->flavorFor(promise.mime));
- promiseKeeper(paste, (PasteboardItemID)promise.itemId, flavor, this);
+ NSInteger pbItemId = promise.itemId;
+ promiseKeeper(paste, reinterpret_cast<PasteboardItemID>(pbItemId), flavor, this);
}
if (paste)
@@ -311,9 +312,9 @@ QMacPasteboard::setMimeData(QMimeData *mime_src)
int numItems = c->count(mime_src);
for (int item = 0; item < numItems; ++item) {
- const int itemID = item+1; //id starts at 1
+ const NSInteger itemID = item+1; //id starts at 1
promises.append(QMacPasteboard::Promise(itemID, c, mimeType, mimeData, item));
- PasteboardPutItemFlavor(paste, (PasteboardItemID)itemID, QCFString(flavor), 0, kPasteboardFlavorNoFlags);
+ PasteboardPutItemFlavor(paste, reinterpret_cast<PasteboardItemID>(itemID), QCFString(flavor), 0, kPasteboardFlavorNoFlags);
#ifdef DEBUG_PASTEBOARD
qDebug(" - adding %d %s [%s] <%s> [%d]",
itemID, qPrintable(mimeType), qPrintable(flavor), qPrintable(c->convertorName()), item);
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index f90fc6b205..71c4de3b69 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -496,7 +496,7 @@ static QTouchDevice *touchDevice = 0;
return YES;
}
-- (void)convertFromEvent:(NSEvent *)event toWindowPoint:(QPointF *)qtWindowPoint andScreenPoint:(QPointF *)qtScreenPoint
+- (void)convertFromScreen:(NSPoint)mouseLocation toWindowPoint:(QPointF *)qtWindowPoint andScreenPoint:(QPointF *)qtScreenPoint
{
// Calculate the mouse position in the QWindow and Qt screen coordinate system,
// starting from coordinates in the NSWindow coordinate system.
@@ -516,23 +516,22 @@ static QTouchDevice *touchDevice = 0;
// NSView and QWindow are equal coordinate systems: the QWindow covers the
// entire NSView, and we've set the NSView's isFlipped property to true.
- NSPoint nsWindowPoint = [event locationInWindow]; // NSWindow coordinates
-
- NSPoint nsViewPoint = [self convertPoint: nsWindowPoint fromView: nil]; // NSView/QWindow coordinates
- *qtWindowPoint = QPointF(nsViewPoint.x, nsViewPoint.y); // NSView/QWindow coordinates
-
NSWindow *window = [self window];
+ NSPoint nsWindowPoint;
// Use convertRectToScreen if available (added in 10.7).
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
- if ([window respondsToSelector:@selector(convertRectToScreen:)]) {
- NSRect screenRect = [window convertRectToScreen : NSMakeRect(nsWindowPoint.x, nsWindowPoint.y, 0, 0)]; // OS X screen coordinates
- *qtScreenPoint = QPointF(screenRect.origin.x, qt_mac_flipYCoordinate(screenRect.origin.y)); // Qt screen coordinates
+ if ([window respondsToSelector:@selector(convertRectFromScreen:)]) {
+ NSRect windowRect = [window convertRectFromScreen:NSMakeRect(mouseLocation.x, mouseLocation.y, 1, 1)];
+ nsWindowPoint = windowRect.origin; // NSWindow coordinates
} else
#endif
{
- NSPoint screenPoint = [window convertBaseToScreen : NSMakePoint(nsWindowPoint.x, nsWindowPoint.y)];
- *qtScreenPoint = QPointF(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y));
+ nsWindowPoint = [window convertScreenToBase:mouseLocation]; // NSWindow coordinates
}
+ NSPoint nsViewPoint = [self convertPoint: nsWindowPoint fromView: nil]; // NSView/QWindow coordinates
+ *qtWindowPoint = QPointF(nsViewPoint.x, nsViewPoint.y); // NSView/QWindow coordinates
+
+ *qtScreenPoint = QPointF(mouseLocation.x, qt_mac_flipYCoordinate(mouseLocation.y)); // Qt screen coordinates
}
- (void)resetMouseButtons
@@ -546,7 +545,7 @@ static QTouchDevice *touchDevice = 0;
QPointF qtWindowPoint;
QPointF qtScreenPoint;
- [self convertFromEvent:theEvent toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
+ [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
ulong timestamp = [theEvent timestamp] * 1000;
QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
@@ -672,7 +671,7 @@ static QTouchDevice *touchDevice = 0;
// mouse moves delivered to it (Apple recommends keeping it OFF because there
// is a performance hit). So it goes.
NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp
- | NSTrackingInVisibleRect | NSTrackingMouseMoved;
+ | NSTrackingInVisibleRect | NSTrackingMouseMoved | NSTrackingCursorUpdate;
NSTrackingArea *ta = [[[NSTrackingArea alloc] initWithRect:[self frame]
options:trackingOptions
owner:self
@@ -681,6 +680,13 @@ static QTouchDevice *touchDevice = 0;
[self addTrackingArea:ta];
}
+-(void)cursorUpdate:(NSEvent *)theEvent
+{
+ Q_UNUSED(theEvent)
+ if (m_platformWindow->m_windowCursor)
+ [m_platformWindow->m_windowCursor set];
+}
+
- (void)mouseMoved:(NSEvent *)theEvent
{
if (m_window->flags() & Qt::WindowTransparentForInput)
@@ -688,7 +694,7 @@ static QTouchDevice *touchDevice = 0;
QPointF windowPoint;
QPointF screenPoint;
- [self convertFromEvent:theEvent toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
QWindow *childWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
// Top-level windows generate enter-leave events for sub-windows.
@@ -697,9 +703,9 @@ static QTouchDevice *touchDevice = 0;
// handling mouseEnter and mouseLeave envents, since they are sent
// individually to different views.
if (m_platformWindow->m_nsWindow && childWindow) {
- if (childWindow != m_platformWindow->m_underMouseWindow) {
- QWindowSystemInterface::handleEnterLeaveEvent(childWindow, m_platformWindow->m_underMouseWindow, windowPoint, screenPoint);
- m_platformWindow->m_underMouseWindow = childWindow;
+ if (childWindow != m_platformWindow->m_enterLeaveTargetWindow) {
+ QWindowSystemInterface::handleEnterLeaveEvent(childWindow, m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
+ m_platformWindow->m_enterLeaveTargetWindow = childWindow;
}
}
@@ -713,6 +719,8 @@ static QTouchDevice *touchDevice = 0;
- (void)mouseEntered:(NSEvent *)theEvent
{
+ m_platformWindow->m_windowUnderMouse = true;
+
if (m_window->flags() & Qt::WindowTransparentForInput)
return [super mouseEntered:theEvent];
@@ -722,13 +730,15 @@ static QTouchDevice *touchDevice = 0;
QPointF windowPoint;
QPointF screenPoint;
- [self convertFromEvent:theEvent toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- m_platformWindow->m_underMouseWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
- QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_underMouseWindow, windowPoint, screenPoint);
+ [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ m_platformWindow->m_enterLeaveTargetWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
+ QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
}
- (void)mouseExited:(NSEvent *)theEvent
{
+ m_platformWindow->m_windowUnderMouse = false;
+
if (m_window->flags() & Qt::WindowTransparentForInput)
return [super mouseExited:theEvent];
Q_UNUSED(theEvent);
@@ -737,8 +747,8 @@ static QTouchDevice *touchDevice = 0;
if (!m_platformWindow->m_nsWindow)
return;
- QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_underMouseWindow);
- m_platformWindow->m_underMouseWindow = 0;
+ QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_enterLeaveTargetWindow);
+ m_platformWindow->m_enterLeaveTargetWindow = 0;
}
- (void)rightMouseDown:(NSEvent *)theEvent
@@ -812,7 +822,7 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
QPointF windowPoint;
QPointF screenPoint;
- [self convertFromEvent: theEvent toWindowPoint: &windowPoint andScreenPoint: &screenPoint];
+ [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint: &windowPoint andScreenPoint: &screenPoint];
uint deviceId = [theEvent deviceID];
if (!tabletDeviceDataHash->contains(deviceId)) {
@@ -985,7 +995,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
- [self convertFromEvent:event toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
QWindowSystemInterface::handleGestureEventWithRealValue(m_window, timestamp, Qt::ZoomNativeGesture,
[event magnification], windowPoint, screenPoint);
}
@@ -1000,7 +1010,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
- [self convertFromEvent:event toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
QWindowSystemInterface::handleGestureEventWithRealValue(m_window, timestamp, Qt::SmartZoomNativeGesture,
zoomIn ? 1.0f : 0.0f, windowPoint, screenPoint);
zoomIn = !zoomIn;
@@ -1015,7 +1025,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
- [self convertFromEvent:event toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
QWindowSystemInterface::handleGestureEventWithRealValue(m_window, timestamp, Qt::RotateNativeGesture,
-[event rotation], windowPoint, screenPoint);
}
@@ -1028,7 +1038,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
- [self convertFromEvent:event toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
qreal angle = 0.0f;
if ([event deltaX] == 1)
@@ -1052,7 +1062,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
- [self convertFromEvent:event toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
QWindowSystemInterface::handleGestureEvent(m_window, timestamp, Qt::BeginNativeGesture,
windowPoint, screenPoint);
}
@@ -1065,7 +1075,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
- [self convertFromEvent:event toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
QWindowSystemInterface::handleGestureEvent(m_window, timestamp, Qt::EndNativeGesture,
windowPoint, screenPoint);
}
@@ -1125,7 +1135,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
QPointF qt_windowPoint;
QPointF qt_screenPoint;
- [self convertFromEvent:theEvent toWindowPoint:&qt_windowPoint andScreenPoint:&qt_screenPoint];
+ [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&qt_windowPoint andScreenPoint:&qt_screenPoint];
NSTimeInterval timestamp = [theEvent timestamp];
ulong qt_timestamp = timestamp * 1000;
diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
index 86e5066fbb..e8f26aa8c4 100644
--- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
@@ -47,7 +47,7 @@
#include "qcocoaaccessibilityelement.h"
#include <qpa/qplatformintegration.h>
-#include <QtGui/private/qaccessible2_p.h>
+#include <QtGui/qaccessible.h>
#include <QtCore/QDebug>
#import <AppKit/NSAccessibility.h>
diff --git a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp
index 8de8268616..03531916cf 100644
--- a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp
@@ -113,7 +113,7 @@ void QEglFSBackingStore::flush(QWindow *window, const QRegion &region, const QPo
#endif
QEglFSWindow *rootWin = m_window->screen()->rootWindow();
- if (!rootWin)
+ if (!rootWin || !rootWin->isRaster())
return;
m_window->create();
@@ -132,13 +132,14 @@ void QEglFSBackingStore::resize(const QSize &size, const QRegion &staticContents
Q_UNUSED(staticContents);
QEglFSWindow *rootWin = m_window->screen()->rootWindow();
- if (!rootWin)
+ if (!rootWin || !rootWin->isRaster())
return;
m_image = QImage(size, QImage::Format_RGB32);
m_window->create();
rootWin->screen()->rootContext()->makeCurrent(rootWin->window());
+ initializeOpenGLFunctions();
if (m_texture)
glDeleteTextures(1, &m_texture);
diff --git a/src/plugins/platforms/eglfs/qeglfsbackingstore.h b/src/plugins/platforms/eglfs/qeglfsbackingstore.h
index 535428aac1..9af856e8e7 100644
--- a/src/plugins/platforms/eglfs/qeglfsbackingstore.h
+++ b/src/plugins/platforms/eglfs/qeglfsbackingstore.h
@@ -43,6 +43,7 @@
#define QEGLFSBACKINGSTORE_H
#include <qpa/qplatformbackingstore.h>
+#include <QtGui/QOpenGLFunctions>
#include <QImage>
#include <QRegion>
@@ -52,7 +53,7 @@ QT_BEGIN_NAMESPACE
class QOpenGLPaintDevice;
class QEglFSWindow;
-class QEglFSBackingStore : public QPlatformBackingStore
+class QEglFSBackingStore : public QPlatformBackingStore, public QOpenGLFunctions
{
public:
QEglFSBackingStore(QWindow *window);
diff --git a/src/plugins/platforms/eglfs/qeglfscompositor.cpp b/src/plugins/platforms/eglfs/qeglfscompositor.cpp
index 9db43a57a1..845bb5b3b5 100644
--- a/src/plugins/platforms/eglfs/qeglfscompositor.cpp
+++ b/src/plugins/platforms/eglfs/qeglfscompositor.cpp
@@ -53,7 +53,8 @@ static QEglFSCompositor *compositor = 0;
QEglFSCompositor::QEglFSCompositor()
: m_screen(0),
- m_program(0)
+ m_program(0),
+ m_initialized(false)
{
Q_ASSERT(!compositor);
m_updateTimer.setSingleShot(true);
@@ -86,6 +87,10 @@ void QEglFSCompositor::renderAll()
Q_ASSERT(context);
context->makeCurrent(rootWin->window());
+ if (!m_initialized) {
+ initializeOpenGLFunctions();
+ m_initialized = true;
+ }
ensureProgram();
m_program->bind();
diff --git a/src/plugins/platforms/eglfs/qeglfscompositor.h b/src/plugins/platforms/eglfs/qeglfscompositor.h
index ade2e06031..0d5daafa2c 100644
--- a/src/plugins/platforms/eglfs/qeglfscompositor.h
+++ b/src/plugins/platforms/eglfs/qeglfscompositor.h
@@ -42,7 +42,8 @@
#ifndef QEGLFSCOMPOSITOR_H
#define QEGLFSCOMPOSITOR_H
-#include <QTimer>
+#include <QtCore/QTimer>
+#include <QtGui/QOpenGLFunctions>
QT_BEGIN_NAMESPACE
@@ -50,7 +51,7 @@ class QEglFSScreen;
class QEglFSWindow;
class QOpenGLShaderProgram;
-class QEglFSCompositor : public QObject
+class QEglFSCompositor : public QObject, public QOpenGLFunctions
{
Q_OBJECT
@@ -76,6 +77,7 @@ private:
int m_vertexCoordEntry;
int m_textureCoordEntry;
int m_isRasterEntry;
+ bool m_initialized;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfscursor.cpp b/src/plugins/platforms/eglfs/qeglfscursor.cpp
index c00e86de35..0066426769 100644
--- a/src/plugins/platforms/eglfs/qeglfscursor.cpp
+++ b/src/plugins/platforms/eglfs/qeglfscursor.cpp
@@ -79,7 +79,7 @@ void QEglFSCursor::resetResources()
m_cursorAtlas.texture = 0;
}
-static GLuint createShader(GLenum shaderType, const char *program)
+GLuint QEglFSCursor::createShader(GLenum shaderType, const char *program)
{
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1 /* count */, &program, NULL /* lengths */);
@@ -98,7 +98,7 @@ static GLuint createShader(GLenum shaderType, const char *program)
return 0;
}
-static GLuint createProgram(GLuint vshader, GLuint fshader)
+GLuint QEglFSCursor::createProgram(GLuint vshader, GLuint fshader)
{
GLuint program = glCreateProgram();
glAttachShader(program, vshader);
@@ -286,6 +286,7 @@ void QEglFSCursor::draw(const QRectF &r)
{
if (!m_program) {
// one time initialization
+ initializeOpenGLFunctions();
createShaderPrograms();
if (!m_cursorAtlas.texture) {
diff --git a/src/plugins/platforms/eglfs/qeglfscursor.h b/src/plugins/platforms/eglfs/qeglfscursor.h
index 51a34e041d..71ff73b8f3 100644
--- a/src/plugins/platforms/eglfs/qeglfscursor.h
+++ b/src/plugins/platforms/eglfs/qeglfscursor.h
@@ -43,15 +43,15 @@
#define QEGLFSCURSOR_H
#include <qpa/qplatformcursor.h>
+#include <QtGui/QOpenGLFunctions>
#include "qeglfsscreen.h"
-#include <GLES2/gl2.h>
QT_BEGIN_NAMESPACE
class QOpenGLShaderProgram;
class QEglFSScreen;
-class QEglFSCursor : public QPlatformCursor
+class QEglFSCursor : public QPlatformCursor, public QOpenGLFunctions
{
public:
QEglFSCursor(QEglFSScreen *screen);
@@ -78,6 +78,9 @@ protected:
void draw(const QRectF &rect);
void update(const QRegion &region);
+ GLuint createShader(GLenum shaderType, const char *program);
+ GLuint createProgram(GLuint vshader, GLuint fshader);
+
QEglFSScreen *m_screen;
// current cursor information
diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
index 67f0c35ed7..55a822b887 100644
--- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
@@ -74,35 +74,20 @@
#include <EGL/egl.h>
+static void initResources()
+{
+ Q_INIT_RESOURCE(cursor);
+}
+
QT_BEGIN_NAMESPACE
QEglFSIntegration::QEglFSIntegration()
: mFontDb(new QGenericUnixFontDatabase)
, mServices(new QGenericUnixServices)
+ , mScreen(0)
, mInputContext(0)
{
- QEglFSHooks::hooks()->platformInit();
-
- EGLint major, minor;
-
- if (!eglBindAPI(EGL_OPENGL_ES_API)) {
- qWarning("Could not bind GL_ES API\n");
- qFatal("EGL error");
- }
-
- mDisplay = eglGetDisplay(QEglFSHooks::hooks() ? QEglFSHooks::hooks()->platformDisplay() : EGL_DEFAULT_DISPLAY);
- if (mDisplay == EGL_NO_DISPLAY) {
- qWarning("Could not open egl display\n");
- qFatal("EGL error");
- }
-
- if (!eglInitialize(mDisplay, &major, &minor)) {
- qWarning("Could not initialize egl display\n");
- qFatal("EGL error");
- }
-
- mScreen = new QEglFSScreen(mDisplay);
- screenAdded(mScreen);
+ initResources();
}
QEglFSIntegration::~QEglFSIntegration()
@@ -166,10 +151,39 @@ QAbstractEventDispatcher *QEglFSIntegration::createEventDispatcher() const
void QEglFSIntegration::initialize()
{
+ QEglFSHooks::hooks()->platformInit();
+
+ EGLint major, minor;
+
+ if (!eglBindAPI(EGL_OPENGL_ES_API)) {
+ qWarning("Could not bind GL_ES API\n");
+ qFatal("EGL error");
+ }
+
+ mDisplay = eglGetDisplay(QEglFSHooks::hooks() ? QEglFSHooks::hooks()->platformDisplay() : EGL_DEFAULT_DISPLAY);
+ if (mDisplay == EGL_NO_DISPLAY) {
+ qWarning("Could not open egl display\n");
+ qFatal("EGL error");
+ }
+
+ if (!eglInitialize(mDisplay, &major, &minor)) {
+ qWarning("Could not initialize egl display\n");
+ qFatal("EGL error");
+ }
+
+ mScreen = createScreen();
+ screenAdded(mScreen);
+
mInputContext = QPlatformInputContextFactory::create();
+
createInputHandlers();
}
+QEglFSScreen *QEglFSIntegration::createScreen() const
+{
+ return new QEglFSScreen(mDisplay);
+}
+
QVariant QEglFSIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
{
switch (hint)
diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h
index a6fcfc8427..f685eec2d4 100644
--- a/src/plugins/platforms/eglfs/qeglfsintegration.h
+++ b/src/plugins/platforms/eglfs/qeglfsintegration.h
@@ -86,6 +86,9 @@ public:
QPlatformInputContext *inputContext() const { return mInputContext; }
+protected:
+ virtual QEglFSScreen *createScreen() const;
+
private:
void createInputHandlers();
diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/qeglfsscreen.cpp
index 3f92d60aa2..758b461b3f 100644
--- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsscreen.cpp
@@ -126,26 +126,34 @@ void QEglFSScreen::setPrimarySurface(EGLSurface surface)
void QEglFSScreen::addWindow(QEglFSWindow *window)
{
- if (!m_windows.contains(window))
+ if (!m_windows.contains(window)) {
m_windows.append(window);
+ topWindowChanged(window);
+ }
}
void QEglFSScreen::removeWindow(QEglFSWindow *window)
{
m_windows.removeOne(window);
+ if (!m_windows.isEmpty())
+ topWindowChanged(m_windows.last());
}
void QEglFSScreen::moveToTop(QEglFSWindow *window)
{
m_windows.removeOne(window);
m_windows.append(window);
+ topWindowChanged(window);
}
void QEglFSScreen::changeWindowIndex(QEglFSWindow *window, int newIdx)
{
int idx = m_windows.indexOf(window);
- if (idx != -1 && idx != newIdx)
+ if (idx != -1 && idx != newIdx) {
m_windows.move(idx, newIdx);
+ if (newIdx == m_windows.size() - 1)
+ topWindowChanged(m_windows.last());
+ }
}
QEglFSWindow *QEglFSScreen::rootWindow()
@@ -157,4 +165,9 @@ QEglFSWindow *QEglFSScreen::rootWindow()
return 0;
}
+void QEglFSScreen::topWindowChanged(QPlatformWindow *window)
+{
+ Q_UNUSED(window);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h
index 578a6cf20d..11d66b7e0f 100644
--- a/src/plugins/platforms/eglfs/qeglfsscreen.h
+++ b/src/plugins/platforms/eglfs/qeglfsscreen.h
@@ -85,6 +85,7 @@ public:
protected:
void setPrimarySurface(EGLSurface surface);
+ virtual void topWindowChanged(QPlatformWindow *window);
private:
friend class QEglFSWindow;
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp
index d6f233b6c5..cc0e64a83b 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp
@@ -210,15 +210,17 @@ void QEglFSWindow::setVisible(bool visible)
void QEglFSWindow::setGeometry(const QRect &r)
{
QRect rect;
- if (m_flags.testFlag(HasNativeWindow))
+ bool forceFullscreen = m_flags.testFlag(HasNativeWindow);
+ if (forceFullscreen)
rect = screen()->availableGeometry();
else
rect = r;
QPlatformWindow::setGeometry(rect);
+ // if we corrected the size, trigger a resize event
if (rect != r)
- QWindowSystemInterface::handleGeometryChange(window(), rect);
+ QWindowSystemInterface::handleGeometryChange(window(), rect, r);
}
QRect QEglFSWindow::geometry() const
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.h b/src/plugins/platforms/ios/qiosapplicationdelegate.h
index bfe31af198..617b740d6e 100644
--- a/src/plugins/platforms/ios/qiosapplicationdelegate.h
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.h
@@ -47,6 +47,5 @@
@interface QIOSApplicationDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
-@property (strong, nonatomic) QIOSViewController *qiosViewController;
@end
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
index e06d2b8840..cf702c82af 100644
--- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
@@ -49,7 +49,6 @@
@implementation QIOSApplicationDelegate
@synthesize window;
-@synthesize qiosViewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
@@ -57,21 +56,34 @@
Q_UNUSED(launchOptions);
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
- self.qiosViewController = [[[QIOSViewController alloc] init] autorelease];
- self.window.rootViewController = self.qiosViewController;
+ self.window.rootViewController = [[[QIOSViewController alloc] init] autorelease];
-#ifdef QT_DEBUG
- self.window.backgroundColor = [UIColor cyanColor];
+#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 makeKeyAndVisible];
+ self.window.hidden = NO;
return YES;
}
- (void)dealloc
{
- [qiosViewController release];
[window release];
[super dealloc];
}
diff --git a/src/plugins/platforms/ios/qiosbackingstore.mm b/src/plugins/platforms/ios/qiosbackingstore.mm
index 2dadc5672b..5ea5fbd8d1 100644
--- a/src/plugins/platforms/ios/qiosbackingstore.mm
+++ b/src/plugins/platforms/ios/qiosbackingstore.mm
@@ -56,6 +56,9 @@ QIOSBackingStore::QIOSBackingStore(QWindow *window)
fmt.setDepthBufferSize(16);
fmt.setStencilBufferSize(8);
+ // Needed to prevent QOpenGLContext::makeCurrent() from failing
+ window->setSurfaceType(QSurface::OpenGLSurface);
+
m_context->setFormat(fmt);
m_context->setScreen(window->screen());
m_context->create();
@@ -69,9 +72,6 @@ QIOSBackingStore::~QIOSBackingStore()
void QIOSBackingStore::beginPaint(const QRegion &)
{
- // Needed to prevent QOpenGLContext::makeCurrent() from failing
- window()->setSurfaceType(QSurface::OpenGLSurface);
-
m_context->makeCurrent(window());
QIOSWindow *iosWindow = static_cast<QIOSWindow *>(window()->handle());
@@ -102,6 +102,8 @@ void QIOSBackingStore::flush(QWindow *window, const QRegion &region, const QPoin
// the child window overlaps a sibling window that's draws using a separate QOpenGLContext.
return;
}
+
+ m_context->makeCurrent(window);
m_context->swapBuffers(window);
}
@@ -115,7 +117,7 @@ void QIOSBackingStore::resize(const QSize &size, const QRegion &staticContents)
// backing store and always keep the paint device's size in sync with the
// window size in beginPaint().
- if (size != window()->size())
+ if (size != window()->size() && !window()->inherits("QWidgetWindow"))
qWarning() << "QIOSBackingStore needs to have the same size as its window";
}
diff --git a/src/plugins/platforms/ios/qioscontext.h b/src/plugins/platforms/ios/qioscontext.h
index 082ec4794c..c48a0251a9 100644
--- a/src/plugins/platforms/ios/qioscontext.h
+++ b/src/plugins/platforms/ios/qioscontext.h
@@ -48,6 +48,8 @@
QT_BEGIN_NAMESPACE
+class QIOSWindow;
+
class QIOSContext : public QObject, public QPlatformOpenGLContext
{
Q_OBJECT
@@ -66,10 +68,14 @@ public:
GLuint defaultFramebufferObject(QPlatformSurface *) const;
QFunctionPointer getProcAddress(const QByteArray &procName);
+ bool isSharing() const Q_DECL_OVERRIDE;
+ bool isValid() const Q_DECL_OVERRIDE;
+
private Q_SLOTS:
void windowDestroyed(QObject *object);
private:
+ QIOSContext *m_sharedContext;
EAGLContext *m_eaglContext;
QSurfaceFormat m_format;
@@ -83,7 +89,7 @@ private:
static void deleteBuffers(const FramebufferObject &framebufferObject);
- mutable QHash<QWindow *, FramebufferObject> m_framebufferObjects;
+ mutable QHash<QIOSWindow *, FramebufferObject> m_framebufferObjects;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm
index 0c4bee1ef0..7310d2904f 100644
--- a/src/plugins/platforms/ios/qioscontext.mm
+++ b/src/plugins/platforms/ios/qioscontext.mm
@@ -51,7 +51,10 @@
QIOSContext::QIOSContext(QOpenGLContext *context)
: QPlatformOpenGLContext()
- , m_eaglContext([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2])
+ , m_sharedContext(static_cast<QIOSContext *>(context->shareHandle()))
+ , m_eaglContext([[EAGLContext alloc]
+ initWithAPI:kEAGLRenderingAPIOpenGLES2
+ sharegroup:m_sharedContext ? [m_sharedContext->m_eaglContext sharegroup] : nil])
, m_format(context->format())
{
m_format.setRenderableType(QSurfaceFormat::OpenGLES);
@@ -110,7 +113,7 @@ void QIOSContext::swapBuffers(QPlatformSurface *surface)
{
Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface);
Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window);
- QWindow *window = static_cast<QWindow *>(surface->surface());
+ QIOSWindow *window = static_cast<QIOSWindow *>(surface);
Q_ASSERT(m_framebufferObjects.contains(window));
[EAGLContext setCurrentContext:m_eaglContext];
@@ -121,7 +124,7 @@ void QIOSContext::swapBuffers(QPlatformSurface *surface)
GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
{
Q_ASSERT(surface && surface->surface()->surfaceClass() == QSurface::Window);
- QWindow *window = static_cast<QWindow *>(surface->surface());
+ QIOSWindow *window = static_cast<QIOSWindow *>(surface);
FramebufferObject &framebufferObject = m_framebufferObjects[window];
@@ -152,8 +155,7 @@ GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
}
// Ensure that the FBO's buffers match the size of the layer
- QIOSWindow *platformWindow = static_cast<QIOSWindow *>(surface);
- UIView *view = reinterpret_cast<UIView *>(platformWindow->winId());
+ UIView *view = reinterpret_cast<UIView *>(window->winId());
CAEAGLLayer *layer = static_cast<CAEAGLLayer *>(view.layer);
if (framebufferObject.renderbufferWidth != (layer.frame.size.width * layer.contentsScale) ||
framebufferObject.renderbufferHeight != (layer.frame.size.height * layer.contentsScale)) {
@@ -188,7 +190,7 @@ GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
void QIOSContext::windowDestroyed(QObject *object)
{
- QWindow *window = static_cast<QWindow *>(object);
+ QIOSWindow *window = static_cast<QIOSWindow *>(object);
if (m_framebufferObjects.contains(window)) {
EAGLContext *originalContext = [EAGLContext currentContext];
[EAGLContext setCurrentContext:m_eaglContext];
@@ -203,5 +205,15 @@ QFunctionPointer QIOSContext::getProcAddress(const QByteArray& functionName)
return QFunctionPointer(dlsym(RTLD_DEFAULT, functionName.constData()));
}
+bool QIOSContext::isValid() const
+{
+ return m_eaglContext;
+}
+
+bool QIOSContext::isSharing() const
+{
+ return m_sharedContext;
+}
+
#include "moc_qioscontext.cpp"
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/plugins/platforms/ios/qioseventdispatcher.h
index f2272ecd68..5caa7f5d2d 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.h
+++ b/src/plugins/platforms/ios/qioseventdispatcher.h
@@ -54,11 +54,9 @@ public:
explicit QIOSEventDispatcher(QObject *parent = 0);
bool processEvents(QEventLoop::ProcessEventsFlags flags) Q_DECL_OVERRIDE;
- void interrupt() Q_DECL_OVERRIDE;
void handleRunLoopExit(CFRunLoopActivity activity);
- void checkIfEventLoopShouldExit();
void interruptEventLoopExec();
private:
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm
index 3dd9c7ad9f..51eb10d385 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.mm
+++ b/src/plugins/platforms/ios/qioseventdispatcher.mm
@@ -446,6 +446,8 @@ bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoo
if (!m_processEventCallsAfterExec && (flags & QEventLoop::EventLoopExec)) {
++m_processEventCallsAfterExec;
+ m_runLoopExitObserver.addToMode(kCFRunLoopCommonModes);
+
// We set a new jump point here that we can return to when the event loop
// is asked to exit, so that we can return from QEventLoop::exec().
switch (setjmp(processEventExitJumpPoint)) {
@@ -475,44 +477,18 @@ bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoo
if (m_processEventCallsAfterExec)
--m_processEventCallsAfterExec;
- // If we're running with nested event loops and the application is quit,
- // then the forwarded interrupt call will happen while our processEvent
- // counter is still 2, and we won't detect that we're about to fall down
- // to the root iOS run-loop. We do an extra check here to catch that case.
- checkIfEventLoopShouldExit();
-
return processedEvents;
}
-void QIOSEventDispatcher::interrupt()
-{
- QEventDispatcherCoreFoundation::interrupt();
-
- if (!rootLevelRunLoopIntegration())
- return;
-
- // If an interrupt happens as part of a non-nested event loop, that is,
- // by processing an event or timer in the root iOS run-loop, we'll be
- // able to detect it here.
- checkIfEventLoopShouldExit();
-}
-
-void QIOSEventDispatcher::checkIfEventLoopShouldExit()
-{
- if (m_processEventCallsAfterExec == 1) {
- qEventDispatcherDebug() << "Hit root runloop level, watching for runloop exit";
- m_runLoopExitObserver.addToMode(kCFRunLoopCommonModes);
- }
-}
-
void QIOSEventDispatcher::handleRunLoopExit(CFRunLoopActivity activity)
{
Q_UNUSED(activity);
Q_ASSERT(activity == kCFRunLoopExit);
- m_runLoopExitObserver.removeFromMode(kCFRunLoopCommonModes);
-
- interruptEventLoopExec();
+ if (m_processEventCallsAfterExec == 1 && !QThreadData::current()->eventLoops.top()->isRunning()) {
+ qEventDispatcherDebug() << "Root runloop level exited";
+ interruptEventLoopExec();
+ }
}
void QIOSEventDispatcher::interruptEventLoopExec()
@@ -521,6 +497,8 @@ void QIOSEventDispatcher::interruptEventLoopExec()
--m_processEventCallsAfterExec;
+ m_runLoopExitObserver.removeFromMode(kCFRunLoopCommonModes);
+
// We re-set applicationProcessEventsReturnPoint here so that future
// calls to QEventLoop::exec() will end up back here after entering
// processEvents, instead of back in didFinishLaunchingWithOptions.
diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h
index fd328c9171..1c76d29389 100644
--- a/src/plugins/platforms/ios/qiosglobal.h
+++ b/src/plugins/platforms/ios/qiosglobal.h
@@ -52,12 +52,12 @@ QT_BEGIN_NAMESPACE
class QPlatformScreen;
bool isQtApplication();
-QIOSViewController *qiosViewController();
-CGRect toCGRect(const QRect &rect);
-QRect fromCGRect(const CGRect &rect);
-CGPoint toCGPoint(const QPoint &point);
-QPoint fromCGPoint(const CGPoint &point);
+CGRect toCGRect(const QRectF &rect);
+QRectF fromCGRect(const CGRect &rect);
+CGPoint toCGPoint(const QPointF &point);
+QPointF fromCGPoint(const CGPoint &point);
+
Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation);
UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation);
QRect fromPortraitToPrimary(const QRect &rect, QPlatformScreen *screen);
diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm
index 9b8462a6cc..d749b8f514 100644
--- a/src/plugins/platforms/ios/qiosglobal.mm
+++ b/src/plugins/platforms/ios/qiosglobal.mm
@@ -58,35 +58,24 @@ bool isQtApplication()
return isQt;
}
-QIOSViewController *qiosViewController()
-{
- // If Qt controls the application, we have created a root view controller were we place top-level
- // QWindows. Note that in a mixed native application, our view controller might later be removed or
- // added as a child of another controller. To protect against that, we keep an explicit pointer to the
- // view controller in cases where this is the controller we need to access.
- static QIOSViewController *c = isQtApplication() ?
- static_cast<QIOSApplicationDelegate *>([UIApplication sharedApplication].delegate).qiosViewController : nil;
- return c;
-}
-
-CGRect toCGRect(const QRect &rect)
+CGRect toCGRect(const QRectF &rect)
{
return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
}
-QRect fromCGRect(const CGRect &rect)
+QRectF fromCGRect(const CGRect &rect)
{
- return QRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
+ return QRectF(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
}
-CGPoint toCGPoint(const QPoint &point)
+CGPoint toCGPoint(const QPointF &point)
{
return CGPointMake(point.x(), point.y());
}
-QPoint fromCGPoint(const CGPoint &point)
+QPointF fromCGPoint(const CGPoint &point)
{
- return QPoint(point.x, point.y);
+ return QPointF(point.x, point.y);
}
Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation)
diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h
index 78c1b260e6..533ba686e1 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.h
+++ b/src/plugins/platforms/ios/qiosinputcontext.h
@@ -44,6 +44,7 @@
#include <UIKit/UIKit.h>
+#include <QtGui/qtransform.h>
#include <qpa/qplatforminputcontext.h>
QT_BEGIN_NAMESPACE
@@ -60,13 +61,17 @@ public:
void showInputPanel();
void hideInputPanel();
bool isInputPanelVisible() const;
+ void setFocusObject(QObject *object);
- void focusViewChanged(UIView *view);
+ void focusWindowChanged(QWindow *focusWindow);
+ void scrollRootView();
private:
QIOSKeyboardListener *m_keyboardListener;
- UIView *m_focusView;
+ UIView<UIKeyInput> *m_focusView;
+ QTransform m_inputItemTransform;
bool m_hasPendingHideRequest;
+ bool m_inSetFocusObject;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index d430589037..0e43429015 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -48,7 +48,12 @@
@public
QIOSInputContext *m_context;
BOOL m_keyboardVisible;
+ BOOL m_keyboardVisibleAndDocked;
QRectF m_keyboardRect;
+ QRectF m_keyboardEndRect;
+ NSTimeInterval m_duration;
+ UIViewAnimationCurve m_curve;
+ UIViewController *m_viewController;
}
@end
@@ -60,8 +65,30 @@
if (self) {
m_context = context;
m_keyboardVisible = NO;
- // After the keyboard became undockable (iOS5), UIKeyboardWillShow/UIKeyboardWillHide
- // no longer works for all cases. So listen to keyboard frame changes instead:
+ m_keyboardVisibleAndDocked = NO;
+ m_duration = 0;
+ m_curve = UIViewAnimationCurveEaseOut;
+ m_viewController = 0;
+
+ if (isQtApplication()) {
+ // Get the root view controller that is on the same screen as the keyboard:
+ for (UIWindow *uiWindow in [[UIApplication sharedApplication] windows]) {
+ if (uiWindow.screen == [UIScreen mainScreen]) {
+ m_viewController = [uiWindow.rootViewController retain];
+ break;
+ }
+ }
+ Q_ASSERT(m_viewController);
+ }
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(keyboardWillShow:)
+ name:@"UIKeyboardWillShowNotification" object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(keyboardWillHide:)
+ name:@"UIKeyboardWillHideNotification" object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(keyboardDidChangeFrame:)
@@ -72,25 +99,68 @@
- (void) dealloc
{
+ [m_viewController release];
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:@"UIKeyboardWillShowNotification" object:nil];
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:@"UIKeyboardWillHideNotification" object:nil];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:@"UIKeyboardDidChangeFrameNotification" object:nil];
[super dealloc];
}
-- (void) keyboardDidChangeFrame:(NSNotification *)notification
+- (QRectF) getKeyboardRect:(NSNotification *)notification
{
- CGRect frame;
- [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&frame];
+ // For Qt applications we rotate the keyboard rect to align with the screen
+ // orientation (which is the interface orientation of the root view controller).
+ // For hybrid apps we follow native behavior, and return the rect unmodified:
+ CGRect keyboardFrame = [[notification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue];
+ if (isQtApplication()) {
+ UIView *view = m_viewController.view;
+ return fromCGRect(CGRectOffset([view convertRect:keyboardFrame fromView:view.window], 0, -view.bounds.origin.y));
+ } else {
+ return fromCGRect(keyboardFrame);
+ }
+}
- m_keyboardRect = fromPortraitToPrimary(fromCGRect(frame), QGuiApplication::primaryScreen()->handle());
+- (void) keyboardDidChangeFrame:(NSNotification *)notification
+{
+ m_keyboardRect = [self getKeyboardRect:notification];
m_context->emitKeyboardRectChanged();
- BOOL visible = CGRectIntersectsRect(frame, [UIScreen mainScreen].bounds);
+ BOOL visible = m_keyboardRect.intersects(fromCGRect([UIScreen mainScreen].bounds));
if (m_keyboardVisible != visible) {
m_keyboardVisible = visible;
m_context->emitInputPanelVisibleChanged();
}
+
+ // If the keyboard was visible and docked from before, this is just a geometry
+ // change (normally caused by an orientation change). In that case, update scroll:
+ if (m_keyboardVisibleAndDocked)
+ m_context->scrollRootView();
+}
+
+- (void) keyboardWillShow:(NSNotification *)notification
+{
+ // Note that UIKeyboardWillShowNotification is only sendt when the keyboard is docked.
+ m_keyboardVisibleAndDocked = YES;
+ m_keyboardEndRect = [self getKeyboardRect:notification];
+ if (!m_duration) {
+ m_duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
+ m_curve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue] << 16;
+ }
+ m_context->scrollRootView();
+}
+
+- (void) keyboardWillHide:(NSNotification *)notification
+{
+ // Note that UIKeyboardWillHideNotification is also sendt when the keyboard is undocked.
+ m_keyboardVisibleAndDocked = NO;
+ m_keyboardEndRect = [self getKeyboardRect:notification];
+ m_context->scrollRootView();
}
@end
@@ -100,7 +170,11 @@ QIOSInputContext::QIOSInputContext()
, m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this])
, m_focusView(0)
, m_hasPendingHideRequest(false)
+ , m_inSetFocusObject(false)
{
+ if (isQtApplication())
+ connect(qGuiApp->inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QIOSInputContext::scrollRootView);
+ connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QIOSInputContext::focusWindowChanged);
}
QIOSInputContext::~QIOSInputContext()
@@ -142,10 +216,76 @@ bool QIOSInputContext::isInputPanelVisible() const
return m_keyboardListener->m_keyboardVisible;
}
-void QIOSInputContext::focusViewChanged(UIView *view)
+void QIOSInputContext::setFocusObject(QObject *)
+{
+ m_inputItemTransform = qApp->inputMethod()->inputItemTransform();
+
+ if (!m_focusView || !m_focusView.isFirstResponder)
+ return;
+
+ // Since m_focusView is the first responder, it means that the keyboard is open and we
+ // should update keyboard layout. But there seem to be no way to tell it to reread the
+ // UITextInputTraits from m_focusView. To work around that, we quickly resign first
+ // responder status just to reassign it again. To not remove the focusObject in the same
+ // go, we need to call the super implementation of resignFirstResponder. Since the call
+ // will cause a 'keyboardWillHide' notification to be sendt, we also block scrollRootView
+ // to avoid artifacts:
+ m_inSetFocusObject = true;
+ SEL sel = @selector(resignFirstResponder);
+ [[m_focusView superclass] instanceMethodForSelector:sel](m_focusView, sel);
+ m_inSetFocusObject = false;
+ [m_focusView becomeFirstResponder];
+}
+
+void QIOSInputContext::focusWindowChanged(QWindow *focusWindow)
{
+ UIView<UIKeyInput> *view = reinterpret_cast<UIView<UIKeyInput> *>(focusWindow->handle()->winId());
if ([m_focusView isFirstResponder])
[view becomeFirstResponder];
[m_focusView release];
m_focusView = [view retain];
}
+
+void QIOSInputContext::scrollRootView()
+{
+ // Scroll the root view (screen) if:
+ // - our backend controls the root view controller on the main screen (no hybrid app)
+ // - the focus object is on the same screen as the keyboard.
+ // - the first responder is a QUIView, and not some other foreign UIView.
+ // - the keyboard is docked. Otherwise the user can move the keyboard instead.
+ // - the inputItem has not been moved/scrolled
+ if (!isQtApplication() || !m_focusView || m_inSetFocusObject)
+ return;
+
+ if (m_inputItemTransform != qApp->inputMethod()->inputItemTransform()) {
+ // The inputItem has moved since the last scroll update. To avoid competing
+ // with the application where the cursor/inputItem should be, we bail:
+ return;
+ }
+
+ UIView *view = m_keyboardListener->m_viewController.view;
+ qreal scrollTo = 0;
+
+ if (m_focusView.isFirstResponder
+ && m_keyboardListener->m_keyboardVisibleAndDocked
+ && m_focusView.window == view.window) {
+ QRectF cursorRect = qGuiApp->inputMethod()->cursorRectangle();
+ cursorRect.translate(qGuiApp->focusWindow()->geometry().topLeft());
+ qreal keyboardY = m_keyboardListener->m_keyboardEndRect.y();
+ int statusBarY = qGuiApp->primaryScreen()->availableGeometry().y();
+ const int margin = 20;
+
+ if (cursorRect.bottomLeft().y() > keyboardY - margin)
+ scrollTo = qMin(view.bounds.size.height - keyboardY, cursorRect.y() - statusBarY - margin);
+ }
+
+ if (scrollTo != view.bounds.origin.y) {
+ // Scroll the view the same way a UIScrollView works: by changing bounds.origin:
+ CGRect newBounds = view.bounds;
+ newBounds.origin.y = scrollTo;
+ [UIView animateWithDuration:m_keyboardListener->m_duration delay:0
+ options:m_keyboardListener->m_curve
+ animations:^{ view.bounds = newBounds; }
+ completion:0];
+ }
+}
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index dcad6121be..5c8f67bda2 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -101,7 +101,12 @@ QIOSIntegration::~QIOSIntegration()
bool QIOSIntegration::hasCapability(Capability cap) const
{
switch (cap) {
+ case BufferQueueingOpenGL:
+ return true;
case OpenGL:
+ case ThreadedOpenGL:
+ return true;
+ case ThreadedPixmaps:
return true;
case MultipleWindows:
return true;
@@ -155,7 +160,7 @@ QPlatformServices *QIOSIntegration::services() const
QVariant QIOSIntegration::styleHint(StyleHint hint) const
{
switch (hint) {
- case ShowIsFullScreen:
+ case ShowIsMaximized:
return true;
case SetFocusOnTouchRelease:
return true;
diff --git a/src/plugins/platforms/ios/qiosscreen.h b/src/plugins/platforms/ios/qiosscreen.h
index 40c7a3ccf7..173bd11719 100644
--- a/src/plugins/platforms/ios/qiosscreen.h
+++ b/src/plugins/platforms/ios/qiosscreen.h
@@ -50,8 +50,10 @@
QT_BEGIN_NAMESPACE
-class QIOSScreen : public QPlatformScreen
+class QIOSScreen : public QObject, public QPlatformScreen
{
+ Q_OBJECT
+
public:
QIOSScreen(unsigned int screenIndex);
~QIOSScreen();
@@ -72,13 +74,18 @@ public:
UIScreen *uiScreen() const;
- void setPrimaryOrientation(Qt::ScreenOrientation orientation);
+ void updateProperties();
+ void layoutWindows();
+
+public slots:
+ void updateStatusBarVisibility();
private:
UIScreen *m_uiScreen;
QRect m_geometry;
QRect m_availableGeometry;
int m_depth;
+ uint m_unscaledDpi;
QSizeF m_physicalSize;
QIOSOrientationListener *m_orientationListener;
};
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index c28d8881bf..57522cb1a3 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -123,8 +123,6 @@ QIOSScreen::QIOSScreen(unsigned int screenIndex)
, m_uiScreen([[UIScreen screens] objectAtIndex:qMin(NSUInteger(screenIndex), [[UIScreen screens] count] - 1)])
, m_orientationListener(0)
{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
QString deviceIdentifier = deviceModelIdentifier();
if (deviceIdentifier == QStringLiteral("iPhone2,1") /* iPhone 3GS */
@@ -134,32 +132,118 @@ QIOSScreen::QIOSScreen(unsigned int screenIndex)
m_depth = 24;
}
- int unscaledDpi = 163; // Regular iPhone DPI
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad
&& !deviceIdentifier.contains(QRegularExpression("^iPad2,[567]$")) /* excluding iPad Mini */) {
- unscaledDpi = 132;
- };
+ m_unscaledDpi = 132;
+ } else {
+ m_unscaledDpi = 163; // Regular iPhone DPI
+ }
- CGRect bounds = [m_uiScreen bounds];
- m_geometry = QRect(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
+ connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QIOSScreen::updateStatusBarVisibility);
- CGRect frame = m_uiScreen.applicationFrame;
- m_availableGeometry = QRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
+ updateProperties();
+}
- const qreal millimetersPerInch = 25.4;
- m_physicalSize = QSizeF(m_geometry.size()) / unscaledDpi * millimetersPerInch;
+QIOSScreen::~QIOSScreen()
+{
+ [m_orientationListener release];
+}
- if (isQtApplication()) {
- // When in a non-mixed environment, let QScreen follow the current interface orientation:
- setPrimaryOrientation(toQtScreenOrientation(UIDeviceOrientation(qiosViewController().interfaceOrientation)));
+void QIOSScreen::updateProperties()
+{
+ UIWindow *uiWindow = 0;
+ for (uiWindow in [[UIApplication sharedApplication] windows]) {
+ if (uiWindow.screen == m_uiScreen)
+ break;
}
- [pool release];
+ bool inPortrait = UIInterfaceOrientationIsPortrait(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);
+
+ if (geometry != m_geometry) {
+ m_geometry = geometry;
+
+ const qreal millimetersPerInch = 25.4;
+ m_physicalSize = QSizeF(m_geometry.size()) / m_unscaledDpi * millimetersPerInch;
+
+ QWindowSystemInterface::handleScreenGeometryChange(screen(), m_geometry);
+ }
+
+ QRect availableGeometry = geometry;
+
+ CGSize applicationFrameSize = m_uiScreen.applicationFrame.size;
+ int statusBarHeight = geometry.height() - (inPortrait ? applicationFrameSize.height : applicationFrameSize.width);
+
+ availableGeometry.adjust(0, statusBarHeight, 0, 0);
+
+ if (availableGeometry != m_availableGeometry) {
+ m_availableGeometry = availableGeometry;
+ QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), m_availableGeometry);
+ }
+
+ if (screen())
+ layoutWindows();
}
-QIOSScreen::~QIOSScreen()
+void QIOSScreen::updateStatusBarVisibility()
{
- [m_orientationListener release];
+ QWindow *focusWindow = QGuiApplication::focusWindow();
+
+ // If we don't have a focus window we leave the status
+ // bar as is, so that the user can activate a new window
+ // with the same window state without the status bar jumping
+ // back and forth.
+ if (!focusWindow)
+ return;
+
+ UIView *view = reinterpret_cast<UIView *>(focusWindow->handle()->winId());
+#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0)
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0) {
+ [view.viewController setNeedsStatusBarAppearanceUpdate];
+ } else
+#endif
+ {
+ bool wasHidden = [UIApplication sharedApplication].statusBarHidden;
+ QIOSViewController *viewController = static_cast<QIOSViewController *>(view.viewController);
+ [[UIApplication sharedApplication]
+ setStatusBarHidden:[viewController prefersStatusBarHidden]
+ withAnimation:UIStatusBarAnimationNone];
+
+ if ([UIApplication sharedApplication].statusBarHidden != wasHidden)
+ updateProperties();
+ }
+}
+
+void QIOSScreen::layoutWindows()
+{
+ QList<QWindow*> windows = QGuiApplication::topLevelWindows();
+
+ const QRect oldGeometry = screen()->geometry();
+ const QRect oldAvailableGeometry = screen()->availableGeometry();
+ const QRect newGeometry = geometry();
+ const QRect newAvailableGeometry = availableGeometry();
+
+ for (int i = 0; i < windows.size(); ++i) {
+ QWindow *window = windows.at(i);
+
+ if (platformScreenForWindow(window) != this)
+ continue;
+
+ QIOSWindow *platformWindow = static_cast<QIOSWindow *>(window->handle());
+ if (!platformWindow)
+ continue;
+
+ // FIXME: Handle more complex cases of no-state and/or child windows when rotating
+
+ if (window->windowState() & Qt::WindowFullScreen
+ || (window->windowState() & Qt::WindowNoState && window->geometry() == oldGeometry))
+ platformWindow->applyGeometry(newGeometry);
+ else if (window->windowState() & Qt::WindowMaximized
+ || (window->windowState() & Qt::WindowNoState && window->geometry() == oldAvailableGeometry))
+ platformWindow->applyGeometry(newAvailableGeometry);
+ }
}
QRect QIOSScreen::geometry() const
@@ -199,7 +283,9 @@ qreal QIOSScreen::devicePixelRatio() const
Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
{
- return Qt::PortraitOrientation;
+ // A UIScreen stays in the native orientation, regardless of rotation
+ return m_uiScreen.bounds.size.width >= m_uiScreen.bounds.size.height ?
+ Qt::LandscapeOrientation : Qt::PortraitOrientation;
}
Qt::ScreenOrientation QIOSScreen::orientation() const
@@ -217,31 +303,11 @@ void QIOSScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask)
}
}
-void QIOSScreen::setPrimaryOrientation(Qt::ScreenOrientation orientation)
-{
- // Note that UIScreen never changes orientation, but QScreen should. To work around
- // this, we let QIOSViewController call us whenever interface orientation changes, and
- // use that as primary orientation. After all, the viewcontrollers geometry is what we
- // place QWindows on top of. A problem with this approach is that QIOSViewController is
- // not in use in a mixed environment, which results in no change to primary orientation.
- // We see that as acceptable since Qt should most likely not interfere with orientation
- // for that case anyway.
- bool portrait = screen()->isPortrait(orientation);
- if (portrait && m_geometry.width() < m_geometry.height())
- return;
-
- // Switching portrait/landscape means swapping width/height (and adjusting x/y):
- m_geometry = QRect(0, 0, m_geometry.height(), m_geometry.width());
- m_physicalSize = QSizeF(m_physicalSize.height(), m_physicalSize.width());
- m_availableGeometry = fromPortraitToPrimary(fromCGRect(m_uiScreen.applicationFrame), this);
-
- QWindowSystemInterface::handleScreenGeometryChange(screen(), m_geometry);
- QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), m_availableGeometry);
-}
-
UIScreen *QIOSScreen::uiScreen() const
{
return m_uiScreen;
}
+#include "moc_qiosscreen.cpp"
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h
index d5a61cb3f4..a0017808d3 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.h
+++ b/src/plugins/platforms/ios/qiosviewcontroller.h
@@ -42,5 +42,6 @@
#import <UIKit/UIKit.h>
@interface QIOSViewController : UIViewController
+- (BOOL)prefersStatusBarHidden;
@end
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
index d315b49776..2e7e44d32c 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.mm
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -42,20 +42,14 @@
#import "qiosviewcontroller.h"
#include <QtGui/QGuiApplication>
+#include <QtGui/QWindow>
#include <QtGui/QScreen>
#include "qiosscreen.h"
#include "qiosglobal.h"
+#include "qioswindow.h"
@implementation QIOSViewController
-- (void)viewDidLoad
-{
-#ifdef QT_DEBUG
- if (!self.nibName)
- self.view.backgroundColor = [UIColor magentaColor];
-#endif
-}
-
-(BOOL)shouldAutorotate
{
// Until a proper orientation and rotation API is in place, we always auto rotate.
@@ -63,26 +57,56 @@
return YES;
}
+#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_6_0)
-(NSUInteger)supportedInterfaceOrientations
{
// We need to tell iOS that we support all orientations in order to set
// status bar orientation when application content orientation changes.
return UIInterfaceOrientationMaskAll;
}
+#endif
+
+#if QT_IOS_DEPLOYMENT_TARGET_BELOW(__IPHONE_6_0)
+-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
+{
+ Q_UNUSED(interfaceOrientation);
+ return YES;
+}
+#endif
-- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
+- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
Q_UNUSED(duration);
+ Q_UNUSED(interfaceOrientation);
if (!QCoreApplication::instance())
return; // FIXME: Store orientation for later (?)
- Qt::ScreenOrientation orientation = toQtScreenOrientation(UIDeviceOrientation(toInterfaceOrientation));
- if (orientation == -1)
- return;
-
QIOSScreen *qiosScreen = static_cast<QIOSScreen *>(QGuiApplication::primaryScreen()->handle());
- qiosScreen->setPrimaryOrientation(orientation);
+ qiosScreen->updateProperties();
+}
+
+#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0)
+- (UIStatusBarStyle)preferredStatusBarStyle
+{
+ // Since we don't place anything behind the status bare by default, we
+ // end up with a black area, so we have to enable the white text mode
+ // of the iOS7 statusbar.
+ return UIStatusBarStyleLightContent;
+
+ // FIXME: Try to detect the content underneath the statusbar and choose
+ // an appropriate style, and/or expose Qt APIs to control the style.
+}
+#endif
+
+- (BOOL)prefersStatusBarHidden
+{
+ QWindow *focusWindow = QGuiApplication::focusWindow();
+ if (!focusWindow)
+ return [UIApplication sharedApplication].statusBarHidden;
+
+ QIOSWindow *topLevel = static_cast<QIOSWindow *>(focusWindow->handle())->topLevelWindow();
+ return topLevel->window()->windowState() == Qt::WindowFullScreen;
}
@end
diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h
index 20f0aa59b6..a5e122bda1 100644
--- a/src/plugins/platforms/ios/qioswindow.h
+++ b/src/plugins/platforms/ios/qioswindow.h
@@ -52,12 +52,17 @@ class QIOSWindow;
@interface UIView (QIOS)
@property(readonly) QWindow *qwindow;
+@property(readonly) UIViewController *viewController;
@end
QT_BEGIN_NAMESPACE
-class QIOSWindow : public QPlatformWindow
+@class QUIView;
+
+class QIOSWindow : public QObject, public QPlatformWindow
{
+ Q_OBJECT
+
public:
explicit QIOSWindow(QWindow *window);
~QIOSWindow();
@@ -74,20 +79,21 @@ public:
void requestActivateWindow();
qreal devicePixelRatio() const;
- int effectiveWidth() const;
- int effectiveHeight() const;
bool setMouseGrabEnabled(bool grab) { return grab; }
bool setKeyboardGrabEnabled(bool grab) { return grab; }
WId winId() const { return WId(m_view); };
+ QIOSWindow *topLevelWindow() const;
+
private:
- UIView *m_view;
+ void applyGeometry(const QRect &rect);
- QRect m_requestedGeometry;
+ QUIView *m_view;
+
+ QRect m_normalGeometry;
int m_windowLevel;
- qreal m_devicePixelRatio;
void raiseOrLower(bool raise);
void updateWindowLevel();
@@ -95,6 +101,8 @@ private:
inline Qt::WindowType windowType() { return static_cast<Qt::WindowType>(int(window()->flags() & Qt::WindowType_Mask)); }
inline bool windowIsPopup() { return windowType() & Qt::Popup & ~Qt::Window; }
+
+ friend class QIOSScreen;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index dbeec5f5f2..0dd810bdf6 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -48,6 +48,7 @@
#include "qiosviewcontroller.h"
#include "qiosintegration.h"
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qwindow_p.h>
#include <qpa/qplatformintegration.h>
#import <QuartzCore/CAEAGLLayer.h>
@@ -57,7 +58,7 @@
#include <QtDebug>
-@interface EAGLView : UIView <UIKeyInput>
+@interface QUIView : UIView <UIKeyInput>
{
@public
UITextAutocapitalizationType autocapitalizationType;
@@ -82,7 +83,7 @@
@end
-@implementation EAGLView
+@implementation QUIView
+ (Class)layerClass
{
@@ -107,15 +108,7 @@
[NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking,
kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
- // Set up text input
- autocapitalizationType = UITextAutocapitalizationTypeNone;
- autocorrectionType = UITextAutocorrectionTypeNo;
- enablesReturnKeyAutomatically = NO;
- keyboardAppearance = UIKeyboardAppearanceDefault;
- keyboardType = UIKeyboardTypeDefault;
- returnKeyType = UIReturnKeyDone;
- secureTextEntry = NO;
- m_nextTouchId = 0;
+ [self updateTextInputTraits];
if (isQtApplication())
self.hidden = YES;
@@ -126,6 +119,41 @@
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,
@@ -138,21 +166,67 @@
qWarning() << m_qioswindow->window()
<< "is backed by a UIView that has a transform set. This is not supported.";
- QRect geometry = fromCGRect(self.frame);
- m_qioswindow->QPlatformWindow::setGeometry(geometry);
- QWindowSystemInterface::handleGeometryChange(m_qioswindow->window(), geometry);
+ // 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;
- // If we have a new size here we need to resize the FBO's corresponding buffers,
- // but we defer that to when the application calls makeCurrent.
+ QWindowSystemInterface::handleGeometryChange(m_qioswindow->window(), actualGeometry, previousGeometry);
+ QWindowSystemInterface::flushWindowSystemEvents();
+
+ if (actualGeometry.size() != previousGeometry.size()) {
+ // Trigger expose event on resize
+ [self setNeedsDisplay];
- [super layoutSubviews];
+ // 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
+{
+ QRect geometry = fromCGRect(layer.frame).toRect();
+ Q_ASSERT(m_qioswindow->geometry() == geometry);
+ Q_ASSERT(self.hidden == !m_qioswindow->window()->isVisible());
+
+ QRegion region = self.hidden ? QRegion() : QRect(QPoint(), geometry.size());
+ QWindowSystemInterface::handleExposeEvent(m_qioswindow->window(), region);
+ QWindowSystemInterface::flushWindowSystemEvents();
}
- (void)updateTouchList:(NSSet *)touches withState:(Qt::TouchPointState)state
{
- // We deliver touch events with global coordinates. But global in this respect means
- // the coordinate system where this QWindow lives. And that is our superview.
- CGSize parentSize = self.superview.frame.size;
+ // 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]) {
@@ -160,9 +234,9 @@
} else {
touchPoint.state = state;
touchPoint.pressure = (state == Qt::TouchPointReleased) ? 0.0 : 1.0;
- QPoint touchPos = fromCGPoint([uiTouch locationInView:self.superview]);
+ QPoint touchPos = fromCGPoint([uiTouch locationInView:rootView]).toPoint();
touchPoint.area = QRectF(touchPos, QSize(0, 0));
- touchPoint.normalPosition = QPointF(touchPos.x() / parentSize.width, touchPos.y() / parentSize.height);
+ touchPoint.normalPosition = QPointF(touchPos.x() / rootViewSize.width, touchPos.y() / rootViewSize.height);
}
}
}
@@ -218,15 +292,26 @@
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
- Q_UNUSED(touches) // ### can a subset of the active touches be cancelled?
+ if (!touches && m_activeTouches.isEmpty())
+ return;
+
+ if (!touches) {
+ m_activeTouches.clear();
+ } else {
+ for (UITouch *touch in touches)
+ m_activeTouches.remove(touch);
+
+ Q_ASSERT_X(m_activeTouches.isEmpty(), Q_FUNC_INFO,
+ "Subset of active touches cancelled by UIKit");
+ }
- // Clear current touch points
- 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(event.timestamp * 1000), iosIntegration->touchDevice());
+ QWindowSystemInterface::handleTouchCancelEvent(m_qioswindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice());
QWindowSystemInterface::flushWindowSystemEvents();
}
@@ -250,13 +335,17 @@
// user cannot type. And since the keyboard will open when a view becomes
// the first responder, it's now a good time to inform QPA that the QWindow
// this view backs became active:
+ [self updateTextInputTraits];
QWindowSystemInterface::handleWindowActivated(m_qioswindow->window());
return [super becomeFirstResponder];
}
- (BOOL)resignFirstResponder
{
- QWindowSystemInterface::handleWindowActivated(0);
+ // Resigning first responed status means that the virtual keyboard was closed, or
+ // some other view became first responder. In either case we clear the focus object to
+ // avoid blinking cursors in line edits etc:
+ static_cast<QWindowPrivate *>(QObjectPrivate::get(m_qioswindow->window()))->clearFocusObject();
return [super resignFirstResponder];
}
@@ -269,8 +358,11 @@
{
QString string = QString::fromUtf8([text UTF8String]);
int key = 0;
- if ([text isEqualToString:@"\n"])
+ if ([text isEqualToString:@"\n"]) {
key = (int)Qt::Key_Return;
+ if (self.returnKeyType == UIReturnKeyDone)
+ [self resignFirstResponder];
+ }
// Send key event to window system interface
QWindowSystemInterface::handleKeyEvent(
@@ -288,14 +380,65 @@
0, QEvent::KeyRelease, (int)Qt::Key_Backspace, Qt::NoModifier);
}
+- (void)updateTextInputTraits
+{
+ // Ask the current focus object what kind of input it
+ // expects, and configure the keyboard appropriately:
+ QObject *focusObject = QGuiApplication::focusObject();
+ if (!focusObject)
+ return;
+ QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints);
+ if (!QCoreApplication::sendEvent(focusObject, &queryEvent))
+ return;
+ if (!queryEvent.value(Qt::ImEnabled).toBool())
+ return;
+
+ Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt());
+
+ self.returnKeyType = (hints & Qt::ImhMultiLine) ? UIReturnKeyDefault : UIReturnKeyDone;
+ self.secureTextEntry = BOOL(hints & Qt::ImhHiddenText);
+ self.autocorrectionType = (hints & Qt::ImhNoPredictiveText) ?
+ UITextAutocorrectionTypeNo : UITextAutocorrectionTypeDefault;
+
+ if (hints & Qt::ImhUppercaseOnly)
+ self.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters;
+ else if (hints & Qt::ImhNoAutoUppercase)
+ self.autocapitalizationType = UITextAutocapitalizationTypeNone;
+ else
+ self.autocapitalizationType = UITextAutocapitalizationTypeSentences;
+
+ if (hints & Qt::ImhUrlCharactersOnly)
+ self.keyboardType = UIKeyboardTypeURL;
+ else if (hints & Qt::ImhEmailCharactersOnly)
+ self.keyboardType = UIKeyboardTypeEmailAddress;
+ else if (hints & Qt::ImhDigitsOnly)
+ self.keyboardType = UIKeyboardTypeNumberPad;
+ else if (hints & Qt::ImhFormattedNumbersOnly)
+ self.keyboardType = UIKeyboardTypeDecimalPad;
+ else if (hints & Qt::ImhDialableCharactersOnly)
+ self.keyboardType = UIKeyboardTypeNumberPad;
+ else
+ self.keyboardType = UIKeyboardTypeDefault;
+}
+
@end
@implementation UIView (QIOS)
- (QWindow *)qwindow
{
- if ([self isKindOfClass:[EAGLView class]])
- return static_cast<EAGLView *>(self)->m_qioswindow->window();
+ if ([self isKindOfClass:[QUIView class]])
+ return static_cast<QUIView *>(self)->m_qioswindow->window();
+ return nil;
+}
+
+- (UIViewController *)viewController
+{
+ id responder = self;
+ while ((responder = [responder nextResponder])) {
+ if ([responder isKindOfClass:UIViewController.class])
+ return responder;
+ }
return nil;
}
@@ -305,26 +448,23 @@ QT_BEGIN_NAMESPACE
QIOSWindow::QIOSWindow(QWindow *window)
: QPlatformWindow(window)
- , m_view([[EAGLView alloc] initWithQIOSWindow:this])
- , m_requestedGeometry(QPlatformWindow::geometry())
+ , m_view([[QUIView alloc] initWithQIOSWindow:this])
+ , m_normalGeometry(QPlatformWindow::geometry())
, m_windowLevel(0)
- , m_devicePixelRatio(1.0)
{
- setParent(parent());
+ setParent(QPlatformWindow::parent());
setWindowState(window->windowState());
-
- // Retina support: get screen scale factor and set it in the content view.
- // This will make framebufferObject() create a 2x frame buffer on retina
- // displays. Also set m_devicePixelRatio which is used for scaling the
- // paint device.
- if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] == YES) {
- m_devicePixelRatio = [[UIScreen mainScreen] scale];
- [m_view setContentScaleFactor: m_devicePixelRatio];
- }
}
QIOSWindow::~QIOSWindow()
{
+ // According to the UIResponder documentation, Cocoa Touch should react to system interruptions
+ // that "might cause the view to be removed from the window" by sending touchesCancelled, but in
+ // practice this doesn't seem to happen when removing the view from its superview. To ensure that
+ // Qt's internal state for touch and mouse handling is kept consistent, we therefor have to force
+ // cancellation of all touch events.
+ [m_view touchesCancelled:0 withEvent:0];
+
[m_view removeFromSuperview];
[m_view release];
}
@@ -337,8 +477,8 @@ bool QIOSWindow::blockedByModal()
void QIOSWindow::setVisible(bool visible)
{
- QPlatformWindow::setVisible(visible);
m_view.hidden = !visible;
+ [m_view setNeedsDisplay];
if (!isQtApplication())
return;
@@ -356,9 +496,13 @@ void QIOSWindow::setVisible(bool visible)
if (visible) {
requestActivateWindow();
+
+ if (window()->isTopLevel())
+ static_cast<QIOSScreen *>(screen())->updateStatusBarVisibility();
+
} else {
// Activate top-most visible QWindow:
- NSArray *subviews = qiosViewController().view.subviews;
+ NSArray *subviews = m_view.viewController.view.subviews;
for (int i = int(subviews.count) - 1; i >= 0; --i) {
UIView *view = [subviews objectAtIndex:i];
if (!view.hidden) {
@@ -373,38 +517,95 @@ void QIOSWindow::setVisible(bool visible)
void QIOSWindow::setGeometry(const QRect &rect)
{
- // If the window is in fullscreen, just bookkeep the requested
- // geometry in case the window goes into Qt::WindowNoState later:
- m_requestedGeometry = rect;
- if (window()->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen))
+ m_normalGeometry = rect;
+
+ if (window()->windowState() != Qt::WindowNoState) {
+ QPlatformWindow::setGeometry(rect);
+
+ // The layout will realize the requested geometry was not applied, and
+ // send geometry-change events that match the actual geometry.
+ [m_view setNeedsLayout];
+
+ if (window()->inherits("QWidgetWindow")) {
+ // QWidget wrongly assumes that setGeometry resets the window
+ // state back to Qt::NoWindowState, so we need to inform it that
+ // that his is not the case by re-issuing the current window state.
+ QWindowSystemInterface::handleWindowStateChanged(window(), window()->windowState());
+
+ // It also needs to be told immediately that the geometry it requested
+ // did not apply, otherwise it will continue on as if it did, instead
+ // of waiting for a resize event.
+ [m_view layoutIfNeeded];
+ }
+
return;
+ }
+
+ applyGeometry(rect);
+}
+
+void QIOSWindow::applyGeometry(const QRect &rect)
+{
+ // Geometry changes are asynchronous, but QWindow::geometry() is
+ // expected to report back the 'requested geometry' until we get
+ // a callback with the updated geometry from the window system.
+ // The baseclass takes care of persisting this for us.
+ QPlatformWindow::setGeometry(rect);
+
+ if (window()->isTopLevel()) {
+ // The QWindow is in QScreen coordinates, which maps to a possibly rotated root-view-controller.
+ // Since the root-view-controller might be translated in relation to the UIWindow, we need to
+ // check specifically for that and compensate. Also check if the root view has been scrolled
+ // as a result of the keyboard being open.
+ UIWindow *uiWindow = m_view.window;
+ UIView *rootView = uiWindow.rootViewController.view;
+ CGRect rootViewPositionInRelationToRootViewController =
+ [rootView convertRect:uiWindow.bounds fromView:uiWindow];
+
+ m_view.frame = CGRectOffset([m_view.superview convertRect:toCGRect(rect) fromView:rootView],
+ rootViewPositionInRelationToRootViewController.origin.x,
+ rootViewPositionInRelationToRootViewController.origin.y
+ + rootView.bounds.origin.y);
+ } else {
+ // Easy, in parent's coordinates
+ m_view.frame = toCGRect(rect);
+ }
+
+ // iOS will automatically trigger -[layoutSubviews:] for resize,
+ // but not for move, so we force it just in case.
+ [m_view setNeedsLayout];
- // Since we don't support transformations on the UIView, we can set the frame
- // directly and let UIKit deal with translating that into bounds and center.
- // Changing the size of the view will end up in a call to -[EAGLView layoutSubviews]
- // which will update QWindowSystemInterface with the new size.
- m_view.frame = toCGRect(rect);
+ if (window()->inherits("QWidgetWindow"))
+ [m_view layoutIfNeeded];
}
void QIOSWindow::setWindowState(Qt::WindowState state)
{
- // FIXME: Figure out where or how we should disable/enable the statusbar.
- // Perhaps setting QWindow to maximized should also mean that we'll show
- // the statusbar, and vice versa for fullscreen?
+ // Update the QWindow representation straight away, so that
+ // we can update the statusbar visibility based on the new
+ // state before applying geometry changes.
+ qt_window_private(window())->windowState = state;
+
+ if (window()->isTopLevel() && window()->isVisible() && window()->isActive())
+ static_cast<QIOSScreen *>(screen())->updateStatusBarVisibility();
switch (state) {
+ case Qt::WindowNoState:
+ applyGeometry(m_normalGeometry);
+ break;
case Qt::WindowMaximized:
- case Qt::WindowFullScreen: {
- // Since UIScreen does not take orientation into account when
- // reporting geometry, we need to look at the top view instead:
- CGSize fullscreenSize = m_view.window.rootViewController.view.bounds.size;
- m_view.frame = CGRectMake(0, 0, fullscreenSize.width, fullscreenSize.height);
- m_view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- break; }
- default:
- m_view.frame = toCGRect(m_requestedGeometry);
- m_view.autoresizingMask = UIViewAutoresizingNone;
+ applyGeometry(screen()->availableGeometry());
+ break;
+ case Qt::WindowFullScreen:
+ applyGeometry(screen()->geometry());
break;
+ case Qt::WindowMinimized:
+ applyGeometry(QRect());
+ break;
+ case Qt::WindowActive:
+ Q_UNREACHABLE();
+ default:
+ Q_UNREACHABLE();
}
}
@@ -414,8 +615,30 @@ void QIOSWindow::setParent(const QPlatformWindow *parentWindow)
UIView *parentView = reinterpret_cast<UIView *>(parentWindow->winId());
[parentView addSubview:m_view];
} else if (isQtApplication()) {
- [qiosViewController().view addSubview:m_view];
+ for (UIWindow *uiWindow in [[UIApplication sharedApplication] windows]) {
+ if (uiWindow.screen == static_cast<QIOSScreen *>(screen())->uiScreen()) {
+ [uiWindow.rootViewController.view addSubview:m_view];
+ break;
+ }
+ }
+ }
+}
+
+QIOSWindow *QIOSWindow::topLevelWindow() const
+{
+ QWindow *window = this->window();
+ while (window) {
+ QWindow *parent = window->parent();
+ if (!parent)
+ parent = window->transientParent();
+
+ if (!parent)
+ break;
+
+ window = parent;
}
+
+ return static_cast<QIOSWindow *>(window->handle());
}
void QIOSWindow::requestActivateWindow()
@@ -423,12 +646,15 @@ void QIOSWindow::requestActivateWindow()
// Note that several windows can be active at the same time if they exist in the same
// hierarchy (transient children). But only one window can be QGuiApplication::focusWindow().
// Dispite the name, 'requestActivateWindow' means raise and transfer focus to the window:
- if (!window()->isTopLevel() || blockedByModal())
+ if (blockedByModal())
return;
- raise();
- QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext();
- static_cast<QIOSInputContext *>(context)->focusViewChanged(m_view);
+ [m_view.window makeKeyWindow];
+
+ if (window()->isTopLevel())
+ raise();
+
+ QWindowSystemInterface::handleWindowActivated(window());
}
void QIOSWindow::raiseOrLower(bool raise)
@@ -444,7 +670,7 @@ void QIOSWindow::raiseOrLower(bool raise)
for (int i = int(subviews.count) - 1; i >= 0; --i) {
UIView *view = static_cast<UIView *>([subviews objectAtIndex:i]);
- if (view.hidden || view == m_view)
+ if (view.hidden || view == m_view || !view.qwindow)
continue;
int level = static_cast<QIOSWindow *>(view.qwindow->handle())->m_windowLevel;
if (m_windowLevel > level || (raise && m_windowLevel == level)) {
@@ -491,17 +717,9 @@ void QIOSWindow::handleContentOrientationChange(Qt::ScreenOrientation orientatio
qreal QIOSWindow::devicePixelRatio() const
{
- return m_devicePixelRatio;
-}
-
-int QIOSWindow::effectiveWidth() const
-{
- return geometry().width() * m_devicePixelRatio;
+ return m_view.contentScaleFactor;
}
-int QIOSWindow::effectiveHeight() const
-{
- return geometry().height() * m_devicePixelRatio;
-}
+#include "moc_qioswindow.cpp"
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/kms/qkmsbackingstore.cpp b/src/plugins/platforms/kms/qkmsbackingstore.cpp
index 29395f3b4f..fa4ef847cd 100644
--- a/src/plugins/platforms/kms/qkmsbackingstore.cpp
+++ b/src/plugins/platforms/kms/qkmsbackingstore.cpp
@@ -52,6 +52,7 @@ QKmsBackingStore::QKmsBackingStore(QWindow *window)
, m_context(new QOpenGLContext)
, m_texture(0)
, m_program(0)
+ , m_initialized(false)
{
m_context->setFormat(window->requestedFormat());
m_context->setScreen(window->screen());
@@ -85,6 +86,11 @@ void QKmsBackingStore::flush(QWindow *window, const QRegion &region, const QPoin
m_context->makeCurrent(window);
+ if (!m_initialized) {
+ initializeOpenGLFunctions();
+ m_initialized = true;
+ }
+
if (!m_program) {
static const char *textureVertexProgram =
"attribute highp vec2 vertexCoordEntry;\n"
diff --git a/src/plugins/platforms/kms/qkmsbackingstore.h b/src/plugins/platforms/kms/qkmsbackingstore.h
index 34ea49a346..c5f6c81d18 100644
--- a/src/plugins/platforms/kms/qkmsbackingstore.h
+++ b/src/plugins/platforms/kms/qkmsbackingstore.h
@@ -43,6 +43,7 @@
#define QBACKINGSTORE_KMS_H
#include <qpa/qplatformbackingstore.h>
+#include <QtGui/QOpenGLFunctions>
#include <QImage>
QT_BEGIN_NAMESPACE
@@ -50,7 +51,7 @@ QT_BEGIN_NAMESPACE
class QOpenGLContext;
class QOpenGLShaderProgram;
-class QKmsBackingStore : public QPlatformBackingStore
+class QKmsBackingStore : public QPlatformBackingStore, public QOpenGLFunctions
{
public:
QKmsBackingStore(QWindow *window);
@@ -69,6 +70,7 @@ private:
uint m_texture;
QOpenGLShaderProgram *m_program;
QRegion m_dirty;
+ bool m_initialized;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/kms/qkmsscreen.h b/src/plugins/platforms/kms/qkmsscreen.h
index a90d6fa051..f0c49ad11c 100644
--- a/src/plugins/platforms/kms/qkmsscreen.h
+++ b/src/plugins/platforms/kms/qkmsscreen.h
@@ -55,8 +55,7 @@ extern "C" {
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
+#include <QtGui/qopengl.h>
#include <qpa/qplatformscreen.h>
diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro
index e2c25add0b..100db54a5c 100644
--- a/src/plugins/platforms/qnx/qnx.pro
+++ b/src/plugins/platforms/qnx/qnx.pro
@@ -5,18 +5,7 @@ QT += platformsupport-private core-private gui-private
# Uncomment this to build with support for IMF once it becomes available in the BBNDK
#CONFIG += qqnx_imf
-# Uncomment this to build with support for PPS based platform integration
-#CONFIG += qqnx_pps
-
-CONFIG(blackberry) {
- CONFIG += qqnx_pps
-
- # Uncomment following line to enable screen event
- # handling through a dedicated thread.
- # CONFIG += qqnx_screeneventthread
-} else {
- CONFIG += qqnx_screeneventthread
-}
+!blackberry:CONFIG += qqnx_screeneventthread
# Uncomment these to enable debugging output for various aspects of the plugin
#DEFINES += QQNXBPSEVENTFILTER_DEBUG
@@ -33,7 +22,6 @@ CONFIG(blackberry) {
#DEFINES += QQNXNAVIGATOREVENTNOTIFIER_DEBUG
#DEFINES += QQNXNAVIGATOR_DEBUG
#DEFINES += QQNXRASTERBACKINGSTORE_DEBUG
-#DEFINES += QQNXROOTWINDOW_DEBUG
#DEFINES += QQNXSCREENEVENTTHREAD_DEBUG
#DEFINES += QQNXSCREENEVENT_DEBUG
#DEFINES += QQNXSCREEN_DEBUG
@@ -50,7 +38,6 @@ SOURCES = main.cpp \
qqnxscreen.cpp \
qqnxwindow.cpp \
qqnxrasterbackingstore.cpp \
- qqnxrootwindow.cpp \
qqnxscreeneventhandler.cpp \
qqnxnativeinterface.cpp \
qqnxnavigatoreventhandler.cpp \
@@ -67,7 +54,6 @@ HEADERS = main.h \
qqnxscreen.h \
qqnxwindow.h \
qqnxrasterbackingstore.h \
- qqnxrootwindow.h \
qqnxscreeneventhandler.h \
qqnxnativeinterface.h \
qqnxnavigatoreventhandler.h \
@@ -144,7 +130,8 @@ CONFIG(qqnx_pps) {
qqnxclipboard.h \
qqnxbuttoneventnotifier.h
- LIBS += -lpps -lclipboard
+ LIBS += -lpps
+ !contains(DEFINES, QT_NO_CLIPBOARD): LIBS += -lclipboard
CONFIG(qqnx_imf) {
DEFINES += QQNX_IMF
diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.cpp b/src/plugins/platforms/qnx/qqnxeglwindow.cpp
index e8fcdd692b..b57227a60b 100644
--- a/src/plugins/platforms/qnx/qqnxeglwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxeglwindow.cpp
@@ -42,6 +42,7 @@
#include "qqnxeglwindow.h"
#include "qqnxscreen.h"
+#include "qqnxglcontext.h"
#include <QDebug>
@@ -55,14 +56,15 @@
QT_BEGIN_NAMESPACE
-QQnxEglWindow::QQnxEglWindow(QWindow *window, screen_context_t context) :
- QQnxWindow(window, context),
- m_requestedBufferSize(window->geometry().size()),
+QQnxEglWindow::QQnxEglWindow(QWindow *window, screen_context_t context, bool needRootWindow) :
+ QQnxWindow(window, context, needRootWindow),
m_platformOpenGLContext(0),
m_newSurfaceRequested(true),
m_eglSurface(EGL_NO_SURFACE)
{
initWindow();
+ m_requestedBufferSize = screen()->rootWindow() == this ?
+ screen()->geometry().size() : window->geometry().size();
}
QQnxEglWindow::~QQnxEglWindow()
@@ -98,8 +100,6 @@ void QQnxEglWindow::createEGLSurface()
QQnxGLContext::checkEGLError("eglCreateWindowSurface");
qFatal("QQNX: failed to create EGL surface, err=%d", eglGetError());
}
-
- screen()->onWindowPost(0);
}
void QQnxEglWindow::destroyEGLSurface()
@@ -146,6 +146,9 @@ EGLSurface QQnxEglWindow::getSurface()
void QQnxEglWindow::setGeometry(const QRect &rect)
{
+ //If this is the root window, it has to be shown fullscreen
+ const QRect &newGeometry = screen()->rootWindow() == this ? screen()->geometry() : rect;
+
//We need to request that the GL context updates
// the EGLsurface on which it is rendering.
{
@@ -153,11 +156,11 @@ void QQnxEglWindow::setGeometry(const QRect &rect)
// setting m_requestedBufferSize and therefore extended the scope to include
// that test.
const QMutexLocker locker(&m_mutex);
- m_requestedBufferSize = rect.size();
- if (m_platformOpenGLContext != 0 && bufferSize() != rect.size())
+ m_requestedBufferSize = newGeometry.size();
+ if (m_platformOpenGLContext != 0 && bufferSize() != newGeometry.size())
m_newSurfaceRequested.testAndSetRelease(false, true);
}
- QQnxWindow::setGeometry(rect);
+ QQnxWindow::setGeometry(newGeometry);
}
QSize QQnxEglWindow::requestedBufferSize() const
@@ -166,6 +169,13 @@ QSize QQnxEglWindow::requestedBufferSize() const
return m_requestedBufferSize;
}
+void QQnxEglWindow::adjustBufferSize()
+{
+ const QSize windowSize = window()->size();
+ if (windowSize != bufferSize())
+ setBufferSize(windowSize);
+}
+
void QQnxEglWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext)
{
// This function does not take ownership of the platform gl context.
@@ -175,6 +185,9 @@ void QQnxEglWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContex
int QQnxEglWindow::pixelFormat() const
{
+ if (!m_platformOpenGLContext) //The platform GL context was not set yet
+ return -1;
+
const QSurfaceFormat format = m_platformOpenGLContext->format();
// Extract size of color channels from window format
const int redSize = format.redBufferSize();
diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.h b/src/plugins/platforms/qnx/qqnxeglwindow.h
index e7dae6a458..fc53afcd7a 100644
--- a/src/plugins/platforms/qnx/qqnxeglwindow.h
+++ b/src/plugins/platforms/qnx/qqnxeglwindow.h
@@ -43,8 +43,6 @@
#define QQNXEGLWINDOW_H
#include "qqnxwindow.h"
-#include "qqnxglcontext.h"
-
#include <QtCore/QMutex>
QT_BEGIN_NAMESPACE
@@ -54,7 +52,7 @@ class QQnxGLContext;
class QQnxEglWindow : public QQnxWindow
{
public:
- QQnxEglWindow(QWindow *window, screen_context_t context);
+ QQnxEglWindow(QWindow *window, screen_context_t context, bool needRootWindow);
~QQnxEglWindow();
void createEGLSurface();
@@ -70,7 +68,7 @@ public:
// Called by QQnxGLContext::createSurface()
QSize requestedBufferSize() const;
- WindowType windowType() const Q_DECL_OVERRIDE { return EGL; }
+ void adjustBufferSize();
protected:
int pixelFormat() const;
diff --git a/src/plugins/platforms/qnx/qqnxglcontext.h b/src/plugins/platforms/qnx/qqnxglcontext.h
index ff57861498..2b12657da9 100644
--- a/src/plugins/platforms/qnx/qqnxglcontext.h
+++ b/src/plugins/platforms/qnx/qqnxglcontext.h
@@ -75,6 +75,8 @@ public:
static EGLDisplay getEglDisplay();
EGLConfig getEglConfig() const { return m_eglConfig;}
+ EGLContext getEglContext() const { return m_eglContext; }
+
private:
//Can be static because different displays returne the same handle
static EGLDisplay ms_eglDisplay;
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index 09054b9eb9..5695ef433a 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -122,6 +122,17 @@ static inline QQnxIntegration::Options parseOptions(const QStringList &paramList
if (!paramList.contains(QLatin1String("no-fullscreen"))) {
options |= QQnxIntegration::FullScreenApplication;
}
+
+// On Blackberry the first window is treated as a root window
+#ifdef Q_OS_BLACKBERRY
+ if (!paramList.contains(QLatin1String("no-rootwindow"))) {
+ options |= QQnxIntegration::RootWindow;
+ }
+#else
+ if (paramList.contains(QLatin1String("rootwindow"))) {
+ options |= QQnxIntegration::RootWindow;
+ }
+#endif
return options;
}
@@ -326,9 +337,10 @@ bool QQnxIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
qIntegrationDebug() << Q_FUNC_INFO;
switch (cap) {
+ case MultipleWindows:
case ThreadedPixmaps:
return true;
-#if defined(QT_OPENGL_ES)
+#if !defined(QT_NO_OPENGL)
case OpenGL:
case ThreadedOpenGL:
case BufferQueueingOpenGL:
@@ -343,12 +355,13 @@ QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const
{
qIntegrationDebug() << Q_FUNC_INFO;
QSurface::SurfaceType surfaceType = window->surfaceType();
+ const bool needRootWindow = options() & RootWindow;
switch (surfaceType) {
case QSurface::RasterSurface:
- return new QQnxRasterWindow(window, m_screenContext);
+ return new QQnxRasterWindow(window, m_screenContext, needRootWindow);
#if !defined(QT_NO_OPENGL)
case QSurface::OpenGLSurface:
- return new QQnxEglWindow(window, m_screenContext);
+ return new QQnxEglWindow(window, m_screenContext, needRootWindow);
#endif
default:
qFatal("QQnxWindow: unsupported window API");
diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h
index ab0d6a3156..8b5614fe4f 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.h
+++ b/src/plugins/platforms/qnx/qqnxintegration.h
@@ -1,6 +1,6 @@
/***************************************************************************
**
-** Copyright (C) 2011 - 2012 Research In Motion
+** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
@@ -84,7 +84,8 @@ class QQnxIntegration : public QPlatformIntegration
public:
enum Option { // Options to be passed on command line.
NoOptions = 0x0,
- FullScreenApplication = 0x1
+ FullScreenApplication = 0x1,
+ RootWindow = 0x2
};
Q_DECLARE_FLAGS(Options, Option)
explicit QQnxIntegration(const QStringList &paramList);
diff --git a/src/plugins/platforms/qnx/qqnxnativeinterface.cpp b/src/plugins/platforms/qnx/qqnxnativeinterface.cpp
index 4dd3444832..6e7fc35a82 100644
--- a/src/plugins/platforms/qnx/qqnxnativeinterface.cpp
+++ b/src/plugins/platforms/qnx/qqnxnativeinterface.cpp
@@ -41,8 +41,11 @@
#include "qqnxnativeinterface.h"
+#include "qqnxglcontext.h"
#include "qqnxscreen.h"
+#include "qqnxwindow.h"
+#include <QtGui/QOpenGLContext>
#include <QtGui/QScreen>
#include <QtGui/QWindow>
@@ -70,4 +73,20 @@ void *QQnxNativeInterface::nativeResourceForScreen(const QByteArray &resource, Q
return 0;
}
+void *QQnxNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
+{
+ if (resource == "eglcontext" && context)
+ return static_cast<QQnxGLContext*>(context->handle())->getEglContext();
+
+ return 0;
+}
+
+void QQnxNativeInterface::setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value)
+{
+ if (name == QStringLiteral("mmRendererWindowName")) {
+ QQnxWindow *qnxWindow = static_cast<QQnxWindow*>(window);
+ qnxWindow->setMMRendererWindowName(value.toString());
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxnativeinterface.h b/src/plugins/platforms/qnx/qqnxnativeinterface.h
index 6692da2576..dfd386214e 100644
--- a/src/plugins/platforms/qnx/qqnxnativeinterface.h
+++ b/src/plugins/platforms/qnx/qqnxnativeinterface.h
@@ -51,6 +51,8 @@ class QQnxNativeInterface : public QPlatformNativeInterface
public:
void *nativeResourceForWindow(const QByteArray &resource, QWindow *window);
void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen);
+ void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context);
+ void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
index 16ff9d7519..1f974b268d 100644
--- a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
@@ -54,8 +54,8 @@
QT_BEGIN_NAMESPACE
-QQnxRasterWindow::QQnxRasterWindow(QWindow *window, screen_context_t context) :
- QQnxWindow(window, context),
+QQnxRasterWindow::QQnxRasterWindow(QWindow *window, screen_context_t context, bool needRootWindow) :
+ QQnxWindow(window, context, needRootWindow),
m_currentBufferIndex(-1),
m_previousBufferIndex(-1)
{
@@ -115,9 +115,6 @@ void QQnxRasterWindow::post(const QRegion &dirty)
// Save modified region and clear scrolled region
m_previousDirty = dirty;
m_scrolled = QRegion();
- // Notify screen that window posted
- if (screen() != 0)
- screen()->onWindowPost(this);
if (m_cover)
m_cover->updateCover();
@@ -169,6 +166,15 @@ QQnxBuffer &QQnxRasterWindow::renderBuffer()
return m_buffers[m_currentBufferIndex];
}
+void QQnxRasterWindow::adjustBufferSize()
+{
+ // When having a raster window we don't need any buffers, since
+ // Qt will draw to the parent TLW backing store.
+ const QSize windowSize = m_parentWindow ? QSize(1,1) : window()->size();
+ if (windowSize != bufferSize())
+ setBufferSize(windowSize);
+}
+
int QQnxRasterWindow::pixelFormat() const
{
return screen()->nativeFormat();
diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.h b/src/plugins/platforms/qnx/qqnxrasterwindow.h
index 8bd42bc320..ad34b3ccf2 100644
--- a/src/plugins/platforms/qnx/qqnxrasterwindow.h
+++ b/src/plugins/platforms/qnx/qqnxrasterwindow.h
@@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE
class QQnxRasterWindow : public QQnxWindow
{
public:
- QQnxRasterWindow(QWindow *window, screen_context_t context);
+ QQnxRasterWindow(QWindow *window, screen_context_t context, bool needRootWindow);
void post(const QRegion &dirty);
@@ -60,7 +60,7 @@ public:
bool hasBuffers() const { return !bufferSize().isEmpty(); }
- WindowType windowType() const Q_DECL_OVERRIDE { return Raster; }
+ void adjustBufferSize();
protected:
int pixelFormat() const;
@@ -69,6 +69,9 @@ protected:
// Copies content from the previous buffer (back buffer) to the current buffer (front buffer)
void blitPreviousToCurrent(const QRegion &region, int dx, int dy, bool flush=false);
+ void blitHelper(QQnxBuffer &source, QQnxBuffer &target, const QPoint &sourceOffset,
+ const QPoint &targetOffset, const QRegion &region, bool flush = false);
+
private:
QRegion m_previousDirty;
QRegion m_scrolled;
diff --git a/src/plugins/platforms/qnx/qqnxrootwindow.cpp b/src/plugins/platforms/qnx/qqnxrootwindow.cpp
deleted file mode 100644
index b3f5c87176..0000000000
--- a/src/plugins/platforms/qnx/qqnxrootwindow.cpp
+++ /dev/null
@@ -1,268 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2011 - 2012 Research In Motion
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqnxrootwindow.h"
-
-#include "qqnxscreen.h"
-
-#include <QtCore/QUuid>
-#include <QtCore/QDebug>
-
-#if defined(QQNXROOTWINDOW_DEBUG)
-#define qRootWindowDebug qDebug
-#else
-#define qRootWindowDebug QT_NO_QDEBUG_MACRO
-#endif
-
-#include <errno.h>
-#include <unistd.h>
-
-static const int MAGIC_ZORDER_FOR_NO_NAV = 10;
-
-QQnxRootWindow::QQnxRootWindow(const QQnxScreen *screen)
- : m_screen(screen),
- m_window(0),
- m_windowGroupName(),
- m_translucent(false)
-{
- qRootWindowDebug() << Q_FUNC_INFO;
- // Create one top-level QNX window to act as a container for child windows
- // since navigator only supports one application window
- errno = 0;
- int result = screen_create_window(&m_window, m_screen->nativeContext());
- int val[2];
- if (result != 0)
- qFatal("QQnxRootWindow: failed to create window, errno=%d", errno);
-
- // Move window to proper display
- errno = 0;
- screen_display_t display = m_screen->nativeDisplay();
- result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window display, errno=%d", errno);
-
- // Make sure window is above navigator but below keyboard if running as root
- // since navigator won't automatically set our z-order in this case
- if (getuid() == 0) {
- errno = 0;
- val[0] = MAGIC_ZORDER_FOR_NO_NAV;
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ZORDER, val);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window z-order, errno=%d", errno);
- }
-
- // Window won't be visible unless it has some buffers so make one dummy buffer that is 1x1
- errno = 0;
- val[0] = SCREEN_USAGE_NATIVE;
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_USAGE, val);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window buffer usage, errno=%d", errno);
-
- errno = 0;
- val[0] = m_screen->nativeFormat();
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window pixel format, errno=%d", errno);
-
- errno = 0;
- val[0] = 1;
- val[1] = 1;
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window buffer size, errno=%d", errno);
-
- errno = 0;
- result = screen_create_window_buffers(m_window, 1);
- if (result != 0)
- qFatal("QQNX: failed to create window buffer, errno=%d", errno);
-
- // Window is always the size of the display
- errno = 0;
- QRect geometry = m_screen->geometry();
- val[0] = geometry.width();
- val[1] = geometry.height();
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window size, errno=%d", errno);
-
- // Fill the window with solid black. Note that the LSB of the pixel value
- // 0x00000000 just happens to be 0x00, so if and when this root window's
- // alpha blending mode is changed from None to Source-Over, it will then
- // be interpreted as transparent.
- errno = 0;
- val[0] = 0;
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_COLOR, val);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window colour, errno=%d", errno);
-
- // Make the window opaque
- errno = 0;
- val[0] = SCREEN_TRANSPARENCY_NONE;
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, val);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window transparency, errno=%d", errno);
-
- // Set the swap interval to 1
- errno = 0;
- val[0] = 1;
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, val);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window swap interval, errno=%d", errno);
-
- // Set viewport size equal to window size but move outside buffer so the fill colour is used exclusively
- errno = 0;
- val[0] = geometry.width();
- val[1] = geometry.height();
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window source size, errno=%d", errno);
-
- errno = 0;
- val[0] = 0;
- val[1] = 0;
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_POSITION, val);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window source position, errno=%d", errno);
-
- // Optionally disable the screen power save
- bool ok = false;
- const int disablePowerSave = qgetenv("QQNX_DISABLE_POWER_SAVE").toInt(&ok);
- if (ok && disablePowerSave) {
- const int mode = SCREEN_IDLE_MODE_KEEP_AWAKE;
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_IDLE_MODE, &mode);
- if (result != 0)
- qWarning("QQnxRootWindow: failed to disable power saving mode");
- }
-
- createWindowGroup();
-
- // Don't post yet. This will be lazily done from QQnxScreen upon first posting of
- // a child window. Doing it now pre-emptively would create a flicker if one of
- // the QWindow's about to be created sets its Qt::WA_TranslucentBackground flag
- // and immediately triggers the buffer re-creation in makeTranslucent().
-}
-
-void QQnxRootWindow::makeTranslucent()
-{
- if (m_translucent)
- return;
-
- int result;
-
- errno = 0;
- const int val = SCREEN_TRANSPARENCY_DISCARD;
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, &val);
- if (result != 0) {
- qFatal("QQnxRootWindow: failed to set window transparency, errno=%d", errno);
- }
-
- m_translucent = true;
- post();
-}
-
-QQnxRootWindow::~QQnxRootWindow()
-{
- // Cleanup top-level QNX window
- screen_destroy_window(m_window);
-}
-
-void QQnxRootWindow::post() const
-{
- qRootWindowDebug() << Q_FUNC_INFO;
- errno = 0;
- screen_buffer_t buffer;
- int result = screen_get_window_property_pv(m_window, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&buffer);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to query window buffer, errno=%d", errno);
-
- errno = 0;
- int dirtyRect[] = {0, 0, 1, 1};
- result = screen_post_window(m_window, buffer, 1, dirtyRect, 0);
- if (result != 0)
- qFatal("QQNX: failed to post window buffer, errno=%d", errno);
-}
-
-void QQnxRootWindow::flush() const
-{
- qRootWindowDebug() << Q_FUNC_INFO;
- // Force immediate display update
- errno = 0;
- int result = screen_flush_context(m_screen->nativeContext(), 0);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to flush context, errno=%d", errno);
-}
-
-void QQnxRootWindow::setRotation(int rotation)
-{
- qRootWindowDebug() << Q_FUNC_INFO << "angle =" << rotation;
- errno = 0;
- int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ROTATION, &rotation);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window rotation, errno=%d", errno);
-}
-
-void QQnxRootWindow::resize(const QSize &size)
-{
- errno = 0;
- int val[] = {size.width(), size.height()};
- int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window size, errno=%d", errno);
-
- errno = 0;
- result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val);
- if (result != 0)
- qFatal("QQnxRootWindow: failed to set window source size, errno=%d", errno);
-
- // NOTE: display will update when child windows relayout and repaint
-}
-
-void QQnxRootWindow::createWindowGroup()
-{
- // Generate a random window group name
- m_windowGroupName = QUuid::createUuid().toString().toLatin1();
-
- // Create window group so child windows can be parented by container window
- errno = 0;
- int result = screen_create_window_group(m_window, m_windowGroupName.constData());
- if (result != 0)
- qFatal("QQnxRootWindow: failed to create app window group, errno=%d", errno);
-}
diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp
index dd8cf2131a..a09d6ce1f5 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreen.cpp
@@ -1,6 +1,6 @@
/***************************************************************************
**
-** Copyright (C) 2011 - 2012 Research In Motion
+** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
@@ -119,11 +119,43 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) {
#endif
}
+static QQnxWindow *findMultimediaWindow(const QList<QQnxWindow*> windows,
+ const QByteArray &mmWindowId)
+{
+ Q_FOREACH (QQnxWindow *sibling, windows) {
+ if (sibling->mmRendererWindowName() == mmWindowId)
+ return sibling;
+
+ QQnxWindow *mmWindow = findMultimediaWindow(sibling->children(), mmWindowId);
+
+ if (mmWindow)
+ return mmWindow;
+ }
+
+ return 0;
+}
+
+static QQnxWindow *findMultimediaWindow(const QList<QQnxWindow*> windows,
+ screen_window_t mmWindowId)
+{
+ Q_FOREACH (QQnxWindow *sibling, windows) {
+ if (sibling->mmRendererWindow() == mmWindowId)
+ return sibling;
+
+ QQnxWindow *mmWindow = findMultimediaWindow(sibling->children(), mmWindowId);
+
+ if (mmWindow)
+ return mmWindow;
+ }
+
+ return 0;
+}
+
QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display, bool primaryScreen)
: m_screenContext(screenContext),
m_display(display),
+ m_rootWindow(0),
m_primaryScreen(primaryScreen),
- m_posted(false),
m_keyboardHeight(0),
m_nativeOrientation(Qt::PrimaryOrientation),
m_coverWindow(0),
@@ -260,7 +292,8 @@ void QQnxScreen::setRotation(int rotation)
{
qScreenDebug() << Q_FUNC_INFO << "orientation =" << rotation;
// Check if rotation changed
- if (m_currentRotation != rotation) {
+ // We only want to rotate if we are the primary screen
+ if (m_currentRotation != rotation && isPrimaryScreen()) {
// Update rotation of root window
if (rootWindow())
rootWindow()->setRotation(rotation);
@@ -280,15 +313,13 @@ void QQnxScreen::setRotation(int rotation)
if (isOrthogonal(m_currentRotation, rotation)) {
qScreenDebug() << Q_FUNC_INFO << "resize, size =" << m_currentGeometry.size();
if (rootWindow())
- rootWindow()->resize(m_currentGeometry.size());
+ rootWindow()->setGeometry(QRect(QPoint(0,0), m_currentGeometry.size()));
- if (m_primaryScreen)
- resizeWindows(previousScreenGeometry);
+ resizeWindows(previousScreenGeometry);
} else {
// TODO: Find one global place to flush display updates
// Force immediate display update if no geometry changes required
- if (rootWindow())
- rootWindow()->flush();
+ screen_flush_context(nativeContext(), 0);
}
// Save new rotation
@@ -458,6 +489,8 @@ void QQnxScreen::removeWindow(QQnxWindow *window)
if (window != m_coverWindow) {
const int numWindowsRemoved = m_childWindows.removeAll(window);
+ if (window == m_rootWindow) //We just removed the root window
+ m_rootWindow = 0; //TODO we need a new root window ;)
if (numWindowsRemoved > 0)
updateHierarchy();
} else {
@@ -493,13 +526,15 @@ void QQnxScreen::updateHierarchy()
QList<QQnxWindow*>::const_iterator it;
int result;
- int topZorder;
+ int topZorder = 0;
errno = 0;
- if (isPrimaryScreen()) {
+ if (rootWindow()) {
result = screen_get_window_property_iv(rootWindow()->nativeHandle(), SCREEN_PROPERTY_ZORDER, &topZorder);
- if (result != 0)
- qFatal("QQnxScreen: failed to query root window z-order, errno=%d", errno);
+ if (result != 0) { //This can happen if we use winId in QWidgets
+ topZorder = 10;
+ qWarning("QQnxScreen: failed to query root window z-order, errno=%d", errno);
+ }
} else {
topZorder = 0; //We do not need z ordering on the secondary screen, because only one window
//is supported there
@@ -507,16 +542,17 @@ void QQnxScreen::updateHierarchy()
topZorder++; // root window has the lowest z-order in the windowgroup
+ int underlayZorder = -1;
// Underlays sit immediately above the root window in the z-ordering
Q_FOREACH (screen_window_t underlay, m_underlays) {
// Do nothing when this fails. This can happen if we have stale windows in m_underlays,
// which in turn can happen because a window was removed but we didn't get a notification
// yet.
- screen_set_window_property_iv(underlay, SCREEN_PROPERTY_ZORDER, &topZorder);
- topZorder++;
+ screen_set_window_property_iv(underlay, SCREEN_PROPERTY_ZORDER, &underlayZorder);
+ underlayZorder--;
}
- // Normal Qt windows come next above underlays in the z-ordering
+ // Normal Qt windows come next above the root window z-ordering
for (it = m_childWindows.constBegin(); it != m_childWindows.constEnd(); ++it)
(*it)->updateZorder(topZorder);
@@ -532,20 +568,6 @@ void QQnxScreen::updateHierarchy()
screen_flush_context( m_screenContext, 0 );
}
-void QQnxScreen::onWindowPost(QQnxWindow *window)
-{
- qScreenDebug() << Q_FUNC_INFO;
- Q_UNUSED(window)
-
- // post app window (so navigator will show it) after first child window
- // has posted; this only needs to happen once as the app window's content
- // never changes
- if (!m_posted && rootWindow()) {
- rootWindow()->post();
- m_posted = true;
- }
-}
-
void QQnxScreen::adjustOrientation()
{
if (!m_primaryScreen)
@@ -585,6 +607,19 @@ void QQnxScreen::addUnderlayWindow(screen_window_t window)
updateHierarchy();
}
+void QQnxScreen::addMultimediaWindow(const QByteArray &id, screen_window_t window)
+{
+ // find the QnxWindow this mmrenderer window is related to
+ QQnxWindow *mmWindow = findMultimediaWindow(m_childWindows, id);
+
+ if (!mmWindow)
+ return;
+
+ mmWindow->setMMRendererWindow(window);
+
+ updateHierarchy();
+}
+
void QQnxScreen::removeOverlayOrUnderlayWindow(screen_window_t window)
{
const int numRemoved = m_overlays.removeAll(window) + m_underlays.removeAll(window);
@@ -610,17 +645,35 @@ void QQnxScreen::newWindowCreated(void *window)
zorder = 0;
}
+ char windowNameBuffer[256] = { 0 };
+ QByteArray windowName;
+
+ if (screen_get_window_property_cv(windowHandle, SCREEN_PROPERTY_ID_STRING,
+ sizeof(windowNameBuffer) - 1, windowNameBuffer) != 0) {
+ qWarning("QQnx: Failed to get id for window, errno=%d", errno);
+ }
+
+ windowName = QByteArray(windowNameBuffer);
+
if (display == nativeDisplay()) {
// A window was created on this screen. If we don't know about this window yet, it means
// it was not created by Qt, but by some foreign library like the multimedia renderer, which
// creates an overlay window when playing a video.
//
- // Treat all foreign windows as overlays or underlays here.
+ // Treat all foreign windows as overlays, underlays or as windows
+ // created by the BlackBerry QtMultimedia plugin.
+ //
+ // In the case of the BlackBerry QtMultimedia plugin, we need to
+ // "attach" the foreign created mmrenderer window to the correct
+ // platform window (usually the one belonging to QVideoWidget) to
+ // ensure proper z-ordering.
//
- // Assume that if a foreign window already has a Z-Order both negative and
+ // Otherwise, assume that if a foreign window already has a Z-Order both negative and
// less than the default Z-Order installed by mmrender on windows it creates,
// the windows should be treated as an underlay. Otherwise, we treat it as an overlay.
- if (!findWindow(windowHandle)) {
+ if (!windowName.isEmpty() && windowName.startsWith("BbVideoWindowControl")) {
+ addMultimediaWindow(windowName, windowHandle);
+ } else if (!findWindow(windowHandle)) {
if (zorder <= MAX_UNDERLAY_ZORDER)
addUnderlayWindow(windowHandle);
else
@@ -634,7 +687,13 @@ void QQnxScreen::windowClosed(void *window)
{
Q_ASSERT(thread() == QThread::currentThread());
const screen_window_t windowHandle = reinterpret_cast<screen_window_t>(window);
- removeOverlayOrUnderlayWindow(windowHandle);
+
+ QQnxWindow *mmWindow = findMultimediaWindow(m_childWindows, windowHandle);
+
+ if (mmWindow)
+ mmWindow->clearMMRendererWindow();
+ else
+ removeOverlayOrUnderlayWindow(windowHandle);
}
void QQnxScreen::windowGroupStateChanged(const QByteArray &id, Qt::WindowState state)
@@ -644,7 +703,7 @@ void QQnxScreen::windowGroupStateChanged(const QByteArray &id, Qt::WindowState s
if (!rootWindow() || id != rootWindow()->groupName())
return;
- QWindow * const window = topMostChildWindow();
+ QWindow * const window = rootWindow()->window();
if (!window)
return;
@@ -659,7 +718,7 @@ void QQnxScreen::activateWindowGroup(const QByteArray &id)
if (!rootWindow() || id != rootWindow()->groupName())
return;
- QWindow * const window = topMostChildWindow();
+ QWindow * const window = rootWindow()->window();
if (!window)
return;
@@ -686,18 +745,28 @@ void QQnxScreen::deactivateWindowGroup(const QByteArray &id)
Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
childWindow->setExposed(false);
- QWindowSystemInterface::handleWindowActivated(0);
+ QWindowSystemInterface::handleWindowActivated(rootWindow()->window());
}
-QSharedPointer<QQnxRootWindow> QQnxScreen::rootWindow() const
+QQnxWindow *QQnxScreen::rootWindow() const
{
- // We only create the root window if we are the primary display.
- if (m_primaryScreen && !m_rootWindow)
- m_rootWindow = QSharedPointer<QQnxRootWindow>(new QQnxRootWindow(this));
-
return m_rootWindow;
}
+void QQnxScreen::setRootWindow(QQnxWindow *window)
+{
+ // Optionally disable the screen power save
+ bool ok = false;
+ const int disablePowerSave = qgetenv("QQNX_DISABLE_POWER_SAVE").toInt(&ok);
+ if (ok && disablePowerSave) {
+ const int mode = SCREEN_IDLE_MODE_KEEP_AWAKE;
+ int result = screen_set_window_property_iv(window->nativeHandle(), SCREEN_PROPERTY_IDLE_MODE, &mode);
+ if (result != 0)
+ qWarning("QQnxRootWindow: failed to disable power saving mode");
+ }
+ m_rootWindow = window;
+}
+
QWindow * QQnxScreen::topMostChildWindow() const
{
if (!m_childWindows.isEmpty()) {
diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h
index e11030ea0a..61c47e6c72 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.h
+++ b/src/plugins/platforms/qnx/qqnxscreen.h
@@ -44,7 +44,7 @@
#include <qpa/qplatformscreen.h>
-#include "qqnxrootwindow.h"
+#include "qqnxwindow.h"
#include <QtCore/QObject>
#include <QtCore/QScopedPointer>
@@ -91,10 +91,10 @@ public:
void lowerWindow(QQnxWindow *window);
void updateHierarchy();
- void onWindowPost(QQnxWindow *window);
void adjustOrientation();
- QSharedPointer<QQnxRootWindow> rootWindow() const;
+ QQnxWindow *rootWindow() const;
+ void setRootWindow(QQnxWindow*);
QPlatformCursor *cursor() const;
@@ -119,15 +119,15 @@ private:
void resizeWindows(const QRect &previousScreenGeometry);
void addOverlayWindow(screen_window_t window);
void addUnderlayWindow(screen_window_t window);
+ void addMultimediaWindow(const QByteArray &id, screen_window_t window);
void removeOverlayOrUnderlayWindow(screen_window_t window);
QWindow *topMostChildWindow() const;
screen_context_t m_screenContext;
screen_display_t m_display;
- mutable QSharedPointer<QQnxRootWindow> m_rootWindow;
+ QQnxWindow *m_rootWindow;
const bool m_primaryScreen;
- bool m_posted;
int m_initialRotation;
int m_currentRotation;
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
index a5d6db0985..37071d825c 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
@@ -40,6 +40,9 @@
****************************************************************************/
#include "qqnxscreeneventhandler.h"
+#if defined(QQNX_SCREENEVENTTHREAD)
+#include "qqnxscreeneventthread.h"
+#endif
#include "qqnxintegration.h"
#include "qqnxkeytranslator.h"
#include "qqnxscreen.h"
@@ -64,6 +67,9 @@ QQnxScreenEventHandler::QQnxScreenEventHandler(QQnxIntegration *integration)
, m_lastButtonState(Qt::NoButton)
, m_lastMouseWindow(0)
, m_touchDevice(0)
+#if defined(QQNX_SCREENEVENTTHREAD)
+ , m_eventThread(0)
+#endif
{
// Create a touch device
m_touchDevice = new QTouchDevice;
@@ -136,6 +142,10 @@ bool QQnxScreenEventHandler::handleEvent(screen_event_t event, int qnxType)
handleDisplayEvent(event);
break;
+ case SCREEN_EVENT_PROPERTY:
+ handlePropertyEvent(event);
+ break;
+
default:
// event ignored
qScreenEventDebug() << Q_FUNC_INFO << "unknown event" << qnxType;
@@ -189,6 +199,43 @@ void QQnxScreenEventHandler::injectKeyboardEvent(int flags, int sym, int modifie
}
}
+#if defined(QQNX_SCREENEVENTTHREAD)
+void QQnxScreenEventHandler::setScreenEventThread(QQnxScreenEventThread *eventThread)
+{
+ m_eventThread = eventThread;
+}
+
+void QQnxScreenEventHandler::processEventsFromScreenThread()
+{
+ if (!m_eventThread)
+ return;
+
+ QQnxScreenEventArray *events = m_eventThread->lock();
+
+ for (int i = 0; i < events->size(); ++i) {
+ screen_event_t event = events->at(i);
+ if (!event)
+ continue;
+ (*events)[i] = 0;
+
+ m_eventThread->unlock();
+
+ long result = 0;
+ QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
+ bool handled = dispatcher && dispatcher->filterNativeEvent(QByteArrayLiteral("screen_event_t"), event, &result);
+ if (!handled)
+ handleEvent(event);
+ screen_destroy_event(event);
+
+ m_eventThread->lock();
+ }
+
+ events->clear();
+
+ m_eventThread->unlock();
+}
+#endif
+
void QQnxScreenEventHandler::handleKeyboardEvent(screen_event_t event)
{
// get flags of key event
@@ -412,11 +459,20 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
if (w) {
// get size of screen which contains window
QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(w);
- QSizeF screenSize = platformScreen->physicalSize();
+ QSizeF screenSize = platformScreen->geometry().size();
// update cached position of current touch point
- m_touchPoints[touchId].normalPosition = QPointF( static_cast<qreal>(pos[0]) / screenSize.width(), static_cast<qreal>(pos[1]) / screenSize.height() );
- m_touchPoints[touchId].area = QRectF( pos[0], pos[1], 0.0, 0.0 );
+ m_touchPoints[touchId].normalPosition =
+ QPointF(static_cast<qreal>(pos[0]) / screenSize.width(),
+ static_cast<qreal>(pos[1]) / screenSize.height());
+
+ m_touchPoints[touchId].area = QRectF(w->geometry().left() + windowPos[0],
+ w->geometry().top() + windowPos[1], 0.0, 0.0);
+ QWindow *parent = w->parent();
+ while (parent) {
+ m_touchPoints[touchId].area.translate(parent->geometry().topLeft());
+ parent = parent->parent();
+ }
// determine event type and update state of current touch point
QEvent::Type type = QEvent::None;
@@ -451,8 +507,8 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
// inject event into Qt
QWindowSystemInterface::handleTouchEvent(w, m_touchDevice, pointList);
qScreenEventDebug() << Q_FUNC_INFO << "Qt touch, w =" << w
- << ", p=(" << pos[0] << "," << pos[1]
- << "), t=" << type;
+ << ", p=" << m_touchPoints[touchId].area.topLeft()
+ << ", t=" << type;
}
}
}
@@ -523,6 +579,48 @@ void QQnxScreenEventHandler::handleDisplayEvent(screen_event_t event)
}
}
+void QQnxScreenEventHandler::handlePropertyEvent(screen_event_t event)
+{
+ errno = 0;
+ int objectType;
+ if (screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType) != 0)
+ qFatal("QQNX: failed to query object type property, errno=%d", errno);
+
+ if (objectType != SCREEN_OBJECT_TYPE_WINDOW)
+ return;
+
+ errno = 0;
+ screen_window_t window = 0;
+ if (screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0)
+ qFatal("QQnx: failed to query window property, errno=%d", errno);
+
+ errno = 0;
+ int property;
+ if (screen_get_event_property_iv(event, SCREEN_PROPERTY_NAME, &property) != 0)
+ qFatal("QQnx: failed to query window property, errno=%d", errno);
+
+ switch (property) {
+ case SCREEN_PROPERTY_KEYBOARD_FOCUS:
+ handleKeyboardFocusPropertyEvent(window);
+ break;
+ default:
+ // event ignored
+ qScreenEventDebug() << Q_FUNC_INFO << "Ignore property event for property: " << property;
+ }
+}
+
+void QQnxScreenEventHandler::handleKeyboardFocusPropertyEvent(screen_window_t window)
+{
+ errno = 0;
+ int focus = 0;
+ if (window && screen_get_window_property_iv(window, SCREEN_PROPERTY_KEYBOARD_FOCUS, &focus) != 0)
+ qFatal("QQnx: failed to query keyboard focus property, errno=%d", errno);
+
+ QWindow *w = focus ? QQnxIntegration::window(window) : 0;
+
+ QWindowSystemInterface::handleWindowActivated(w);
+}
+
#include "moc_qqnxscreeneventhandler.cpp"
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
index af0b086eb8..a7bcd449ee 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
@@ -50,6 +50,9 @@ QT_BEGIN_NAMESPACE
class QQnxIntegration;
class QQnxScreenEventFilter;
+#if defined(QQNX_SCREENEVENTTHREAD)
+class QQnxScreenEventThread;
+#endif
class QQnxScreenEventHandler : public QObject
{
@@ -65,10 +68,19 @@ public:
static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
+#if defined(QQNX_SCREENEVENTTHREAD)
+ void setScreenEventThread(QQnxScreenEventThread *eventThread);
+#endif
+
Q_SIGNALS:
void newWindowCreated(void *window);
void windowClosed(void *window);
+#if defined(QQNX_SCREENEVENTTHREAD)
+private Q_SLOTS:
+ void processEventsFromScreenThread();
+#endif
+
private:
void handleKeyboardEvent(screen_event_t event);
void handlePointerEvent(screen_event_t event);
@@ -76,6 +88,8 @@ private:
void handleCloseEvent(screen_event_t event);
void handleCreateEvent(screen_event_t event);
void handleDisplayEvent(screen_event_t event);
+ void handlePropertyEvent(screen_event_t event);
+ void handleKeyboardFocusPropertyEvent(screen_window_t window);
private:
enum {
@@ -90,6 +104,9 @@ private:
QTouchDevice *m_touchDevice;
QWindowSystemInterface::TouchPoint m_touchPoints[MaximumTouchPoints];
QList<QQnxScreenEventFilter*> m_eventFilters;
+#if defined(QQNX_SCREENEVENTTHREAD)
+ QQnxScreenEventThread *m_eventThread;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
index f3f660bc03..25a597bab9 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
@@ -61,6 +61,9 @@ QQnxScreenEventThread::QQnxScreenEventThread(screen_context_t context, QQnxScree
m_screenEventHandler(screenEventHandler),
m_quit(false)
{
+ screenEventHandler->setScreenEventThread(this);
+ connect(this, SIGNAL(eventPending()), screenEventHandler, SLOT(processEventsFromScreenThread()), Qt::QueuedConnection);
+ connect(this, SIGNAL(finished()), screenEventHandler, SLOT(processEventsFromScreenThread()), Qt::QueuedConnection);
}
QQnxScreenEventThread::~QQnxScreenEventThread()
@@ -74,20 +77,31 @@ void QQnxScreenEventThread::injectKeyboardEvent(int flags, int sym, int mod, int
QQnxScreenEventHandler::injectKeyboardEvent(flags, sym, mod, scan, cap);
}
-void QQnxScreenEventThread::run()
+QQnxScreenEventArray *QQnxScreenEventThread::lock()
{
- screen_event_t event;
+ m_mutex.lock();
+ return &m_events;
+}
- // create screen event
- errno = 0;
- int result = screen_create_event(&event);
- if (result)
- qFatal("QQNX: failed to create screen event, errno=%d", errno);
+void QQnxScreenEventThread::unlock()
+{
+ m_mutex.unlock();
+}
+void QQnxScreenEventThread::run()
+{
qScreenEventThreadDebug() << Q_FUNC_INFO << "screen event thread started";
// loop indefinitely
while (!m_quit) {
+ screen_event_t event;
+
+ // create screen event
+ errno = 0;
+ int result = screen_create_event(&event);
+ if (result)
+ qFatal("QQNX: failed to create screen event, errno=%d", errno);
+
// block until screen event is available
errno = 0;
@@ -108,14 +122,22 @@ void QQnxScreenEventThread::run()
qScreenEventThreadDebug() << Q_FUNC_INFO << "QNX user screen event";
m_quit = true;
} else {
- m_screenEventHandler->handleEvent(event, qnxType);
+ m_mutex.lock();
+ m_events << event;
+ m_mutex.unlock();
+ emit eventPending();
}
}
qScreenEventThreadDebug() << Q_FUNC_INFO << "screen event thread stopped";
// cleanup
- screen_destroy_event(event);
+ m_mutex.lock();
+ Q_FOREACH (screen_event_t event, m_events) {
+ screen_destroy_event(event);
+ }
+ m_events.clear();
+ m_mutex.unlock();
}
void QQnxScreenEventThread::shutdown()
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventthread.h b/src/plugins/platforms/qnx/qqnxscreeneventthread.h
index 5e931819be..cbdb505b3b 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventthread.h
+++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.h
@@ -43,6 +43,7 @@
#define QQNXSCREENEVENTTHREAD_H
#include <QtCore/QThread>
+#include <QtCore/QMutex>
#include <screen/screen.h>
@@ -50,21 +51,33 @@ QT_BEGIN_NAMESPACE
class QQnxScreenEventHandler;
+typedef QVarLengthArray<screen_event_t, 64> QQnxScreenEventArray;
+
class QQnxScreenEventThread : public QThread
{
+ Q_OBJECT
+
public:
QQnxScreenEventThread(screen_context_t context, QQnxScreenEventHandler *screenEventHandler);
~QQnxScreenEventThread();
static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
+ QQnxScreenEventArray *lock();
+ void unlock();
+
protected:
void run();
+Q_SIGNALS:
+ void eventPending();
+
private:
void shutdown();
screen_context_t m_screenContext;
+ QMutex m_mutex;
+ QQnxScreenEventArray m_events;
QQnxScreenEventHandler *m_screenEventHandler;
bool m_quit;
};
diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp
index 3969a09098..b25c0b5b29 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxwindow.cpp
@@ -1,6 +1,6 @@
/***************************************************************************
**
-** Copyright (C) 2011 - 2012 Research In Motion
+** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
@@ -40,15 +40,16 @@
****************************************************************************/
#include "qqnxwindow.h"
-#if !defined(QT_NO_OPENGL)
-#include "qqnxglcontext.h"
-#endif
#include "qqnxintegration.h"
#include "qqnxscreen.h"
+#include <QUuid>
+
#include <QtGui/QWindow>
#include <qpa/qwindowsysteminterface.h>
+#include "private/qguiapplication_p.h"
+
#include <QtCore/QDebug>
#if defined(Q_OS_BLACKBERRY)
@@ -69,26 +70,36 @@
QT_BEGIN_NAMESPACE
-QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context)
+QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootWindow)
: QPlatformWindow(window),
m_screenContext(context),
+ m_parentWindow(0),
m_window(0),
m_screen(0),
- m_parentWindow(0),
m_visible(false),
m_exposed(true),
- m_windowState(Qt::WindowNoState)
+ m_windowState(Qt::WindowNoState),
+ m_mmRendererWindow(0)
{
qWindowDebug() << Q_FUNC_INFO << "window =" << window << ", size =" << window->size();
int result;
- // Create child QNX window
+ QQnxScreen *platformScreen = static_cast<QQnxScreen *>(window->screen()->handle());
+
+ m_isTopLevel = ( needRootWindow && !platformScreen->rootWindow())
+ || (!needRootWindow && !parent())
+ || window->type() == Qt::CoverWindow;
+
errno = 0;
- if (static_cast<QQnxScreen *>(window->screen()->handle())->isPrimaryScreen()
- && window->type() != Qt::CoverWindow) {
- result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW);
+ if (m_isTopLevel) {
+ result = screen_create_window(&m_window, m_screenContext); // Creates an application window
+ if (window->type() != Qt::CoverWindow) {
+ if (needRootWindow)
+ platformScreen->setRootWindow(this);
+ createWindowGroup();
+ }
} else {
- result = screen_create_window(&m_window, m_screenContext);
+ result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW);
}
if (result != 0)
qFatal("QQnxWindow: failed to create window, errno=%d", errno);
@@ -115,20 +126,24 @@ QQnxWindow::~QQnxWindow()
void QQnxWindow::setGeometry(const QRect &rect)
{
- const QRect oldGeometry = setGeometryHelper(rect);
+ QRect newGeometry = rect;
+ if (screen()->rootWindow() == this) //If this is the root window, it has to be shown fullscreen
+ newGeometry = screen()->geometry();
+
+ const QRect oldGeometry = setGeometryHelper(newGeometry);
// Send a geometry change event to Qt (triggers resizeEvent() in QWindow/QWidget).
// Calling flushWindowSystemEvents() here would flush input events which
// could result in re-entering QQnxWindow::setGeometry() again.
QWindowSystemInterface::setSynchronousWindowsSystemEvents(true);
- QWindowSystemInterface::handleGeometryChange(window(), rect);
- QWindowSystemInterface::handleExposeEvent(window(), rect);
+ QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
+ QWindowSystemInterface::handleExposeEvent(window(), newGeometry);
QWindowSystemInterface::setSynchronousWindowsSystemEvents(false);
// Now move all children.
if (!oldGeometry.isEmpty()) {
- const QPoint offset = rect.topLeft() - oldGeometry.topLeft();
+ const QPoint offset = newGeometry.topLeft() - oldGeometry.topLeft();
Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
childWindow->setOffset(offset);
}
@@ -262,16 +277,6 @@ bool QQnxWindow::isExposed() const
return m_visible && m_exposed;
}
-void QQnxWindow::adjustBufferSize()
-{
- if (m_parentWindow)
- return;
-
- const QSize windowSize = window()->size();
- if (windowSize != bufferSize())
- setBufferSize(windowSize);
-}
-
void QQnxWindow::setBufferSize(const QSize &size)
{
qWindowDebug() << Q_FUNC_INFO << "window =" << window() << "size =" << size;
@@ -290,6 +295,8 @@ void QQnxWindow::setBufferSize(const QSize &size)
// Create window buffers if they do not exist
if (m_bufferSize.isEmpty()) {
val[0] = pixelFormat();
+ if (val[0] == -1) // The platform GL context was not set yet on the window, so we can't procede
+ return;
errno = 0;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val);
@@ -303,12 +310,6 @@ void QQnxWindow::setBufferSize(const QSize &size)
qFatal("QQnxWindow: failed to create window buffers, errno=%d", errno);
}
- // If the child window has been configured for transparency, lazily create
- // a full-screen buffer to back the root window.
- if (window()->requestedFormat().hasAlpha()) {
- m_screen->rootWindow()->makeTranslucent();
- }
-
// check if there are any buffers available
int bufferCount = 0;
result = screen_get_window_property_iv(m_window, SCREEN_PROPERTY_RENDER_BUFFER_COUNT, &bufferCount);
@@ -333,6 +334,9 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen)
if (platformScreen == 0) { // The screen has been destroyed
m_screen = 0;
+ Q_FOREACH (QQnxWindow *childWindow, m_childWindows) {
+ childWindow->setScreen(0);
+ }
return;
}
@@ -342,26 +346,36 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen)
if (m_screen) {
qWindowDebug() << Q_FUNC_INFO << "Moving window to different screen";
m_screen->removeWindow(this);
- screen_leave_window_group(m_window);
+ QQnxIntegration *platformIntegration = static_cast<QQnxIntegration*>(QGuiApplicationPrivate::platformIntegration());
+
+ if ((platformIntegration->options() & QQnxIntegration::RootWindow)) {
+ screen_leave_window_group(m_window);
+ }
}
- platformScreen->addWindow(this);
m_screen = platformScreen;
-
- // Move window to proper screen/display
- errno = 0;
- screen_display_t display = platformScreen->nativeDisplay();
- int result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display);
- if (result != 0)
- qFatal("QQnxWindow: failed to set window display, errno=%d", errno);
-
-
- if (m_screen->isPrimaryScreen() && window()->type() != Qt::CoverWindow) {
- // Add window to display's window group
+ if (!m_parentWindow) {
+ platformScreen->addWindow(this);
+ }
+ if (m_isTopLevel) {
+ // Move window to proper screen/display
errno = 0;
- result = screen_join_window_group(m_window, platformScreen->windowGroupName());
+ screen_display_t display = platformScreen->nativeDisplay();
+ int result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display);
if (result != 0)
- qFatal("QQnxWindow: failed to join window group, errno=%d", errno);
+ qFatal("QQnxWindow: failed to set window display, errno=%d", errno);
+ } else {
+ errno = 0;
+ int result;
+ if (!parent()) {
+ result = screen_join_window_group(m_window, platformScreen->windowGroupName());
+ if (result != 0)
+ qFatal("QQnxWindow: failed to join window group, errno=%d", errno);
+ } else {
+ result = screen_join_window_group(m_window, static_cast<QQnxWindow*>(parent())->groupName().constData());
+ if (result != 0)
+ qFatal("QQnxWindow: failed to join window group, errno=%d", errno);
+ }
Q_FOREACH (QQnxWindow *childWindow, m_childWindows) {
// Only subwindows and tooltips need necessarily be moved to another display with the window.
@@ -405,20 +419,12 @@ void QQnxWindow::setParent(const QPlatformWindow *window)
setScreen(m_parentWindow->m_screen);
m_parentWindow->m_childWindows.push_back(this);
-
- // we don't need any buffers, since
- // Qt will draw to the parent TLW
- // backing store.
- setBufferSize(QSize(1, 1));
} else {
m_screen->addWindow(this);
-
- // recreate buffers, in case the
- // window has been reparented and
- // becomes a TLW
- adjustBufferSize();
}
+ adjustBufferSize();
+
m_screen->updateHierarchy();
}
@@ -489,6 +495,22 @@ void QQnxWindow::gainedFocus()
QWindowSystemInterface::handleWindowActivated(window());
}
+void QQnxWindow::setMMRendererWindowName(const QString &name)
+{
+ m_mmRendererWindowName = name;
+}
+
+void QQnxWindow::setMMRendererWindow(screen_window_t handle)
+{
+ m_mmRendererWindow = handle;
+}
+
+void QQnxWindow::clearMMRendererWindow()
+{
+ m_mmRendererWindowName.clear();
+ m_mmRendererWindow = 0;
+}
+
QQnxWindow *QQnxWindow::findWindow(screen_window_t windowHandle)
{
if (m_window == windowHandle)
@@ -524,6 +546,15 @@ void QQnxWindow::minimize()
#endif
}
+void QQnxWindow::setRotation(int rotation)
+{
+ qWindowDebug() << Q_FUNC_INFO << "angle =" << rotation;
+ errno = 0;
+ int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ROTATION, &rotation);
+ if (result != 0)
+ qFatal("QQnxRootWindow: failed to set window rotation, errno=%d", errno);
+}
+
void QQnxWindow::initWindow()
{
// Alpha channel is always pre-multiplied if present
@@ -577,23 +608,48 @@ void QQnxWindow::initWindow()
setWindowState(window()->windowState());
if (window()->parent() && window()->parent()->handle())
setParent(window()->parent()->handle());
- setGeometryHelper(window()->geometry());
+
+ if (screen()->rootWindow() == this) {
+ setGeometryHelper(screen()->geometry());
+ QWindowSystemInterface::handleGeometryChange(window(), screen()->geometry());
+ } else {
+ setGeometryHelper(window()->geometry());
+ }
}
+void QQnxWindow::createWindowGroup()
+{
+ // Generate a random window group name
+ m_windowGroupName = QUuid::createUuid().toString().toLatin1();
+
+ // Create window group so child windows can be parented by container window
+ errno = 0;
+ int result = screen_create_window_group(m_window, m_windowGroupName.constData());
+ if (result != 0)
+ qFatal("QQnxRootWindow: failed to create app window group, errno=%d", errno);
+}
void QQnxWindow::updateZorder(int &topZorder)
{
- errno = 0;
- int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ZORDER, &topZorder);
- topZorder++;
+ updateZorder(m_window, topZorder);
- if (result != 0)
- qFatal("QQnxWindow: failed to set window z-order=%d, errno=%d, mWindow=%p", topZorder, errno, m_window);
+ if (m_mmRendererWindow)
+ updateZorder(m_mmRendererWindow, topZorder);
Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
childWindow->updateZorder(topZorder);
}
+void QQnxWindow::updateZorder(screen_window_t window, int &topZorder)
+{
+ errno = 0;
+ int result = screen_set_window_property_iv(window, SCREEN_PROPERTY_ZORDER, &topZorder);
+ topZorder++;
+
+ if (result != 0)
+ qFatal("QQnxWindow: failed to set window z-order=%d, errno=%d, mWindow=%p", topZorder, errno, window);
+}
+
void QQnxWindow::applyWindowState()
{
switch (m_windowState) {
diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h
index f96280848a..3c8070b0be 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.h
+++ b/src/plugins/platforms/qnx/qqnxwindow.h
@@ -66,12 +66,7 @@ class QQnxWindow : public QPlatformWindow
{
friend class QQnxScreen;
public:
- enum WindowType {
- EGL,
- Raster
- };
-
- QQnxWindow(QWindow *window, screen_context_t context);
+ QQnxWindow(QWindow *window, screen_context_t context, bool needRootWindow);
virtual ~QQnxWindow();
void setGeometry(const QRect &rect);
@@ -83,7 +78,7 @@ public:
WId winId() const { return (WId)m_window; }
screen_window_t nativeHandle() const { return m_window; }
- void adjustBufferSize();
+ virtual void adjustBufferSize() = 0;
void setBufferSize(const QSize &size);
QSize bufferSize() const { return m_bufferSize; }
@@ -99,6 +94,9 @@ public:
void propagateSizeHints();
void gainedFocus();
+ void setMMRendererWindowName(const QString &name);
+ void setMMRendererWindow(screen_window_t handle);
+ void clearMMRendererWindow();
QQnxScreen *screen() const { return m_screen; }
const QList<QQnxWindow*>& children() const { return m_childWindows; }
@@ -107,7 +105,14 @@ public:
void minimize();
- virtual WindowType windowType() const = 0;
+ QString mmRendererWindowName() const { return m_mmRendererWindowName; }
+
+ screen_window_t mmRendererWindow() const { return m_mmRendererWindow; }
+
+ void setRotation(int rotation);
+
+ QByteArray groupName() const { return m_windowGroupName; }
+
protected:
virtual int pixelFormat() const = 0;
virtual void resetBuffers() = 0;
@@ -117,12 +122,16 @@ protected:
screen_context_t m_screenContext;
QScopedPointer<QQnxAbstractCover> m_cover;
+ QQnxWindow *m_parentWindow;
+
private:
+ void createWindowGroup();
QRect setGeometryHelper(const QRect &rect);
void removeFromParent();
void setOffset(const QPoint &setOffset);
void updateVisibility(bool parentVisible);
void updateZorder(int &topZorder);
+ void updateZorder(screen_window_t window, int &zOrder);
void applyWindowState();
screen_window_t m_window;
@@ -130,11 +139,16 @@ private:
QQnxScreen *m_screen;
QList<QQnxWindow*> m_childWindows;
- QQnxWindow *m_parentWindow;
bool m_visible;
bool m_exposed;
QRect m_unmaximizedGeometry;
Qt::WindowState m_windowState;
+ QString m_mmRendererWindowName;
+ screen_window_t m_mmRendererWindow;
+
+ QByteArray m_windowGroupName;
+
+ bool m_isTopLevel;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
index 9170c774b4..66ed9d85dc 100644
--- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp
+++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
@@ -44,7 +44,7 @@
#include "iaccessible2.h"
#include "qwindowsaccessibility.h"
-#include <QtGui/private/qaccessible2_p.h>
+#include <QtGui/qaccessible.h>
#include <QtGui/qclipboard.h>
#include <QtWidgets/qapplication.h>
#include <QtCore/qdebug.h>
diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
index 63b4370dc2..885bc37cff 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
@@ -51,7 +51,6 @@
#include <QtCore/qpointer.h>
#include <QtCore/qsettings.h>
#include <QtGui/qaccessible.h>
-#include <QtGui/private/qaccessible2_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <qpa/qplatformintegration.h>
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
index 93592eb969..8bb7646258 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
@@ -54,7 +54,6 @@
#include <QtCore/qpair.h>
#include <QtCore/qsettings.h>
#include <QtGui/qaccessible.h>
-#include <QtGui/private/qaccessible2_p.h>
#include <QtGui/qguiapplication.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/qwindow.h>
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index f6ed9447ef..7b574b0a56 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -93,6 +93,7 @@ enum WindowsEventType // Simplify event types
NonClientHitTest = NonClientEventFlag + 2,
KeyEvent = KeyEventFlag + 1,
KeyDownEvent = KeyEventFlag + KeyDownEventFlag + 1,
+ KeyboardLayoutChangeEvent = KeyEventFlag + 2,
InputMethodKeyEvent = InputMethodEventFlag + KeyEventFlag + 1,
InputMethodKeyDownEvent = InputMethodEventFlag + KeyEventFlag + KeyDownEventFlag + 1,
ClipboardEvent = ClipboardEventFlag + 1,
@@ -165,6 +166,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
return QtWindows::InputMethodKeyEvent;
case WM_IME_KEYDOWN:
return QtWindows::InputMethodKeyDownEvent;
+#ifdef WM_INPUTLANGCHANGE
+ case WM_INPUTLANGCHANGE:
+ return QtWindows::KeyboardLayoutChangeEvent;
+#endif // WM_INPUTLANGCHANGE
case WM_TOUCH:
return QtWindows::TouchEvent;
case WM_CHANGECBCHAIN:
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
index 26205eb146..55e7b85d96 100644
--- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
@@ -149,7 +149,23 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion &region)
QImage::Format format = QWindowsNativeImage::systemFormat();
if (format == QImage::Format_RGB32 && rasterWindow()->window()->format().hasAlpha())
format = QImage::Format_ARGB32_Premultiplied;
- m_image.reset(new QWindowsNativeImage(size.width(), size.height(), format));
+
+ QWindowsNativeImage *oldwni = m_image.data();
+ QWindowsNativeImage *newwni = new QWindowsNativeImage(size.width(), size.height(), format);
+
+ if (oldwni && !region.isEmpty()) {
+ const QImage &oldimg(oldwni->image());
+ QImage &newimg(newwni->image());
+ QRegion staticRegion(region);
+ staticRegion &= QRect(0, 0, oldimg.width(), oldimg.height());
+ staticRegion &= QRect(0, 0, newimg.width(), newimg.height());
+ QPainter painter(&newimg);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ foreach (const QRect &rect, staticRegion.rects())
+ painter.drawImage(rect, oldimg, rect);
+ }
+
+ m_image.reset(newwni);
}
}
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 85b03673ac..77cac647ba 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -783,9 +783,15 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::InputMethodCloseCandidateWindowEvent:
// TODO: Release/regrab mouse if a popup has mouse grab.
return false;
- case QtWindows::ClipboardEvent:
case QtWindows::DestroyEvent:
-
+ if (!platformWindow->testFlag(QWindowsWindow::WithinDestroy)) {
+ qWarning() << "External WM_DESTROY received for " << platformWindow->window()
+ << ", parent: " << platformWindow->window()->parent()
+ << ", transient parent: " << platformWindow->window()->transientParent();
+ }
+ return false;
+ case QtWindows::ClipboardEvent:
+ return false;
case QtWindows::UnknownEvent:
return false;
case QtWindows::AccessibleObjectFromWindowRequest:
@@ -842,8 +848,9 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::KeyEvent:
case QtWindows::InputMethodKeyEvent:
case QtWindows::InputMethodKeyDownEvent:
+ case QtWindows::KeyboardLayoutChangeEvent:
#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
- return platformSessionManager()->isInterractionBlocked() ? true : d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result);
+ return platformSessionManager()->isInteractionBlocked() ? true : d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result);
#else
return d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result);
#endif
@@ -867,7 +874,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::NonClientMouseEvent:
if (platformWindow->frameStrutEventsEnabled())
#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
- return platformSessionManager()->isInterractionBlocked() ? true : d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
+ return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
#else
return d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
#endif
@@ -887,13 +894,13 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::MouseEvent:
case QtWindows::LeaveEvent:
#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
- return platformSessionManager()->isInterractionBlocked() ? true : d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
+ return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
#else
return d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
#endif
case QtWindows::TouchEvent:
#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
- return platformSessionManager()->isInterractionBlocked() ? true : d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
+ return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
#else
return d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
#endif
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
index ac57a1b396..6c928119b3 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -161,12 +161,18 @@ bool QWindowsFontEngine::hasCFFTable() const
return GetFontData(hdc, MAKE_TAG('C', 'F', 'F', ' '), 0, 0, 0) != GDI_ERROR;
}
+bool QWindowsFontEngine::hasCMapTable() const
+{
+ HDC hdc = m_fontEngineData->hdc;
+ SelectObject(hdc, hfont);
+ return GetFontData(hdc, MAKE_TAG('c', 'm', 'a', 'p'), 0, 0, 0) != GDI_ERROR;
+}
+
void QWindowsFontEngine::getCMap()
{
- ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE);
+ ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE) || hasCMapTable();
- // TMPF_TRUETYPE is not set for fonts with CFF tables
- cffTable = !ttf && hasCFFTable();
+ cffTable = hasCFFTable();
HDC hdc = m_fontEngineData->hdc;
SelectObject(hdc, hfont);
@@ -374,6 +380,7 @@ HGDIOBJ QWindowsFontEngine::selectDesignFont() const
{
LOGFONT f = m_logfont;
f.lfHeight = unitsPerEm;
+ f.lfWidth = 0;
HFONT designFont = CreateFontIndirect(&f);
return SelectObject(m_fontEngineData->hdc, designFont);
}
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h
index d783b6048c..acf84d270c 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.h
+++ b/src/plugins/platforms/windows/qwindowsfontengine.h
@@ -140,6 +140,7 @@ private:
QWindowsNativeImage *drawGDIGlyph(HFONT font, glyph_t, int margin, const QTransform &xform,
QImage::Format mask_format);
bool hasCFFTable() const;
+ bool hasCMapTable() const;
const QSharedPointer<QWindowsFontEngineData> m_fontEngineData;
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
index 47c136991a..2743ef029d 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -86,6 +86,10 @@ QWindowsKeyMapper::~QWindowsKeyMapper()
#define VK_OEM_3 0xC0
#endif
+// We not only need the scancode itself but also the extended bit of key messages. Thus we need
+// the additional bit when masking the scancode.
+enum { scancodeBitmask = 0x1ff };
+
// Key recorder ------------------------------------------------------------------------[ start ] --
struct KeyRecord {
KeyRecord(int c, int a, int s, const QString &t) : code(c), ascii(a), state(s), text(t) {}
@@ -97,6 +101,8 @@ struct KeyRecord {
QString text;
};
+// We need to record the pressed keys in order to decide, whether the key event is an autorepeat
+// event. As soon as its state changes, the chain of autorepeat events will be broken.
static const int QT_MAX_KEY_RECORDINGS = 64; // User has LOTS of fingers...
struct KeyRecorder
{
@@ -503,12 +509,6 @@ static inline int toKeyOrUnicode(int vk, int scancode, unsigned char *kbdBuffer,
return code == Qt::Key_unknown ? 0 : code;
}
-int qt_translateKeyCode(int vk)
-{
- int code = winceKeyBend((vk < 0 || vk > 255) ? 0 : vk);
- return code == Qt::Key_unknown ? 0 : code;
-}
-
static inline int asciiToKeycode(char a, int state)
{
if (a >= 'a' && a <= 'z')
@@ -554,12 +554,8 @@ void QWindowsKeyMapper::changeKeyboard()
keyboardInputDirection = bidi ? Qt::RightToLeft : Qt::LeftToRight;
}
-void QWindowsKeyMapper::clearRecordedKeys()
-{
- key_recorder.clearKeys();
-}
-
-
+// Helper function that is used when obtaining the list of characters that can be produced by one key and
+// every possible combination of modifiers
inline void setKbdState(unsigned char *kbd, bool shift, bool ctrl, bool alt)
{
kbd[VK_LSHIFT ] = (shift ? 0x80 : 0);
@@ -570,14 +566,18 @@ inline void setKbdState(unsigned char *kbd, bool shift, bool ctrl, bool alt)
kbd[VK_MENU ] = (alt ? 0x80 : 0);
}
+// Adds the msg's key to keyLayout if it is not yet present there
void QWindowsKeyMapper::updateKeyMap(const MSG &msg)
{
unsigned char kbdBuffer[256]; // Will hold the complete keyboard state
GetKeyboardState(kbdBuffer);
- quint32 scancode = (msg.lParam >> 16) & 0xfff;
+ const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask;
updatePossibleKeyCodes(kbdBuffer, scancode, msg.wParam);
}
+// Fills keyLayout for that vk_key. Values are all characters one can type using that key
+// (in connection with every combination of modifiers) and whether these "characters" are
+// dead keys.
void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 scancode,
quint32 vk_key)
{
@@ -598,6 +598,10 @@ void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32
buffer[VK_RCONTROL] = 0;
buffer[VK_LMENU ] = 0; // Use right Alt, since left Ctrl + right Alt is considered AltGraph
+ // keyLayout contains the actual characters which can be written using the vk_key together with the
+ // different modifiers. '2' together with shift will for example cause the character
+ // to be @ for a US key layout (thus keyLayout[vk_key].qtKey[1] will be @). In addition to that
+ // it stores whether the resulting key is a dead key as these keys have to be handled later.
bool isDeadKey = false;
keyLayout[vk_key].deadkeys = 0;
keyLayout[vk_key].dirty = false;
@@ -635,8 +639,9 @@ void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32
}
keyLayout[vk_key].qtKey[8] = fallbackKey;
- // If this vk_key a Dead Key
- if (MapVirtualKey(vk_key, 2) & 0x80000000) {
+ // If one of the values inserted into the keyLayout above, can be considered a dead key, we have
+ // to run the workaround below.
+ if (keyLayout[vk_key].deadkeys) {
// Push a Space, then the original key through the low-level ToAscii functions.
// We do this because these functions (ToAscii / ToUnicode) will alter the internal state of
// the keyboard driver By doing the following, we set the keyboard driver state back to what
@@ -661,17 +666,6 @@ void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32
}
}
-bool QWindowsKeyMapper::isADeadKey(unsigned int vk_key, unsigned int modifiers)
-{
- if ((vk_key < NumKeyboardLayoutItems) && keyLayout[vk_key].exists) {
- for (size_t i = 0; i < NumMods; ++i) {
- if (uint(ModsTbl[i]) == modifiers)
- return bool(keyLayout[vk_key].deadkeys & 1<<i);
- }
- }
- return false;
-}
-
static inline QString messageKeyText(const MSG &msg)
{
const QChar ch = QChar((ushort)msg.wParam);
@@ -742,12 +736,21 @@ bool QWindowsKeyMapper::translateKeyEvent(QWindow *widget, HWND hwnd,
const MSG &msg, LRESULT *result)
{
*result = 0;
+
+ // Reset layout map when system keyboard layout is changed
+ if (msg.message == WM_INPUTLANGCHANGE) {
+ deleteLayouts();
+ return true;
+ }
+
+ // Add this key to the keymap if it is not present yet.
+ updateKeyMap(msg);
+
MSG peekedMsg;
// consume dead chars?(for example, typing '`','a' resulting in a-accent).
if (PeekMessage(&peekedMsg, hwnd, 0, 0, PM_NOREMOVE) && peekedMsg.message == WM_DEADCHAR)
return true;
- if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
- updateKeyMap(msg);
+
return translateKeyEventInternal(widget, msg, false);
}
@@ -755,9 +758,8 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
{
const int msgType = msg.message;
- const quint32 scancode = (msg.lParam >> 16) & 0xfff;
- const quint32 vk_key = MapVirtualKey(scancode, 1);
- const bool isNumpad = (msg.wParam >= VK_NUMPAD0 && msg.wParam <= VK_NUMPAD9);
+ const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask;
+ const quint32 vk_key = msg.wParam;
quint32 nModifiers = 0;
QWindow *receiver = m_keyGrabber ? m_keyGrabber : window;
@@ -786,10 +788,6 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
state |= (nModifiers & AltAny ? int(Qt::AltModifier) : 0);
state |= (nModifiers & MetaAny ? int(Qt::MetaModifier) : 0);
- // Now we know enough to either have MapVirtualKey or our own keymap tell us if it's a deadkey
- const bool isDeadKey = isADeadKey(msg.wParam, state)
- || MapVirtualKey(msg.wParam, 2) & 0x80000000;
-
// A multi-character key or a Input method character
// not found by our look-ahead
if (msgType == WM_CHAR || msgType == WM_IME_CHAR) {
@@ -849,23 +847,12 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
return true;
// Translate VK_* (native) -> Key_* (Qt) keys
- // If it's a dead key, we cannot use the toKeyOrUnicode() function, since that will change
- // the internal state of the keyboard driver, resulting in that dead keys no longer works.
- // ..also if we're typing numbers on the keypad, while holding down the Alt modifier.
- int code = 0;
- if (isNumpad && (nModifiers & AltAny)) {
- code = winceKeyBend(msg.wParam);
- } else if (!isDeadKey) {
- // QTBUG-8764, QTBUG-10032
- // Can't call toKeyOrUnicode because that would call ToUnicode, and, if a dead key
- // is pressed at the moment, Windows would NOT use it to compose a character for the next
- // WM_CHAR event.
-
- // Instead, use MapVirtualKey, which will provide adequate values.
- code = MapVirtualKey(msg.wParam, MAPVK_VK_TO_CHAR);
- if (code < 0x20 || code == 0x7f) // The same logic as in toKeyOrUnicode()
- code = winceKeyBend(msg.wParam);
- }
+ int modifiersIndex = 0;
+ modifiersIndex |= (nModifiers & ShiftAny ? 0x1 : 0);
+ modifiersIndex |= (nModifiers & ControlAny ? 0x2 : 0);
+ modifiersIndex |= (nModifiers & AltAny ? 0x4 : 0);
+
+ int code = keyLayout[vk_key].qtKey[modifiersIndex];
// Invert state logic:
// If the key actually pressed is a modifier key, then we remove its modifier key from the
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h
index ce6ca23708..f7d33758a0 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.h
+++ b/src/plugins/platforms/windows/qwindowskeymapper.h
@@ -100,9 +100,7 @@ private:
QLocale keyboardInputLocale;
Qt::LayoutDirection keyboardInputDirection;
- void clearRecordedKeys();
void updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 scancode, quint32 vk_key);
- bool isADeadKey(unsigned int vk_key, unsigned int modifiers);
void deleteLayouts();
QWindow *m_keyGrabber;
diff --git a/src/plugins/platforms/windows/qwindowssessionmanager.cpp b/src/plugins/platforms/windows/qwindowssessionmanager.cpp
index efdbb6b279..e86722f953 100644
--- a/src/plugins/platforms/windows/qwindowssessionmanager.cpp
+++ b/src/plugins/platforms/windows/qwindowssessionmanager.cpp
@@ -52,10 +52,6 @@ QWindowsSessionManager::QWindowsSessionManager(const QString &id, const QString
{
}
-QWindowsSessionManager::~QWindowsSessionManager()
-{
-}
-
bool QWindowsSessionManager::allowsInteraction()
{
m_blockUserInput = false;
@@ -68,16 +64,6 @@ bool QWindowsSessionManager::allowsErrorInteraction()
return true;
}
-void QWindowsSessionManager::blocksInteraction()
-{
- m_blockUserInput = true;
-}
-
-bool QWindowsSessionManager::isInterractionBlocked() const
-{
- return m_blockUserInput;
-}
-
void QWindowsSessionManager::release()
{
if (m_isActive)
@@ -89,24 +75,4 @@ void QWindowsSessionManager::cancel()
m_canceled = true;
}
-void QWindowsSessionManager::clearCancellation()
-{
- m_canceled = false;
-}
-
-bool QWindowsSessionManager::wasCanceled() const
-{
- return m_canceled;
-}
-
-void QWindowsSessionManager::setActive(bool active)
-{
- m_isActive = active;
-}
-
-bool QWindowsSessionManager::isActive() const
-{
- return m_isActive;
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowssessionmanager.h b/src/plugins/platforms/windows/qwindowssessionmanager.h
index 3e21cbabec..0443635c35 100644
--- a/src/plugins/platforms/windows/qwindowssessionmanager.h
+++ b/src/plugins/platforms/windows/qwindowssessionmanager.h
@@ -60,22 +60,21 @@ class QWindowsSessionManager : public QPlatformSessionManager
{
public:
explicit QWindowsSessionManager(const QString &id, const QString &key);
- virtual ~QWindowsSessionManager();
bool allowsInteraction() Q_DECL_OVERRIDE;
bool allowsErrorInteraction() Q_DECL_OVERRIDE;
- void blocksInteraction();
- bool isInterractionBlocked() const;
+ void blocksInteraction() { m_blockUserInput = true; }
+ bool isInteractionBlocked() const { return m_blockUserInput; }
void release() Q_DECL_OVERRIDE;
void cancel() Q_DECL_OVERRIDE;
- void clearCancellation();
- bool wasCanceled() const;
+ void clearCancellation() { m_canceled = false; }
+ bool wasCanceled() const { return m_canceled; }
- void setActive(bool active);
- bool isActive() const;
+ void setActive(bool active) { m_isActive = active; }
+ bool isActive() const { return m_isActive;}
private:
bool m_isActive;
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 1909e0313b..58047124a1 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -305,7 +305,7 @@ bool QWindowsWindow::setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool has
#endif // Q_OS_WINCE
}
-static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qreal level)
+static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bool openGL, qreal level)
{
#ifdef Q_OS_WINCE // WINCE does not support that feature and microsoft explicitly warns to use those calls
Q_UNUSED(hwnd);
@@ -314,8 +314,8 @@ static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qr
Q_UNUSED(level);
#else
if (QWindowsWindow::setWindowLayered(hwnd, flags, hasAlpha, level)) {
- if (hasAlpha && (flags & Qt::FramelessWindowHint)) {
- // Windows with alpha: Use blend function to update.
+ if (hasAlpha && !openGL && (flags & Qt::FramelessWindowHint)) {
+ // Non-GL windows with alpha: Use blend function to update.
BLENDFUNCTION blend = {AC_SRC_OVER, 0, (BYTE)(255.0 * level), AC_SRC_ALPHA};
QWindowsContext::user32dll.updateLayeredWindow(hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA);
} else {
@@ -661,7 +661,7 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLe
EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
}
- setWindowOpacity(hwnd, flags, hasAlpha, opacityLevel);
+ setWindowOpacity(hwnd, flags, hasAlpha, isGL, opacityLevel);
} else { // child.
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, swpFlags);
}
@@ -929,6 +929,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
QWindowsWindow::~QWindowsWindow()
{
+ setFlag(WithinDestroy);
#ifndef Q_OS_WINCE
if (testFlag(TouchRegistered))
QWindowsContext::user32dll.unregisterTouchWindow(m_data.hwnd);
@@ -1122,6 +1123,8 @@ QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const
void QWindowsWindow::updateTransientParent() const
{
#ifndef Q_OS_WINCE
+ if (window()->type() == Qt::Popup)
+ return; // QTBUG-34503, // a popup stays on top, no parent, see also WindowCreationData::fromWindow().
// Update transient parent.
const HWND oldTransientParent =
GetAncestor(m_data.hwnd, GA_PARENT) == GetDesktopWindow() ? GetAncestor(m_data.hwnd, GA_ROOTOWNER) : HWND(0);
@@ -1497,6 +1500,8 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowState state)
handleHidden();
QWindowSystemInterface::flushWindowSystemEvents(); // Tell QQuickWindow to stop rendering now.
break;
+ case Qt::WindowMaximized:
+ case Qt::WindowFullScreen:
case Qt::WindowNoState: {
// QTBUG-17548: We send expose events when receiving WM_Paint, but for
// layered windows and transient children, we won't receive any WM_Paint.
@@ -1548,7 +1553,7 @@ static const QScreen *effectiveScreen(const QWindow *w)
bool QWindowsWindow::isFullScreen_sys() const
{
- return geometry_sys() == effectiveScreen(window())->geometry();
+ return window()->isTopLevel() && geometry_sys() == effectiveScreen(window())->geometry();
}
/*!
@@ -1745,7 +1750,9 @@ void QWindowsWindow::setOpacity(qreal level)
if (m_opacity != level) {
m_opacity = level;
if (m_data.hwnd)
- setWindowOpacity(m_data.hwnd, m_data.flags, window()->format().hasAlpha(), level);
+ setWindowOpacity(m_data.hwnd, m_data.flags,
+ window()->format().hasAlpha(), testFlag(OpenGLSurface),
+ level);
}
}
diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp
index 5fc5b4ba97..3f1c53b122 100644
--- a/src/plugins/platforms/xcb/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/qglxintegration.cpp
@@ -440,6 +440,86 @@ bool QGLXContext::isValid() const
return m_context != 0;
}
+bool QGLXContext::m_queriedDummyContext = false;
+bool QGLXContext::m_supportsThreading = true;
+
+
+// If this list grows to any significant size, change it a
+// proper string table and make the implementation below use
+// binary search.
+static const char *qglx_threadedgl_blacklist_renderer[] = {
+ "Chromium", // QTBUG-32225 (initialization fails)
+ "Mesa DRI Intel(R) Sandybridge Mobile", // QTBUG-34492 (flickering in fullscreen)
+ 0
+};
+
+static const char *qglx_threadedgl_blacklist_vendor[] = {
+ "nouveau", // QTCREATORBUG-10875 (crash in creator)
+ 0
+};
+
+void QGLXContext::queryDummyContext()
+{
+ if (m_queriedDummyContext)
+ return;
+ m_queriedDummyContext = true;
+
+ static bool skip = qEnvironmentVariableIsSet("QT_OPENGL_NO_SANITY_CHECK");
+ if (skip)
+ return;
+
+ QOpenGLContext *oldContext = QOpenGLContext::currentContext();
+ QSurface *oldSurface = 0;
+ if (oldContext)
+ oldSurface = oldContext->surface();
+
+ QScopedPointer<QSurface> surface;
+ const char *glxvendor = glXGetClientString(glXGetCurrentDisplay(), GLX_VENDOR);
+ if (glxvendor && !strcmp(glxvendor, "ATI")) {
+ QWindow *window = new QWindow;
+ window->resize(64, 64);
+ window->setSurfaceType(QSurface::OpenGLSurface);
+ window->create();
+ surface.reset(window);
+ } else {
+ QOffscreenSurface *offSurface = new QOffscreenSurface;
+ offSurface->create();
+ surface.reset(offSurface);
+ }
+
+ QOpenGLContext context;
+ context.create();
+ context.makeCurrent(surface.data());
+
+ m_supportsThreading = true;
+
+ const char *renderer = (const char *) glGetString(GL_RENDERER);
+ for (int i = 0; qglx_threadedgl_blacklist_renderer[i]; ++i) {
+ if (strstr(renderer, qglx_threadedgl_blacklist_renderer[i]) != 0) {
+ m_supportsThreading = false;
+ break;
+ }
+ }
+
+ const char *vendor = (const char *) glGetString(GL_VENDOR);
+ for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) {
+ if (strstr(vendor, qglx_threadedgl_blacklist_vendor[i]) != 0) {
+ m_supportsThreading = false;
+ break;
+ }
+ }
+
+ context.doneCurrent();
+ if (oldContext && oldSurface)
+ oldContext->makeCurrent(oldSurface);
+}
+
+bool QGLXContext::supportsThreading()
+{
+ if (!m_queriedDummyContext)
+ queryDummyContext();
+ return m_supportsThreading;
+}
QGLXPbuffer::QGLXPbuffer(QOffscreenSurface *offscreenSurface)
: QPlatformOffscreenSurface(offscreenSurface)
diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h
index 1666f71060..00bba94ab3 100644
--- a/src/plugins/platforms/xcb/qglxintegration.h
+++ b/src/plugins/platforms/xcb/qglxintegration.h
@@ -72,6 +72,9 @@ public:
GLXContext glxContext() const { return m_context; }
+ static bool supportsThreading();
+ static void queryDummyContext();
+
private:
QXcbScreen *m_screen;
GLXContext m_context;
@@ -79,6 +82,8 @@ private:
QSurfaceFormat m_format;
bool m_isPBufferCurrent;
int m_swapInterval;
+ static bool m_queriedDummyContext;
+ static bool m_supportsThreading;
};
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 3f599123b9..96e6534b74 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1429,7 +1429,10 @@ static const char * xcb_atomnames = {
#if XCB_USE_MAEMO_WINDOW_PROPERTIES
"_MEEGOTOUCH_ORIENTATION_ANGLE\0"
#endif
- "_XSETTINGS_SETTINGS\0" // \0\0 terminates loop.
+ "_XSETTINGS_SETTINGS\0"
+ "_COMPIZ_DECOR_PENDING\0"
+ "_COMPIZ_DECOR_REQUEST\0"
+ "_COMPIZ_DECOR_DELETE_PIXMAP\0" // \0\0 terminates loop.
};
QXcbAtom::Atom QXcbConnection::qatom(xcb_atom_t xatom) const
@@ -1737,10 +1740,26 @@ bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, doub
return true;
}
-bool QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode)
+// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed:
+// - "pad0" became "extension"
+// - "pad1" and "pad" became "pad0"
+// New and old version of this struct share the following fields:
+// NOTE: API might change again in the next release of xcb in which case this comment will
+// need to be updated to reflect the reality.
+typedef struct qt_xcb_ge_event_t {
+ uint8_t response_type;
+ uint8_t extension;
+ uint16_t sequence;
+ uint32_t length;
+ uint16_t event_type;
+} qt_xcb_ge_event_t;
+
+bool QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *ev, int opCode)
{
- // xGenericEvent has "extension" on the second byte, xcb_ge_event_t has "pad0".
- if (event->pad0 == opCode) {
+ qt_xcb_ge_event_t *event = (qt_xcb_ge_event_t *)ev;
+ // xGenericEvent has "extension" on the second byte, the same is true for xcb_ge_event_t starting from
+ // the xcb version 1.9.3, prior to that it was called "pad0".
+ if (event->extension == opCode) {
// xcb event structs contain stuff that wasn't on the wire, the full_sequence field
// adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes.
// Move this data back to have the same layout in memory as it was on the wire
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 3f46f1c462..3a71eb2574 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -277,6 +277,10 @@ namespace QXcbAtom {
#endif
_XSETTINGS_SETTINGS,
+ _COMPIZ_DECOR_PENDING,
+ _COMPIZ_DECOR_REQUEST,
+ _COMPIZ_DECOR_DELETE_PIXMAP,
+
NPredefinedAtoms,
_QT_SETTINGS_TIMESTAMP = NPredefinedAtoms,
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 5168bd818b..ecbf28bab9 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -278,10 +278,15 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
#else
case OpenGL: return false;
#endif
+#if defined(XCB_USE_GLX)
+ case ThreadedOpenGL: return m_connections.at(0)->supportsThreadedRendering() && QGLXContext::supportsThreading();
+#else
case ThreadedOpenGL: return m_connections.at(0)->supportsThreadedRendering();
+#endif
case WindowMasks: return true;
case MultipleWindows: return true;
case ForeignWindows: return true;
+ case SyncState: return true;
default: return QPlatformIntegration::hasCapability(cap);
}
}
@@ -458,4 +463,11 @@ QPlatformSessionManager *QXcbIntegration::createPlatformSessionManager(const QSt
}
#endif
+void QXcbIntegration::sync()
+{
+ for (int i = 0; i < m_connections.size(); i++) {
+ m_connections.at(i)->sync();
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index 79fb1965c4..6ae23125c8 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -106,6 +106,7 @@ public:
QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const Q_DECL_OVERRIDE;
#endif
+ void sync();
private:
QList<QXcbConnection *> m_connections;
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 832f871bb7..806f948cc2 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -154,7 +154,7 @@ enum QX11EmbedMessageType {
XEMBED_ACTIVATE_ACCELERATOR = 14
};
-const long XEMBED_VERSION = 0;
+const quint32 XEMBED_VERSION = 0;
// Returns \c true if we should set WM_TRANSIENT_FOR on \a w
static inline bool isTransient(const QWindow *w)
@@ -403,7 +403,7 @@ void QXcbWindow::create()
}
// set the PID to let the WM kill the application if unresponsive
- long pid = getpid();
+ quint32 pid = getpid();
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
atom(QXcbAtom::_NET_WM_PID), XCB_ATOM_CARDINAL, 32,
1, &pid));
@@ -422,7 +422,7 @@ void QXcbWindow::create()
1, &leader));
/* Add XEMBED info; this operation doesn't initiate the embedding. */
- long data[] = { XEMBED_VERSION, XEMBED_MAPPED };
+ quint32 data[] = { XEMBED_VERSION, XEMBED_MAPPED };
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
atom(QXcbAtom::_XEMBED_INFO),
atom(QXcbAtom::_XEMBED_INFO),
@@ -1544,11 +1544,18 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
#endif
} else if (event->type == atom(QXcbAtom::_XEMBED)) {
handleXEmbedMessage(event);
- } else if (event->type == atom(QXcbAtom::MANAGER) || event->type == atom(QXcbAtom::_NET_ACTIVE_WINDOW)
- || event->type == atom(QXcbAtom::_NET_WM_STATE) || event->type == atom(QXcbAtom::MANAGER)
+ } else if (event->type == atom(QXcbAtom::_NET_ACTIVE_WINDOW)) {
+ connection()->setFocusWindow(this);
+ QWindowSystemInterface::handleWindowActivated(window());
+ } else if (event->type == atom(QXcbAtom::MANAGER)
+ || event->type == atom(QXcbAtom::_NET_WM_STATE)
|| event->type == atom(QXcbAtom::WM_CHANGE_STATE)) {
- // Ignore _NET_ACTIVE_WINDOW, _NET_WM_STATE, MANAGER which are relate to tray icons
+ // Ignore _NET_WM_STATE, MANAGER which are relate to tray icons
// and other messages.
+ } else if (event->type == atom(QXcbAtom::_COMPIZ_DECOR_PENDING)
+ || event->type == atom(QXcbAtom::_COMPIZ_DECOR_REQUEST)
+ || event->type == atom(QXcbAtom::_COMPIZ_DECOR_DELETE_PIXMAP)) {
+ //silence the _COMPIZ messages for now
} else {
qWarning() << "QXcbWindow: Unhandled client message:" << connection()->atomName(event->type);
}
@@ -1817,7 +1824,7 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
xcb_get_property_reply(xcb_connection(), get_cookie, NULL);
if (reply && reply->format == 32 && reply->type == wmStateAtom) {
- const long *data = (const long *)xcb_get_property_value(reply);
+ const quint32 *data = (const quint32 *)xcb_get_property_value(reply);
if (reply->length != 0 && XCB_WM_STATE_ICONIC == data[0])
newState = Qt::WindowMinimized;
}
@@ -1988,8 +1995,8 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
}
// Sends an XEmbed message.
-void QXcbWindow::sendXEmbedMessage(xcb_window_t window, long message,
- long detail, long data1, long data2)
+void QXcbWindow::sendXEmbedMessage(xcb_window_t window, quint32 message,
+ quint32 detail, quint32 data1, quint32 data2)
{
xcb_client_message_event_t event;
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 5601a115e9..45d44b213f 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -169,8 +169,8 @@ private:
void updateDoesNotAcceptFocus(bool doesNotAcceptFocus);
QRect windowToWmGeometry(QRect r) const;
- void sendXEmbedMessage(xcb_window_t window, long message,
- long detail = 0, long data1 = 0, long data2 = 0);
+ void sendXEmbedMessage(xcb_window_t window, quint32 message,
+ quint32 detail = 0, quint32 data1 = 0, quint32 data2 = 0);
void handleXEmbedMessage(const xcb_client_message_event_t *event);
void create();
diff --git a/src/plugins/platformthemes/gtk2/qgtk2theme.cpp b/src/plugins/platformthemes/gtk2/qgtk2theme.cpp
index f069d9f97c..812f4bc000 100644
--- a/src/plugins/platformthemes/gtk2/qgtk2theme.cpp
+++ b/src/plugins/platformthemes/gtk2/qgtk2theme.cpp
@@ -87,8 +87,16 @@ QVariant QGtk2Theme::themeHint(QPlatformTheme::ThemeHint hint) const
bool QGtk2Theme::usePlatformNativeDialog(DialogType type) const
{
- Q_UNUSED(type);
- return true;
+ switch (type) {
+ case ColorDialog:
+ return true;
+ case FileDialog:
+ return true;
+ case FontDialog:
+ return true;
+ default:
+ return false;
+ }
}
QPlatformDialogHelper *QGtk2Theme::createPlatformDialogHelper(DialogType type) const