summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
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