summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp4
-rw-r--r--src/plugins/generic/tuiotouch/qtuiohandler.cpp2
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp106
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h8
-rw-r--r--src/plugins/platforms/android/androidjniinput.cpp4
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp2
-rw-r--r--src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp8
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp6
-rw-r--r--src/plugins/platforms/android/qandroidplatformfontdatabase.cpp6
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm41
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm18
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h2
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm60
-rw-r--r--src/plugins/platforms/directfb/qdirectfbblitter.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp11
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp24
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.json3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro21
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp464
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h137
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp49
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp6
-rw-r--r--src/plugins/platforms/eglfs/qeglfscontext.cpp3
-rw-r--r--src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp21
-rw-r--r--src/plugins/platforms/eglfs/qeglfsdeviceintegration.h5
-rw-r--r--src/plugins/platforms/eglfs/qeglfsintegration.cpp15
-rw-r--r--src/plugins/platforms/eglfs/qeglfswindow.cpp34
-rw-r--r--src/plugins/platforms/eglfs/qeglfswindow.h2
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.h1
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm21
-rw-r--r--src/plugins/platforms/ios/qiosmenu.h4
-rw-r--r--src/plugins/platforms/ios/qiosmenu.mm39
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm187
-rw-r--r--src/plugins/platforms/ios/qiostheme.mm2
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm9
-rw-r--r--src/plugins/platforms/offscreen/qoffscreencommon.cpp4
-rw-r--r--src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp2
-rw-r--r--src/plugins/platforms/windows/openglblacklists/default.json14
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp4
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.cpp4
-rw-r--r--src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp78
-rw-r--r--src/plugins/platforms/winrt/qwinrttheme.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp45
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp43
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp11
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp20
59 files changed, 1343 insertions, 245 deletions
diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp
index 7258877eb7..3b8a85a26b 100644
--- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp
+++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp
@@ -845,7 +845,7 @@ QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QStri
QHashIterator<QString, QOfonoDataConnectionManagerInterface*> i(ofonoContextManagers);
while (i.hasNext()) {
i.next();
- const QString path = i.key() +"/"+contextPart;
+ const QString path = i.key() + QLatin1Char('/') +contextPart;
if (isActiveContext(path)) {
cpPriv->state |= QNetworkConfiguration::Active;
break;
@@ -1024,7 +1024,7 @@ QNetworkConfiguration::BearerType QNetworkManagerEngine::currentBearerType(const
QHashIterator<QString, QOfonoDataConnectionManagerInterface*> i(ofonoContextManagers);
while (i.hasNext()) {
i.next();
- QString contextPath = i.key() +"/"+contextPart;
+ QString contextPath = i.key() + QLatin1Char('/') +contextPart;
if (i.value()->contexts().contains(contextPath)) {
diff --git a/src/plugins/generic/tuiotouch/qtuiohandler.cpp b/src/plugins/generic/tuiotouch/qtuiohandler.cpp
index bc43a38bd8..2598bc5caf 100644
--- a/src/plugins/generic/tuiotouch/qtuiohandler.cpp
+++ b/src/plugins/generic/tuiotouch/qtuiohandler.cpp
@@ -203,7 +203,7 @@ void QTuioHandler::process2DCurAlive(const QOscMessage &message)
for (int i = 1; i < arguments.count(); ++i) {
if (QMetaType::Type(arguments.at(i).type()) != QMetaType::Int) {
- qWarning() << "Ignoring malformed TUIO alive message (bad argument on position" << i << arguments << ")";
+ qWarning() << "Ignoring malformed TUIO alive message (bad argument on position" << i << arguments << ')';
return;
}
diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
index 9a41244c63..f69bc5e401 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
@@ -73,13 +73,18 @@ public:
delete connection;
}
+ static QString getSocketPath();
static QDBusConnection *createConnection();
+ void initBus();
+ void createBusProxy();
+
QDBusConnection *connection;
QIBusProxy *bus;
QIBusInputContextProxy *context;
bool valid;
+ bool busConnected;
QString predit;
bool needsSurroundingText;
};
@@ -88,12 +93,21 @@ public:
QIBusPlatformInputContext::QIBusPlatformInputContext ()
: d(new QIBusPlatformInputContextPrivate())
{
- if (d->context) {
- connect(d->context, SIGNAL(CommitText(QDBusVariant)), SLOT(commitText(QDBusVariant)));
- connect(d->context, SIGNAL(UpdatePreeditText(QDBusVariant,uint,bool)), this, SLOT(updatePreeditText(QDBusVariant,uint,bool)));
- connect(d->context, SIGNAL(DeleteSurroundingText(int,uint)), this, SLOT(deleteSurroundingText(int,uint)));
- connect(d->context, SIGNAL(RequireSurroundingText()), this, SLOT(surroundingTextRequired()));
+ QString socketPath = QIBusPlatformInputContextPrivate::getSocketPath();
+ QFile file(socketPath);
+ if (file.open(QFile::ReadOnly)) {
+ // If KDE session save is used or restart ibus-daemon,
+ // the applications could run before ibus-daemon runs.
+ // We watch the getSocketPath() to get the launching ibus-daemon.
+ m_socketWatcher.addPath(socketPath);
+ connect(&m_socketWatcher, SIGNAL(fileChanged(QString)), this, SLOT(socketChanged(QString)));
}
+
+ m_timer.setSingleShot(true);
+ connect(&m_timer, SIGNAL(timeout()), this, SLOT(connectToBus()));
+
+ connectToContextSignals();
+
QInputMethod *p = qApp->inputMethod();
connect(p, SIGNAL(cursorRectangleChanged()), this, SLOT(cursorRectChanged()));
m_eventFilterUseSynchronousMode = false;
@@ -117,7 +131,7 @@ bool QIBusPlatformInputContext::isValid() const
void QIBusPlatformInputContext::invokeAction(QInputMethod::Action a, int)
{
- if (!d->valid)
+ if (!d->busConnected)
return;
if (a == QInputMethod::Click)
@@ -128,7 +142,7 @@ void QIBusPlatformInputContext::reset()
{
QPlatformInputContext::reset();
- if (!d->valid)
+ if (!d->busConnected)
return;
d->context->Reset();
@@ -139,7 +153,7 @@ void QIBusPlatformInputContext::commit()
{
QPlatformInputContext::commit();
- if (!d->valid)
+ if (!d->busConnected)
return;
QObject *input = qApp->focusObject();
@@ -193,7 +207,7 @@ void QIBusPlatformInputContext::update(Qt::InputMethodQueries q)
void QIBusPlatformInputContext::cursorRectChanged()
{
- if (!d->valid)
+ if (!d->busConnected)
return;
QRect r = qApp->inputMethod()->cursorRectangle().toRect();
@@ -211,7 +225,7 @@ void QIBusPlatformInputContext::cursorRectChanged()
void QIBusPlatformInputContext::setFocusObject(QObject *object)
{
- if (!d->valid)
+ if (!d->busConnected)
return;
if (debug)
@@ -291,7 +305,7 @@ void QIBusPlatformInputContext::deleteSurroundingText(int offset, uint n_chars)
bool QIBusPlatformInputContext::filterEvent(const QEvent *event)
{
- if (!d->valid)
+ if (!d->busConnected)
return false;
if (!inputMethodAccepted())
@@ -400,13 +414,66 @@ void QIBusPlatformInputContext::filterEventFinished(QDBusPendingCallWatcher *cal
call->deleteLater();
}
+void QIBusPlatformInputContext::socketChanged(const QString &str)
+{
+ qCDebug(qtQpaInputMethods) << "socketChanged";
+ Q_UNUSED (str);
+
+ m_timer.stop();
+
+ if (d->context)
+ disconnect(d->context);
+ if (d->connection)
+ d->connection->disconnectFromBus(QLatin1String("QIBusProxy"));
+
+ m_timer.start(100);
+}
+
+// When getSocketPath() is modified, the bus is not established yet
+// so use m_timer.
+void QIBusPlatformInputContext::connectToBus()
+{
+ qCDebug(qtQpaInputMethods) << "QIBusPlatformInputContext::connectToBus";
+ d->initBus();
+ connectToContextSignals();
+
+ if (m_socketWatcher.files().size() == 0)
+ m_socketWatcher.addPath(QIBusPlatformInputContextPrivate::getSocketPath());
+}
+
+void QIBusPlatformInputContext::connectToContextSignals()
+{
+ if (d->context) {
+ connect(d->context, SIGNAL(CommitText(QDBusVariant)), SLOT(commitText(QDBusVariant)));
+ connect(d->context, SIGNAL(UpdatePreeditText(QDBusVariant,uint,bool)), this, SLOT(updatePreeditText(QDBusVariant,uint,bool)));
+ connect(d->context, SIGNAL(DeleteSurroundingText(int,uint)), this, SLOT(deleteSurroundingText(int,uint)));
+ connect(d->context, SIGNAL(RequireSurroundingText()), this, SLOT(surroundingTextRequired()));
+ }
+}
+
QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate()
- : connection(createConnection()),
+ : connection(0),
bus(0),
context(0),
valid(false),
+ busConnected(false),
needsSurroundingText(false)
{
+ valid = !QStandardPaths::findExecutable(QString::fromLocal8Bit("ibus-daemon"), QStringList()).isEmpty();
+ if (!valid)
+ return;
+ initBus();
+}
+
+void QIBusPlatformInputContextPrivate::initBus()
+{
+ connection = createConnection();
+ busConnected = false;
+ createBusProxy();
+}
+
+void QIBusPlatformInputContextPrivate::createBusProxy()
+{
if (!connection || !connection->isConnected())
return;
@@ -442,11 +509,11 @@ QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate()
context->SetCapabilities(IBUS_CAP_PREEDIT_TEXT|IBUS_CAP_FOCUS|IBUS_CAP_SURROUNDING_TEXT);
if (debug)
- qDebug(">>>> valid!");
- valid = true;
+ qDebug(">>>> bus connected!");
+ busConnected = true;
}
-QDBusConnection *QIBusPlatformInputContextPrivate::createConnection()
+QString QIBusPlatformInputContextPrivate::getSocketPath()
{
QByteArray display(qgetenv("DISPLAY"));
QByteArray host = "unix";
@@ -464,9 +531,14 @@ QDBusConnection *QIBusPlatformInputContextPrivate::createConnection()
if (debug)
qDebug() << "host=" << host << "displayNumber" << displayNumber;
- QFile file(QDir::homePath() + QLatin1String("/.config/ibus/bus/") +
+ return QDir::homePath() + QLatin1String("/.config/ibus/bus/") +
QLatin1String(QDBusConnection::localMachineId()) +
- QLatin1Char('-') + QString::fromLocal8Bit(host) + QLatin1Char('-') + QString::fromLocal8Bit(displayNumber));
+ QLatin1Char('-') + QString::fromLocal8Bit(host) + QLatin1Char('-') + QString::fromLocal8Bit(displayNumber);
+}
+
+QDBusConnection *QIBusPlatformInputContextPrivate::createConnection()
+{
+ QFile file(getSocketPath());
if (!file.open(QFile::ReadOnly))
return 0;
diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h
index 127db7df8b..a8efd9deb3 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h
+++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h
@@ -37,7 +37,9 @@
#include <QtCore/qpointer.h>
#include <QtDBus/qdbuspendingreply.h>
+#include <QFileSystemWatcher>
#include <QLoggingCategory>
+#include <QTimer>
#include <QWindow>
QT_BEGIN_NAMESPACE
@@ -96,10 +98,16 @@ public Q_SLOTS:
void deleteSurroundingText(int offset, uint n_chars);
void surroundingTextRequired();
void filterEventFinished(QDBusPendingCallWatcher *call);
+ void socketChanged(const QString &str);
+ void connectToBus();
private:
QIBusPlatformInputContextPrivate *d;
bool m_eventFilterUseSynchronousMode;
+ QFileSystemWatcher m_socketWatcher;
+ QTimer m_timer;
+
+ void connectToContextSignals();
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp
index b410e5f68e..8982787ec9 100644
--- a/src/plugins/platforms/android/androidjniinput.cpp
+++ b/src/plugins/platforms/android/androidjniinput.cpp
@@ -278,7 +278,7 @@ namespace QtAndroidInput
}
#ifdef QT_DEBUG_ANDROID_STYLUS
- qDebug() << action << pointerType << buttonState << "@" << x << y << "pressure" << pressure << ": buttons" << buttons;
+ qDebug() << action << pointerType << buttonState << '@' << x << y << "pressure" << pressure << ": buttons" << buttons;
#endif
QWindowSystemInterface::handleTabletEvent(tlw, ulong(time),
@@ -681,7 +681,7 @@ namespace QtAndroidInput
return Qt::Key_AudioCycleTrack;
default:
- qWarning() << "Unhandled key code " << key << "!";
+ qWarning() << "Unhandled key code " << key << '!';
return 0;
}
}
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index cd40b7eec2..c7c82e255c 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -292,7 +292,7 @@ namespace QtAndroid
QString manufacturer = QJNIObjectPrivate::getStaticObjectField("android/os/Build", "MANUFACTURER", "Ljava/lang/String;").toString();
QString model = QJNIObjectPrivate::getStaticObjectField("android/os/Build", "MODEL", "Ljava/lang/String;").toString();
- return manufacturer + QStringLiteral(" ") + model;
+ return manufacturer + QLatin1Char(' ') + model;
}
int createSurface(AndroidSurfaceClient *client, const QRect &geometry, bool onTop, int imageDepth)
diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp
index 64be75b63f..6ad3d2dc9a 100644
--- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp
+++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp
@@ -122,8 +122,8 @@ public:
m_assetFile = 0;
m_assetDir = asset;
m_fileName = fileName;
- if (!m_fileName.endsWith(QChar(QLatin1Char('/'))))
- m_fileName += "/";
+ if (!m_fileName.endsWith(QLatin1Char('/')))
+ m_fileName += QLatin1Char('/');
}
~AndroidAbstractFileEngine()
@@ -231,8 +231,8 @@ public:
return;
m_fileName = file;
- if (!m_fileName.endsWith(QChar(QLatin1Char('/'))))
- m_fileName += "/";
+ if (!m_fileName.endsWith(QLatin1Char('/')))
+ m_fileName += QLatin1Char('/');
close();
}
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp
index b44340106d..e3ea048e84 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/qandroidinputcontext.cpp
@@ -342,7 +342,7 @@ QAndroidInputContext::QAndroidInputContext()
if (clazz == NULL) {
qCritical() << "Native registration unable to find class '"
<< QtNativeInputConnectionClassName
- << "'";
+ << '\'';
return;
}
@@ -350,7 +350,7 @@ QAndroidInputContext::QAndroidInputContext()
if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
qCritical() << "RegisterNatives failed for '"
<< QtNativeInputConnectionClassName
- << "'";
+ << '\'';
return;
}
@@ -358,7 +358,7 @@ QAndroidInputContext::QAndroidInputContext()
if (clazz == NULL) {
qCritical() << "Native registration unable to find class '"
<< QtExtractedTextClassName
- << "'";
+ << '\'';
return;
}
diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
index be1a3d7bdf..a8bbec9400 100644
--- a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
+++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
@@ -69,11 +69,11 @@ QStringList QAndroidPlatformFontDatabase::fallbacksForFamily(const QString &fami
{
QStringList result;
if (styleHint == QFont::Monospace || styleHint == QFont::Courier)
- result.append(QString(qgetenv("QT_ANDROID_FONTS_MONOSPACE")).split(";"));
+ result.append(QString(qgetenv("QT_ANDROID_FONTS_MONOSPACE")).split(QLatin1Char(';')));
else if (styleHint == QFont::Serif)
- result.append(QString(qgetenv("QT_ANDROID_FONTS_SERIF")).split(";"));
+ result.append(QString(qgetenv("QT_ANDROID_FONTS_SERIF")).split(QLatin1Char(';')));
else
- result.append(QString(qgetenv("QT_ANDROID_FONTS")).split(";"));
+ result.append(QString(qgetenv("QT_ANDROID_FONTS")).split(QLatin1Char(';')));
result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script));
return result;
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index 2098f0dc8c..8e38181c29 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -303,7 +303,7 @@ NSCursor *QCocoaCursor::createCursorFromPixmap(const QPixmap pixmap, const QPoin
NSImage *nsimage;
if (pixmap.devicePixelRatio() > 1.0) {
QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio();
- QPixmap scaledPixmap = pixmap.scaled(layoutSize);
+ QPixmap scaledPixmap = pixmap.scaled(layoutSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(scaledPixmap));
CGImageRef cgImage = qt_mac_toCGImage(pixmap.toImage());
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index bb493ef2be..8ad80333f8 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -622,7 +622,7 @@ QString qt_mac_applicationName()
if (appName.isEmpty()) {
QString arg0 = QGuiApplicationPrivate::instance()->appName();
if (arg0.contains("/")) {
- QStringList parts = arg0.split("/");
+ QStringList parts = arg0.split(QLatin1Char('/'));
appName = parts.at(parts.count() - 1);
} else {
appName = arg0;
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 57739f3a58..aa7a09805a 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -463,6 +463,13 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
NSView *view = cocoaWindow ? cocoaWindow->contentView() : nil;
NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil;
+ QScreen *screen = 0;
+ if (parentWindow)
+ screen = parentWindow->screen();
+ if (!screen && !QGuiApplication::screens().isEmpty())
+ screen = QGuiApplication::screens().at(0);
+ Q_ASSERT(screen);
+
// Ideally, we would call -popUpMenuPositioningItem:atLocation:inView:.
// However, this showed not to work with modal windows where the menu items
// would appear disabled. So, we resort to a more artisanal solution. Note
@@ -479,6 +486,21 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
[popupCell setTransparent:YES];
[popupCell setMenu:m_nativeMenu];
[popupCell selectItem:nsItem];
+
+ int availableHeight = screen->availableSize().height();
+ const QPoint &globalPos = parentWindow->mapToGlobal(pos);
+ int menuHeight = m_nativeMenu.size.height;
+ if (globalPos.y() + menuHeight > availableHeight) {
+ // Maybe we need to fix the vertical popup position but we don't know the
+ // exact popup height at the moment (and Cocoa is just guessing) nor its
+ // position. So, instead of translating by the popup's full height, we need
+ // to estimate where the menu will show up and translate by the remaining height.
+ float idx = ([m_nativeMenu indexOfItem:nsItem] + 1.0f) / m_nativeMenu.numberOfItems;
+ float heightBelowPos = (1.0 - idx) * menuHeight;
+ if (globalPos.y() + heightBelowPos > availableHeight)
+ pos.setY(pos.y() - globalPos.y() + availableHeight - heightBelowPos);
+ }
+
NSRect cellFrame = NSMakeRect(pos.x(), pos.y(), m_nativeMenu.minimumWidth, 10);
[popupCell performClickWithFrame:cellFrame inView:view];
} else {
@@ -487,22 +509,21 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
if (view) {
// convert coordinates from view to the view's window
nsPos = [view convertPoint:nsPos toView:nil];
- } else if (!QGuiApplication::screens().isEmpty()) {
- QScreen *screen = QGuiApplication::screens().at(0);
+ } else {
nsPos.y = screen->availableVirtualSize().height() - nsPos.y;
}
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];
+ 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];
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index f78a27614e..e830be212a 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -270,7 +270,6 @@ public: // for QNSView
QPointer<QWindow> m_enterLeaveTargetWindow;
bool m_windowUnderMouse;
- bool m_ignoreWindowShouldClose;
bool m_inConstructor;
bool m_inSetVisible;
bool m_inSetGeometry;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index f790259f0e..adfef81117 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -345,7 +345,6 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_synchedWindowState(Qt::WindowActive)
, m_windowModality(Qt::NonModal)
, m_windowUnderMouse(false)
- , m_ignoreWindowShouldClose(false)
, m_inConstructor(true)
, m_inSetVisible(false)
, m_inSetGeometry(false)
@@ -809,13 +808,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
return styleMask;
if ((type & Qt::Popup) == Qt::Popup) {
if (!windowIsPopupType(type)) {
- styleMask = NSUtilityWindowMask;
+ styleMask = NSUtilityWindowMask | NSResizableWindowMask;
if (!(flags & Qt::CustomizeWindowHint)) {
- styleMask |= NSResizableWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask | NSTitledWindowMask;
+ styleMask |= NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask;
} else {
- if (flags & Qt::WindowMaximizeButtonHint)
- styleMask |= NSResizableWindowMask;
if (flags & Qt::WindowTitleHint)
styleMask |= NSTitledWindowMask;
if (flags & Qt::WindowCloseButtonHint)
@@ -1228,9 +1224,10 @@ void QCocoaWindow::windowDidEndLiveResize()
bool QCocoaWindow::windowShouldClose()
{
- // might have been set from qnsview.mm
- if (m_ignoreWindowShouldClose)
- return false;
+ // This callback should technically only determine if the window
+ // should (be allowed to) close, but since our QPA API to determine
+ // that also involves actually closing the window we do both at the
+ // same time, instead of doing the latter in windowWillClose.
bool accepted = false;
QWindowSystemInterface::handleCloseEvent(window(), &accepted);
QWindowSystemInterface::flushWindowSystemEvents();
@@ -1364,6 +1361,9 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
[m_contentView setHidden: YES];
}
+ m_nsWindow.ignoresMouseEvents =
+ (window()->flags() & Qt::WindowTransparentForInput) == Qt::WindowTransparentForInput;
+
const qreal opacity = qt_window_private(window())->opacity;
if (!qFuzzyCompare(opacity, qreal(1.0)))
setOpacity(opacity);
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index a49a42378d..d7b9c3831b 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -76,6 +76,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
bool m_resendKeyEvent;
bool m_scrolling;
bool m_exposedOnMoveToWindow;
+ NSEvent *m_currentlyInterpretedKeyEvent;
}
- (id)init;
@@ -131,7 +132,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
- (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType;
- (void)keyDown:(NSEvent *)theEvent;
- (void)keyUp:(NSEvent *)theEvent;
-- (BOOL)performKeyEquivalent:(NSEvent *)theEvent;
- (void)registerDragTypes;
- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender;
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 4db55c1b73..8c22e51fe2 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -152,6 +152,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self];
m_resendKeyEvent = false;
m_scrolling = false;
+ m_currentlyInterpretedKeyEvent = 0;
if (!touchDevice) {
touchDevice = new QTouchDevice;
@@ -709,8 +710,12 @@ QT_WARNING_POP
// Popups implicitly grap mouse events; forward to the active popup if there is one
if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) {
- if (QNSView *popupView = popup->qtView())
- targetView = popupView;
+ // Tooltips must be transparent for mouse events
+ // The bug reference is QTBUG-46379
+ if (!popup->m_windowFlags.testFlag(Qt::ToolTip)) {
+ if (QNSView *popupView = popup->qtView())
+ targetView = popupView;
+ }
}
[targetView convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
@@ -1436,41 +1441,40 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
if (!(modifiers & (Qt::ControlModifier | Qt::MetaModifier)) && (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff))
text = QCFString::toQString(characters);
- QWindow *focusWindow = [self topLevelWindow];
+ QWindow *window = [self topLevelWindow];
+
+ // Popups implicitly grab key events; forward to the active popup if there is one.
+ // This allows popups to e.g. intercept shortcuts and close the popup in response.
+ if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow())
+ window = popup->window();
if (eventType == QEvent::KeyPress) {
if (m_composingText.isEmpty()) {
- QKeyEvent override(QEvent::ShortcutOverride, keyCode, modifiers,
- nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1);
- override.setTimestamp(timestamp);
- m_sendKeyEvent = !QWindowSystemInterface::tryHandleShortcutOverrideEvent(focusWindow, &override);
+ m_sendKeyEvent = !QWindowSystemInterface::handleShortcutEvent(window, timestamp, keyCode,
+ modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1);
}
QObject *fo = QGuiApplication::focusObject();
if (m_sendKeyEvent && fo) {
- // if escape is pressed we don't want interpretKeyEvents to close a dialog. This will be done via QWindowSystemInterface
- if (keyCode == Qt::Key_Escape)
- m_platformWindow->m_ignoreWindowShouldClose = true;
-
QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints);
if (QCoreApplication::sendEvent(fo, &queryEvent)) {
bool imEnabled = queryEvent.value(Qt::ImEnabled).toBool();
Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt());
if (imEnabled && !(hints & Qt::ImhDigitsOnly || hints & Qt::ImhFormattedNumbersOnly || hints & Qt::ImhHiddenText)) {
// pass the key event to the input method. note that m_sendKeyEvent may be set to false during this call
+ m_currentlyInterpretedKeyEvent = nsevent;
[self interpretKeyEvents:[NSArray arrayWithObject:nsevent]];
+ m_currentlyInterpretedKeyEvent = 0;
}
}
-
- m_platformWindow->m_ignoreWindowShouldClose = false;;
}
if (m_resendKeyEvent)
m_sendKeyEvent = true;
}
if (m_sendKeyEvent && m_composingText.isEmpty())
- QWindowSystemInterface::handleExtendedKeyEvent(focusWindow, timestamp, QEvent::Type(eventType), keyCode, modifiers,
+ QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, QEvent::Type(eventType), keyCode, modifiers,
nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1, false);
m_sendKeyEvent = false;
@@ -1491,21 +1495,23 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
[self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)];
}
-- (BOOL)performKeyEquivalent:(NSEvent *)nsevent
+- (void)cancelOperation:(id)sender
{
- NSString *chars = [nsevent charactersIgnoringModifiers];
+ Q_UNUSED(sender);
- if ([nsevent type] == NSKeyDown && [chars length] > 0) {
- QChar ch = [chars characterAtIndex:0];
- Qt::Key qtKey = qt_mac_cocoaKey2QtKey(ch);
- // check for Command + Key_Period
- if ([nsevent modifierFlags] & NSCommandKeyMask
- && qtKey == Qt::Key_Period) {
- [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
- return YES;
- }
- }
- return [super performKeyEquivalent:nsevent];
+ NSEvent *currentEvent = [NSApp currentEvent];
+ if (!currentEvent || currentEvent.type != NSKeyDown)
+ return;
+
+ // Handling the key event may recurse back here through interpretKeyEvents
+ // (when IM is enabled), so we need to guard against that.
+ if (currentEvent == m_currentlyInterpretedKeyEvent)
+ return;
+
+ // Send Command+Key_Period and Escape as normal keypresses so that
+ // the key sequence is delivered through Qt. That way clients can
+ // intercept the shortcut and override its effect.
+ [self handleKeyEvent:currentEvent eventType:int(QEvent::KeyPress)];
}
- (void)flagsChanged:(NSEvent *)nsevent
diff --git a/src/plugins/platforms/directfb/qdirectfbblitter.cpp b/src/plugins/platforms/directfb/qdirectfbblitter.cpp
index 4deac969e4..b87310ed76 100644
--- a/src/plugins/platforms/directfb/qdirectfbblitter.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbblitter.cpp
@@ -473,7 +473,7 @@ IDirectFBSurface *QDirectFbTextureGlyphCache::sourceSurface()
case QImage::Format_Mono:
desc.pixelformat = DSPF_A1;
break;
- case QImage::Format_Indexed8:
+ case QImage::Format_Alpha8:
desc.pixelformat = DSPF_A8;
break;
default:
diff --git a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro
index 0adbb0d49f..cf367d930f 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro
@@ -1,7 +1,8 @@
TEMPLATE = subdirs
contains(QT_CONFIG, egl_x11): SUBDIRS += eglfs_x11
-contains(QT_CONFIG, kms): SUBDIRS += eglfs_kms
+contains(QT_CONFIG, eglfs_gbm): SUBDIRS += eglfs_kms
+contains(QT_CONFIG, eglfs_egldevice): SUBDIRS += eglfs_kms_egldevice
contains(QT_CONFIG, eglfs_brcm): SUBDIRS += eglfs_brcm
contains(QT_CONFIG, eglfs_mali): SUBDIRS += eglfs_mali
contains(QT_CONFIG, eglfs_viv): SUBDIRS += eglfs_viv
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp
index f3df1f8445..c29d64c06d 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp
@@ -191,6 +191,12 @@ QEglFSKmsScreen *QEglFSKmsDevice::screenForConnector(drmModeResPtr resources, dr
return Q_NULLPTR;
}
+ // Skip disconnected output
+ if (configuration == OutputConfigPreferred && connector->connection == DRM_MODE_DISCONNECTED) {
+ qCDebug(qLcEglfsKmsDebug) << "Skipping disconnected output" << connectorName;
+ return Q_NULLPTR;
+ }
+
// Get the current mode on the current crtc
drmModeModeInfo crtc_mode;
memset(&crtc_mode, 0, sizeof crtc_mode);
@@ -213,7 +219,7 @@ QEglFSKmsScreen *QEglFSKmsDevice::screenForConnector(drmModeResPtr resources, dr
for (int i = 0; i < connector->count_modes; i++) {
const drmModeModeInfo &mode = connector->modes[i];
qCDebug(qLcEglfsKmsDebug) << "mode" << i << mode.hdisplay << "x" << mode.vdisplay
- << "@" << mode.vrefresh << "hz";
+ << '@' << mode.vrefresh << "hz";
modes << connector->modes[i];
}
@@ -272,7 +278,7 @@ QEglFSKmsScreen *QEglFSKmsDevice::screenForConnector(drmModeResPtr resources, dr
int height = modes[selected_mode].vdisplay;
int refresh = modes[selected_mode].vrefresh;
qCDebug(qLcEglfsKmsDebug) << "Selected mode" << selected_mode << ":" << width << "x" << height
- << "@" << refresh << "hz for output" << connectorName;
+ << '@' << refresh << "hz for output" << connectorName;
}
QEglFSKmsOutput output = {
@@ -284,6 +290,7 @@ QEglFSKmsScreen *QEglFSKmsDevice::screenForConnector(drmModeResPtr resources, dr
false,
drmModeGetCrtc(m_dri_fd, crtc_id),
modes,
+ connector->subpixel,
connectorProperty(connector, QByteArrayLiteral("DPMS"))
};
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp
index 227c8f9a62..60586f98a7 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp
@@ -52,15 +52,11 @@ public:
QEglFSKmsInterruptHandler(QEglFSKmsScreen *screen) : m_screen(screen) {
m_vtHandler = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->vtHandler();
connect(m_vtHandler, &QFbVtHandler::interrupted, this, &QEglFSKmsInterruptHandler::restoreVideoMode);
- connect(m_vtHandler, &QFbVtHandler::suspendRequested, this, &QEglFSKmsInterruptHandler::handleSuspendRequest);
+ connect(m_vtHandler, &QFbVtHandler::aboutToSuspend, this, &QEglFSKmsInterruptHandler::restoreVideoMode);
}
public slots:
void restoreVideoMode() { m_screen->restoreMode(); }
- void handleSuspendRequest() {
- m_screen->restoreMode();
- m_vtHandler->suspend();
- }
private:
QFbVtHandler *m_vtHandler;
@@ -321,6 +317,24 @@ qreal QEglFSKmsScreen::refreshRate() const
return refresh > 0 ? refresh : 60;
}
+QPlatformScreen::SubpixelAntialiasingType QEglFSKmsScreen::subpixelAntialiasingTypeHint() const
+{
+ switch (m_output.subpixel) {
+ default:
+ case DRM_MODE_SUBPIXEL_UNKNOWN:
+ case DRM_MODE_SUBPIXEL_NONE:
+ return Subpixel_None;
+ case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
+ return Subpixel_RGB;
+ case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
+ return Subpixel_BGR;
+ case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
+ return Subpixel_VRGB;
+ case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
+ return Subpixel_VBGR;
+ }
+}
+
QPlatformScreen::PowerState QEglFSKmsScreen::powerState() const
{
return m_powerState;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h
index 2ce8700478..7fd6ccaa31 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h
@@ -60,6 +60,7 @@ struct QEglFSKmsOutput
bool mode_set;
drmModeCrtcPtr saved_crtc;
QList<drmModeModeInfo> modes;
+ int subpixel;
drmModePropertyPtr dpms_prop;
};
@@ -104,6 +105,8 @@ public:
QEglFSKmsOutput &output() { return m_output; }
void restoreMode();
+ SubpixelAntialiasingType subpixelAntialiasingTypeHint() const Q_DECL_OVERRIDE;
+
QPlatformScreen::PowerState powerState() const Q_DECL_OVERRIDE;
void setPowerState(QPlatformScreen::PowerState state) Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.json b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.json
new file mode 100644
index 0000000000..169ba1eb02
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "eglfs_kms_egldevice" ]
+}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro
new file mode 100644
index 0000000000..2274c5b228
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro
@@ -0,0 +1,21 @@
+TARGET = qeglfs-kms-egldevice-integration
+
+PLUGIN_TYPE = egldeviceintegrations
+PLUGIN_CLASS_NAME = QEglFSKmsEglDeviceIntegrationPlugin
+load(qt_plugin)
+
+QT += core-private gui-private platformsupport-private eglfs_device_lib-private
+
+INCLUDEPATH += $$PWD/../..
+
+CONFIG += egl
+QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
+
+SOURCES += $$PWD/qeglfskmsegldevicemain.cpp \
+ $$PWD/qeglfskmsegldeviceintegration.cpp
+
+HEADERS += $$PWD/qeglfskmsegldeviceintegration.h
+
+OTHER_FILES += $$PWD/eglfs_kms_egldevice.json
+
+LIBS += -ldrm
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
new file mode 100644
index 0000000000..2f32bd73a3
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
@@ -0,0 +1,464 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeglfskmsegldeviceintegration.h"
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcEglfsKmsDebug, "qt.qpa.eglfs.kms")
+
+QEglFSKmsEglDeviceIntegration::QEglFSKmsEglDeviceIntegration()
+ : m_dri_fd(-1)
+ , m_egl_device(EGL_NO_DEVICE_EXT)
+ , m_egl_display(EGL_NO_DISPLAY)
+ , m_drm_connector(Q_NULLPTR)
+ , m_drm_encoder(Q_NULLPTR)
+ , m_drm_crtc(0)
+{
+ qCDebug(qLcEglfsKmsDebug, "New DRM/KMS on EGLDevice integration created");
+}
+
+void QEglFSKmsEglDeviceIntegration::platformInit()
+{
+ if (!query_egl_device())
+ qFatal("Could not set up EGL device!");
+
+ const char *deviceName = m_query_device_string(m_egl_device, EGL_DRM_DEVICE_FILE_EXT);
+ if (!deviceName)
+ qFatal("Failed to query device name from EGLDevice");
+
+ qCDebug(qLcEglfsKmsDebug, "Opening %s", deviceName);
+
+ m_dri_fd = drmOpen(deviceName, Q_NULLPTR);
+ if (m_dri_fd < 0)
+ qFatal("Could not open DRM device");
+
+ if (!setup_kms())
+ qFatal("Could not set up KMS on device %s!", m_device.constData());
+
+ qCDebug(qLcEglfsKmsDebug, "DRM/KMS initialized");
+}
+
+void QEglFSKmsEglDeviceIntegration::platformDestroy()
+{
+ if (qt_safe_close(m_dri_fd) == -1)
+ qErrnoWarning("Could not close DRM device");
+
+ m_dri_fd = -1;
+}
+
+EGLNativeDisplayType QEglFSKmsEglDeviceIntegration::platformDisplay() const
+{
+ return static_cast<EGLNativeDisplayType>(m_egl_device);
+}
+
+EGLDisplay QEglFSKmsEglDeviceIntegration::createDisplay(EGLNativeDisplayType nativeDisplay)
+{
+ qCDebug(qLcEglfsKmsDebug, "Creating display");
+
+ const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+
+ m_get_platform_display = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
+ m_has_egl_platform_device = extensions && strstr(extensions, "EGL_EXT_platform_device");
+
+ EGLDisplay display;
+
+ if (!m_has_egl_platform_device) {
+ qWarning("EGL_EXT_platform_device not available, falling back to legacy path!");
+ display = eglGetDisplay(nativeDisplay);
+ } else {
+ display = m_get_platform_display(EGL_PLATFORM_DEVICE_EXT, nativeDisplay, Q_NULLPTR);
+ }
+
+ if (display == EGL_NO_DISPLAY)
+ qFatal("Could not get EGL display");
+
+ EGLint major, minor;
+ if (!eglInitialize(display, &major, &minor))
+ qFatal("Could not initialize egl display");
+
+ if (!eglBindAPI(EGL_OPENGL_ES_API))
+ qFatal("Failed to bind EGL_OPENGL_ES_API\n");
+
+ return display;
+}
+
+QSizeF QEglFSKmsEglDeviceIntegration::physicalScreenSize() const
+{
+ return QSizeF(m_drm_connector->mmWidth, m_drm_connector->mmHeight);
+}
+
+QSize QEglFSKmsEglDeviceIntegration::screenSize() const
+{
+ return QSize(m_drm_mode.hdisplay, m_drm_mode.vdisplay);
+}
+
+int QEglFSKmsEglDeviceIntegration::screenDepth() const
+{
+ return 32;
+}
+
+QSurfaceFormat QEglFSKmsEglDeviceIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
+{
+ QSurfaceFormat format(inputFormat);
+ format.setRenderableType(QSurfaceFormat::OpenGLES);
+ format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
+ format.setRedBufferSize(8);
+ format.setGreenBufferSize(8);
+ format.setBlueBufferSize(8);
+ return format;
+}
+
+EGLint QEglFSKmsEglDeviceIntegration::surfaceType() const
+{
+ return EGL_STREAM_BIT_KHR;
+}
+
+class QEglJetsonTK1Window : public QEglFSWindow
+{
+public:
+ QEglJetsonTK1Window(QWindow *w, const QEglFSKmsEglDeviceIntegration *integration)
+ : QEglFSWindow(w)
+ , m_integration(integration)
+ , m_egl_stream(EGL_NO_STREAM_KHR)
+ { }
+
+ void invalidateSurface() Q_DECL_OVERRIDE;
+ void resetSurface() Q_DECL_OVERRIDE;
+
+ const QEglFSKmsEglDeviceIntegration *m_integration;
+ EGLStreamKHR m_egl_stream;
+ EGLint m_latency;
+};
+
+void QEglJetsonTK1Window::invalidateSurface()
+{
+ QEglFSWindow::invalidateSurface();
+ m_integration->m_destroy_stream(screen()->display(), m_egl_stream);
+}
+
+void QEglJetsonTK1Window::resetSurface()
+{
+ qCDebug(qLcEglfsKmsDebug, "Creating stream");
+
+ EGLDisplay display = screen()->display();
+ EGLOutputLayerEXT layer = EGL_NO_OUTPUT_LAYER_EXT;
+ EGLint count;
+
+ m_egl_stream = m_integration->m_create_stream(display, Q_NULLPTR);
+ if (m_egl_stream == EGL_NO_STREAM_KHR) {
+ qWarning("resetSurface: Couldn't create EGLStream for native window");
+ return;
+ }
+
+ qCDebug(qLcEglfsKmsDebug, "Created stream %p on display %p", m_egl_stream, display);
+
+ if (!m_integration->m_get_output_layers(display, Q_NULLPTR, Q_NULLPTR, 0, &count) || count == 0) {
+ qWarning("No output layers found");
+ return;
+ }
+
+ qCDebug(qLcEglfsKmsDebug, "Output has %d layers", count);
+
+ QVector<EGLOutputLayerEXT> layers;
+ layers.resize(count);
+ EGLint actualCount;
+ if (!m_integration->m_get_output_layers(display, Q_NULLPTR, layers.data(), count, &actualCount)) {
+ qWarning("Failed to get layers");
+ return;
+ }
+
+ for (int i = 0; i < actualCount; ++i) {
+ EGLAttrib id;
+ if (m_integration->m_query_output_layer_attrib(display, layers[i], EGL_DRM_CRTC_EXT, &id)) {
+ qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - crtc %d", i, layers[i], id);
+ if (id == EGLAttrib(m_integration->m_drm_crtc))
+ layer = layers[i];
+ } else if (m_integration->m_query_output_layer_attrib(display, layers[i], EGL_DRM_PLANE_EXT, &id)) {
+ // Not used yet, just for debugging.
+ qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - plane %d", i, layers[i], id);
+ } else {
+ qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - unknown", i, layers[i]);
+ }
+ }
+
+ QByteArray reqLayerIndex = qgetenv("QT_QPA_EGLFS_LAYER_INDEX");
+ if (!reqLayerIndex.isEmpty()) {
+ int idx = reqLayerIndex.toInt();
+ if (idx >= 0 && idx < layers.count())
+ layer = layers[idx];
+ }
+
+ if (layer == EGL_NO_OUTPUT_LAYER_EXT) {
+ qWarning("resetSurface: Couldn't get EGLOutputLayer for native window");
+ return;
+ }
+
+ qCDebug(qLcEglfsKmsDebug, "Using layer %p", layer);
+
+ if (!m_integration->m_stream_consumer_output(display, m_egl_stream, layer))
+ qWarning("resetSurface: Unable to connect stream");
+
+ m_config = QEglFSIntegration::chooseConfig(display, m_integration->surfaceFormatFor(window()->requestedFormat()));
+ m_format = q_glFormatFromConfig(display, m_config);
+ qCDebug(qLcEglfsKmsDebug) << "Stream producer format is" << m_format;
+
+ const int w = m_integration->screenSize().width();
+ const int h = m_integration->screenSize().height();
+ qCDebug(qLcEglfsKmsDebug, "Creating stream producer surface of size %dx%d", w, h);
+
+ const EGLint stream_producer_attribs[] = {
+ EGL_WIDTH, w,
+ EGL_HEIGHT, h,
+ EGL_NONE
+ };
+
+ m_surface = m_integration->m_create_stream_producer_surface(display, m_config, m_egl_stream, stream_producer_attribs);
+ if (m_surface == EGL_NO_SURFACE)
+ return;
+
+ qCDebug(qLcEglfsKmsDebug, "Created stream producer surface %p", m_surface);
+}
+
+QEglFSWindow *QEglFSKmsEglDeviceIntegration::createWindow(QWindow *window) const
+{
+ QEglJetsonTK1Window *eglWindow = new QEglJetsonTK1Window(window, this);
+
+ if (!const_cast<QEglFSKmsEglDeviceIntegration *>(this)->query_egl_extensions(eglWindow->screen()->display()))
+ qFatal("Required extensions missing!");
+
+ return eglWindow;
+}
+
+bool QEglFSKmsEglDeviceIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case QPlatformIntegration::ThreadedPixmaps:
+ case QPlatformIntegration::OpenGL:
+ case QPlatformIntegration::ThreadedOpenGL:
+ case QPlatformIntegration::BufferQueueingOpenGL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void QEglFSKmsEglDeviceIntegration::waitForVSync(QPlatformSurface *) const
+{
+ static bool mode_set = false;
+
+ if (!mode_set) {
+ mode_set = true;
+
+ drmModeCrtcPtr currentMode = drmModeGetCrtc(m_dri_fd, m_drm_crtc);
+ const bool alreadySet = currentMode
+ && currentMode->width == m_drm_mode.hdisplay
+ && currentMode->height == m_drm_mode.vdisplay;
+ if (currentMode)
+ drmModeFreeCrtc(currentMode);
+ if (alreadySet) {
+ qCDebug(qLcEglfsKmsDebug, "Mode already set");
+ return;
+ }
+
+ qCDebug(qLcEglfsKmsDebug, "Setting mode");
+ int ret = drmModeSetCrtc(m_dri_fd, m_drm_crtc,
+ -1, 0, 0,
+ &m_drm_connector->connector_id, 1,
+ const_cast<const drmModeModeInfoPtr>(&m_drm_mode));
+ if (ret)
+ qFatal("drmModeSetCrtc failed");
+ }
+}
+
+qreal QEglFSKmsEglDeviceIntegration::refreshRate() const
+{
+ quint32 refresh = m_drm_mode.vrefresh;
+ return refresh > 0 ? refresh : 60;
+}
+
+bool QEglFSKmsEglDeviceIntegration::supportsSurfacelessContexts() const
+{
+ // Returning false disables the usage of EGL_KHR_surfaceless_context even when the
+ // extension is available. This is just what we need since, at least with NVIDIA
+ // 352.00 making a null surface current with a context breaks.
+ return false;
+}
+
+bool QEglFSKmsEglDeviceIntegration::setup_kms()
+{
+ drmModeRes *resources;
+ drmModeConnector *connector;
+ drmModeEncoder *encoder;
+ quint32 crtc = 0;
+ int i;
+
+ resources = drmModeGetResources(m_dri_fd);
+ if (!resources) {
+ qWarning("drmModeGetResources failed");
+ return false;
+ }
+
+ for (i = 0; i < resources->count_connectors; i++) {
+ connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]);
+ if (!connector)
+ continue;
+
+ if (connector->connection == DRM_MODE_CONNECTED && connector->count_modes > 0)
+ break;
+
+ drmModeFreeConnector(connector);
+ }
+
+ if (i == resources->count_connectors) {
+ qWarning("No currently active connector found.");
+ return false;
+ }
+
+ qCDebug(qLcEglfsKmsDebug, "Using connector with type %d", connector->connector_type);
+
+ for (i = 0; i < resources->count_encoders; i++) {
+ encoder = drmModeGetEncoder(m_dri_fd, resources->encoders[i]);
+ if (!encoder)
+ continue;
+
+ if (encoder->encoder_id == connector->encoder_id)
+ break;
+
+ drmModeFreeEncoder(encoder);
+ }
+
+ for (int j = 0; j < resources->count_crtcs; j++) {
+ if ((encoder->possible_crtcs & (1 << j))) {
+ crtc = resources->crtcs[j];
+ break;
+ }
+ }
+
+ if (crtc == 0)
+ qFatal("No suitable CRTC available");
+
+ m_drm_connector = connector;
+ m_drm_encoder = encoder;
+ m_drm_mode = connector->modes[0];
+ m_drm_crtc = crtc;
+
+ qCDebug(qLcEglfsKmsDebug).noquote() << "Using crtc" << m_drm_crtc
+ << "with mode" << m_drm_mode.hdisplay << "x" << m_drm_mode.vdisplay
+ << "@" << m_drm_mode.vrefresh;
+
+ drmModeFreeResources(resources);
+
+ return true;
+}
+
+bool QEglFSKmsEglDeviceIntegration::query_egl_device()
+{
+ const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+ if (!extensions) {
+ qWarning("eglQueryString failed");
+ return false;
+ }
+
+ m_has_egl_device_base = strstr(extensions, "EGL_EXT_device_base");
+ m_query_devices = reinterpret_cast<PFNEGLQUERYDEVICESEXTPROC>(eglGetProcAddress("eglQueryDevicesEXT"));
+ m_query_device_string = reinterpret_cast<PFNEGLQUERYDEVICESTRINGEXTPROC>(eglGetProcAddress("eglQueryDeviceStringEXT"));
+
+ if (!m_has_egl_device_base || !m_query_devices || !m_query_device_string)
+ qFatal("EGL_EXT_device_base missing");
+
+ EGLint num_devices = 0;
+ if (m_query_devices(1, &m_egl_device, &num_devices) != EGL_TRUE) {
+ qWarning("eglQueryDevicesEXT failed: eglError: %x", eglGetError());
+ return false;
+ }
+
+ qCDebug(qLcEglfsKmsDebug, "Found %d EGL devices", num_devices);
+
+ if (num_devices < 1 || m_egl_device == EGL_NO_DEVICE_EXT) {
+ qWarning("eglQueryDevicesEXT could not find any EGL devices");
+ return false;
+ }
+
+ return true;
+}
+
+bool QEglFSKmsEglDeviceIntegration::query_egl_extensions(EGLDisplay display)
+{
+ if (!eglBindAPI(EGL_OPENGL_ES_API)) {
+ qWarning() << Q_FUNC_INFO << "failed to bind EGL_OPENGL_ES_API";
+ return false;
+ }
+
+ m_create_stream = reinterpret_cast<PFNEGLCREATESTREAMKHRPROC>(eglGetProcAddress("eglCreateStreamKHR"));
+ m_destroy_stream = reinterpret_cast<PFNEGLDESTROYSTREAMKHRPROC>(eglGetProcAddress("eglDestroyStreamKHR"));
+ m_stream_attrib = reinterpret_cast<PFNEGLSTREAMATTRIBKHRPROC>(eglGetProcAddress("eglStreamAttribKHR"));
+ m_query_stream = reinterpret_cast<PFNEGLQUERYSTREAMKHRPROC>(eglGetProcAddress("eglQueryStreamKHR"));
+ m_query_stream_u64 = reinterpret_cast<PFNEGLQUERYSTREAMU64KHRPROC>(eglGetProcAddress("eglQueryStreamu64KHR"));
+ m_create_stream_producer_surface = reinterpret_cast<PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC>(eglGetProcAddress("eglCreateStreamProducerSurfaceKHR"));
+ m_stream_consumer_output = reinterpret_cast<PFNEGLSTREAMCONSUMEROUTPUTEXTPROC>(eglGetProcAddress("eglStreamConsumerOutputEXT"));
+ m_get_output_layers = reinterpret_cast<PFNEGLGETOUTPUTLAYERSEXTPROC>(eglGetProcAddress("eglGetOutputLayersEXT"));
+ m_get_output_ports = reinterpret_cast<PFNEGLGETOUTPUTPORTSEXTPROC>(eglGetProcAddress("eglGetOutputPortsEXT"));
+ m_output_layer_attrib = reinterpret_cast<PFNEGLOUTPUTLAYERATTRIBEXTPROC>(eglGetProcAddress("eglOutputLayerAttribEXT"));
+ m_query_output_layer_attrib = reinterpret_cast<PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC>(eglGetProcAddress("eglQueryOutputLayerAttribEXT"));
+ m_query_output_layer_string = reinterpret_cast<PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC>(eglGetProcAddress("eglQueryOutputLayerStringEXT"));
+ m_query_output_port_attrib = reinterpret_cast<PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC>(eglGetProcAddress("eglQueryOutputPortAttribEXT"));
+ m_query_output_port_string = reinterpret_cast<PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC>(eglGetProcAddress("eglQueryOutputPortStringEXT"));
+ m_get_stream_file_descriptor = reinterpret_cast<PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC>(eglGetProcAddress("eglGetStreamFileDescriptorKHR"));
+ m_create_stream_from_file_descriptor = reinterpret_cast<PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC>(eglGetProcAddress("eglCreateStreamFromFileDescriptorKHR"));
+ m_stream_consumer_gltexture = reinterpret_cast<PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC>(eglGetProcAddress("eglStreamConsumerGLTextureExternalKHR"));
+ m_stream_consumer_acquire = reinterpret_cast<PFNEGLSTREAMCONSUMERACQUIREKHRPROC>(eglGetProcAddress("eglStreamConsumerAcquireKHR"));
+
+ const char *extensions = eglQueryString(display, EGL_EXTENSIONS);
+ if (!extensions) {
+ qWarning() << Q_FUNC_INFO << "eglQueryString failed";
+ return false;
+ }
+
+ m_has_egl_stream = strstr(extensions, "EGL_KHR_stream");
+ m_has_egl_stream_producer_eglsurface = strstr(extensions, "EGL_KHR_stream_producer_eglsurface");
+ m_has_egl_stream_consumer_egloutput = strstr(extensions, "EGL_EXT_stream_consumer_egloutput");
+ m_has_egl_output_drm = strstr(extensions, "EGL_EXT_output_drm");
+ m_has_egl_output_base = strstr(extensions, "EGL_EXT_output_base");
+ m_has_egl_stream_cross_process_fd = strstr(extensions, "EGL_KHR_stream_cross_process_fd");
+ m_has_egl_stream_consumer_gltexture = strstr(extensions, "EGL_KHR_stream_consumer_gltexture");
+
+ return m_has_egl_output_base &&
+ m_has_egl_output_drm &&
+ m_has_egl_stream &&
+ m_has_egl_stream_producer_eglsurface &&
+ m_has_egl_stream_consumer_egloutput;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
new file mode 100644
index 0000000000..c6132354a8
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEGLFSKMSEGLDEVICEINTEGRATION_H
+#define QEGLFSKMSEGLDEVICEINTEGRATION_H
+
+#include "qeglfsdeviceintegration.h"
+#include "qeglfswindow.h"
+#include "qeglfsintegration.h"
+
+#include <QtPlatformSupport/private/qdevicediscovery_p.h>
+#include <QtPlatformSupport/private/qeglconvenience_p.h>
+#include <QtCore/private/qcore_unix_p.h>
+#include <QtCore/QScopedPointer>
+#include <QtGui/qpa/qplatformwindow.h>
+#include <QtGui/qguiapplication.h>
+#include <QDebug>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSKmsEglDeviceIntegration : public QEGLDeviceIntegration
+{
+public:
+ QEglFSKmsEglDeviceIntegration();
+
+ void platformInit() Q_DECL_OVERRIDE;
+ void platformDestroy() Q_DECL_OVERRIDE;
+ EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE;
+ EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay) Q_DECL_OVERRIDE;
+ QSizeF physicalScreenSize() const Q_DECL_OVERRIDE;
+ QSize screenSize() const Q_DECL_OVERRIDE;
+ int screenDepth() const Q_DECL_OVERRIDE;
+ qreal refreshRate() const Q_DECL_OVERRIDE;
+ QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const Q_DECL_OVERRIDE;
+ EGLint surfaceType() const Q_DECL_OVERRIDE;
+ QEglFSWindow *createWindow(QWindow *window) const Q_DECL_OVERRIDE;
+ bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
+ void waitForVSync(QPlatformSurface *surface) const Q_DECL_OVERRIDE;
+ bool supportsSurfacelessContexts() const Q_DECL_OVERRIDE;
+
+ bool setup_kms();
+
+ bool query_egl_device();
+ bool query_egl_extensions(EGLDisplay display);
+
+ // device bits
+ QByteArray m_device;
+ int m_dri_fd;
+ EGLDeviceEXT m_egl_device;
+ EGLDisplay m_egl_display;
+
+ // KMS bits
+ drmModeConnector *m_drm_connector;
+ drmModeEncoder *m_drm_encoder;
+ drmModeModeInfo m_drm_mode;
+ quint32 m_drm_crtc;
+
+ // EGLStream infrastructure
+ PFNEGLGETPLATFORMDISPLAYEXTPROC m_get_platform_display;
+ bool m_has_egl_platform_device;
+
+ PFNEGLQUERYDEVICESEXTPROC m_query_devices;
+ PFNEGLQUERYDEVICESTRINGEXTPROC m_query_device_string;
+ bool m_has_egl_device_base;
+
+ PFNEGLCREATESTREAMKHRPROC m_create_stream;
+ PFNEGLDESTROYSTREAMKHRPROC m_destroy_stream;
+ PFNEGLSTREAMATTRIBKHRPROC m_stream_attrib;
+ PFNEGLQUERYSTREAMKHRPROC m_query_stream;
+ PFNEGLQUERYSTREAMU64KHRPROC m_query_stream_u64;
+ bool m_has_egl_stream;
+
+ PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC m_create_stream_producer_surface;
+ bool m_has_egl_stream_producer_eglsurface;
+
+ PFNEGLSTREAMCONSUMEROUTPUTEXTPROC m_stream_consumer_output;
+ bool m_has_egl_stream_consumer_egloutput;
+
+ bool m_has_egl_output_drm;
+
+ PFNEGLGETOUTPUTLAYERSEXTPROC m_get_output_layers;
+ PFNEGLGETOUTPUTPORTSEXTPROC m_get_output_ports;
+ PFNEGLOUTPUTLAYERATTRIBEXTPROC m_output_layer_attrib;
+ PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC m_query_output_layer_attrib;
+ PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC m_query_output_layer_string;
+ PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC m_query_output_port_attrib;
+ PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC m_query_output_port_string;
+ bool m_has_egl_output_base;
+
+ PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC m_get_stream_file_descriptor;
+ PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC m_create_stream_from_file_descriptor;
+ bool m_has_egl_stream_cross_process_fd;
+
+ PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC m_stream_consumer_gltexture;
+ PFNEGLSTREAMCONSUMERACQUIREKHRPROC m_stream_consumer_acquire;
+ bool m_has_egl_stream_consumer_gltexture;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
new file mode 100644
index 0000000000..f987ae38a6
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the qmake spec of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeglfskmsegldeviceintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSKmsEglDeviceIntegrationPlugin : public QEGLDeviceIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QEGLDeviceIntegrationFactoryInterface_iid FILE "eglfs_kms_egldevice.json")
+
+public:
+ QEGLDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSKmsEglDeviceIntegration; }
+};
+
+QT_END_NAMESPACE
+
+#include "qeglfskmsegldevicemain.moc"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp
index 455d78035a..43decdf849 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.cpp
@@ -32,7 +32,6 @@
****************************************************************************/
#include "qeglfsmaliintegration.h"
-#include <EGL/fbdev_window.h>
#include <unistd.h>
#include <fcntl.h>
@@ -43,6 +42,11 @@
QT_BEGIN_NAMESPACE
+struct fbdev_window {
+ unsigned short width;
+ unsigned short height;
+};
+
void QEglFSMaliIntegration::platformInit()
{
// Keep the non-overridden base class functions based on fb0 working.
diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp
index e2223aba43..6fcdae7ad2 100644
--- a/src/plugins/platforms/eglfs/qeglfscontext.cpp
+++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp
@@ -44,7 +44,8 @@ QT_BEGIN_NAMESPACE
QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display,
EGLConfig *config, const QVariant &nativeHandle)
- : QEGLPlatformContext(format, share, display, config, nativeHandle),
+ : QEGLPlatformContext(format, share, display, config, nativeHandle,
+ qt_egl_device_integration()->supportsSurfacelessContexts() ? Flags(0) : QEGLPlatformContext::NoSurfaceless),
m_tempWindow(0)
{
}
diff --git a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp
index d27c949c8d..0c2aa7ad61 100644
--- a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp
@@ -34,6 +34,7 @@
#include "qeglfsdeviceintegration.h"
#include "qeglfsintegration.h"
#include "qeglfscursor.h"
+#include "qeglfswindow.h"
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QGuiApplication>
#include <private/qguiapplication_p.h>
@@ -175,6 +176,11 @@ EGLNativeDisplayType QEGLDeviceIntegration::platformDisplay() const
return EGL_DEFAULT_DISPLAY;
}
+EGLDisplay QEGLDeviceIntegration::createDisplay(EGLNativeDisplayType nativeDisplay)
+{
+ return eglGetDisplay(nativeDisplay);
+}
+
bool QEGLDeviceIntegration::usesDefaultScreen()
{
return true;
@@ -238,6 +244,11 @@ qreal QEGLDeviceIntegration::refreshRate() const
return q_refreshRateFromFb(framebuffer);
}
+EGLint QEGLDeviceIntegration::surfaceType() const
+{
+ return EGL_WINDOW_BIT;
+}
+
QSurfaceFormat QEGLDeviceIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
{
QSurfaceFormat format = inputFormat;
@@ -257,6 +268,11 @@ bool QEGLDeviceIntegration::filterConfig(EGLDisplay, EGLConfig) const
return true;
}
+QEglFSWindow *QEGLDeviceIntegration::createWindow(QWindow *window) const
+{
+ return new QEglFSWindow(window);
+}
+
EGLNativeWindowType QEGLDeviceIntegration::createNativeWindow(QPlatformWindow *platformWindow,
const QSize &size,
const QSurfaceFormat &format)
@@ -313,4 +329,9 @@ bool QEGLDeviceIntegration::supportsPBuffers() const
return true;
}
+bool QEGLDeviceIntegration::supportsSurfacelessContexts() const
+{
+ return true;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h
index 260fc313f7..d91d67de16 100644
--- a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h
+++ b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.h
@@ -56,6 +56,7 @@
QT_BEGIN_NAMESPACE
class QPlatformSurface;
+class QEglFSWindow;
#define QEGLDeviceIntegrationFactoryInterface_iid "org.qt-project.qt.qpa.egl.QEGLDeviceIntegrationFactoryInterface.5.5"
@@ -67,6 +68,7 @@ public:
virtual void platformInit();
virtual void platformDestroy();
virtual EGLNativeDisplayType platformDisplay() const;
+ virtual EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay);
virtual bool usesDefaultScreen();
virtual void screenInit();
virtual void screenDestroy();
@@ -79,6 +81,8 @@ public:
virtual QImage::Format screenFormat() const;
virtual qreal refreshRate() const;
virtual QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const;
+ virtual EGLint surfaceType() const;
+ virtual QEglFSWindow *createWindow(QWindow *window) const;
virtual EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow,
const QSize &size,
const QSurfaceFormat &format);
@@ -92,6 +96,7 @@ public:
virtual QByteArray fbDeviceName() const;
virtual int framebufferIndex() const;
virtual bool supportsPBuffers() const;
+ virtual bool supportsSurfacelessContexts() const;
};
class Q_EGLFS_EXPORT QEGLDeviceIntegrationPlugin : public QObject
diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
index f0946b9b64..2df06caa6b 100644
--- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
@@ -117,7 +117,7 @@ void QEglFSIntegration::initialize()
{
qt_egl_device_integration()->platformInit();
- m_display = eglGetDisplay(nativeDisplay());
+ m_display = qt_egl_device_integration()->createDisplay(nativeDisplay());
if (m_display == EGL_NO_DISPLAY)
qFatal("Could not open egl display");
@@ -179,7 +179,7 @@ QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *wi
QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const
{
QWindowSystemInterface::flushWindowSystemEvents();
- QEglFSWindow *w = new QEglFSWindow(window);
+ QEglFSWindow *w = qt_egl_device_integration()->createWindow(window);
w->create();
if (window->type() != Qt::ToolTip)
w->requestActivateWindow();
@@ -213,10 +213,14 @@ QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOf
{
EGLDisplay dpy = surface->screen() ? static_cast<QEglFSScreen *>(surface->screen()->handle())->display() : display();
QSurfaceFormat fmt = qt_egl_device_integration()->surfaceFormatFor(surface->requestedFormat());
- if (qt_egl_device_integration()->supportsPBuffers())
- return new QEGLPbuffer(dpy, fmt, surface);
- else
+ if (qt_egl_device_integration()->supportsPBuffers()) {
+ QEGLPlatformContext::Flags flags = 0;
+ if (!qt_egl_device_integration()->supportsSurfacelessContexts())
+ flags |= QEGLPlatformContext::NoSurfaceless;
+ return new QEGLPbuffer(dpy, fmt, surface, flags);
+ } else {
return new QEglFSOffscreenWindow(dpy, fmt, surface);
+ }
// Never return null. Multiple QWindows are not supported by this plugin.
}
@@ -433,6 +437,7 @@ EGLConfig QEglFSIntegration::chooseConfig(EGLDisplay display, const QSurfaceForm
};
Chooser chooser(display);
+ chooser.setSurfaceType(qt_egl_device_integration()->surfaceType());
chooser.setSurfaceFormat(format);
return chooser.chooseConfig();
}
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp
index c3b9dd6ef0..8301be8c17 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp
@@ -51,7 +51,7 @@ QEglFSWindow::QEglFSWindow(QWindow *w)
m_backingStore(0),
m_raster(false),
m_winId(0),
- m_surface(0),
+ m_surface(EGL_NO_SURFACE),
m_window(0),
m_flags(0)
{
@@ -120,13 +120,14 @@ void QEglFSWindow::create()
setGeometry(QRect()); // will become fullscreen
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
- EGLDisplay display = static_cast<QEglFSScreen *>(screen)->display();
- QSurfaceFormat platformFormat = qt_egl_device_integration()->surfaceFormatFor(window()->requestedFormat());
- m_config = QEglFSIntegration::chooseConfig(display, platformFormat);
- m_format = q_glFormatFromConfig(display, m_config, platformFormat);
-
resetSurface();
+ if (m_surface == EGL_NO_SURFACE) {
+ EGLint error = eglGetError();
+ eglTerminate(screen->display());
+ qFatal("EGL Error : Could not create the egl surface: error = 0x%x\n", error);
+ }
+
screen->setPrimarySurface(m_surface);
if (isRaster()) {
@@ -158,15 +159,10 @@ void QEglFSWindow::destroy()
QOpenGLCompositor::instance()->removeWindow(this);
}
-// The virtual functions resetSurface and invalidateSurface may get overridden
-// in derived classes, for example in the Android port, to perform the native
-// window and surface creation differently.
-
void QEglFSWindow::invalidateSurface()
{
if (m_surface != EGL_NO_SURFACE) {
- EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display();
- eglDestroySurface(display, m_surface);
+ eglDestroySurface(screen()->display(), m_surface);
m_surface = EGL_NO_SURFACE;
}
qt_egl_device_integration()->destroyNativeWindow(m_window);
@@ -175,15 +171,13 @@ void QEglFSWindow::invalidateSurface()
void QEglFSWindow::resetSurface()
{
- QEglFSScreen *nativeScreen = static_cast<QEglFSScreen *>(screen());
- EGLDisplay display = nativeScreen->display();
- m_window = qt_egl_device_integration()->createNativeWindow(this, nativeScreen->geometry().size(), m_format);
+ EGLDisplay display = screen()->display();
+ QSurfaceFormat platformFormat = qt_egl_device_integration()->surfaceFormatFor(window()->requestedFormat());
+
+ m_config = QEglFSIntegration::chooseConfig(display, platformFormat);
+ m_format = q_glFormatFromConfig(display, m_config, platformFormat);
+ m_window = qt_egl_device_integration()->createNativeWindow(this, screen()->geometry().size(), m_format);
m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL);
- if (m_surface == EGL_NO_SURFACE) {
- EGLint error = eglGetError();
- eglTerminate(display);
- qFatal("EGL Error : Could not create the egl surface: error = 0x%x\n", error);
- }
}
void QEglFSWindow::setVisible(bool visible)
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h
index 53b9e18dc1..806b21de0a 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.h
+++ b/src/plugins/platforms/eglfs/qeglfswindow.h
@@ -89,7 +89,7 @@ public:
const QPlatformTextureList *textures() const Q_DECL_OVERRIDE;
void endCompositing() Q_DECL_OVERRIDE;
-private:
+protected:
QOpenGLCompositorBackingStore *m_backingStore;
bool m_raster;
WId m_winId;
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/plugins/platforms/ios/qioseventdispatcher.h
index fdaa7e68fe..e8ea1cc28b 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.h
+++ b/src/plugins/platforms/ios/qioseventdispatcher.h
@@ -46,6 +46,7 @@ public:
explicit QIOSEventDispatcher(QObject *parent = 0);
bool processEvents(QEventLoop::ProcessEventsFlags flags) Q_DECL_OVERRIDE;
+ bool processPostedEvents() Q_DECL_OVERRIDE;
void handleRunLoopExit(CFRunLoopActivity activity);
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm
index bd4b8778ed..0e9f176487 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.mm
+++ b/src/plugins/platforms/ios/qioseventdispatcher.mm
@@ -39,6 +39,8 @@
#include <QtCore/private/qcoreapplication_p.h>
#include <QtCore/private/qthread_p.h>
+#include <qpa/qwindowsysteminterface.h>
+
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <Foundation/NSProcessInfo.h>
@@ -461,6 +463,25 @@ bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoo
return processedEvents;
}
+/*!
+ Override of the CoreFoundation posted events runloop source callback
+ so that we can send window system (QPA) events in addition to sending
+ normal Qt events.
+*/
+bool QIOSEventDispatcher::processPostedEvents()
+{
+ // Don't send window system events if the base CF dispatcher has determined
+ // that events should not be sent for this pass of the runloop source.
+ if (!QEventDispatcherCoreFoundation::processPostedEvents())
+ return false;
+
+ qEventDispatcherDebug() << "Sending window system events for " << m_processEvents.flags; qIndent();
+ QWindowSystemInterface::sendWindowSystemEvents(m_processEvents.flags);
+ qUnIndent();
+
+ return true;
+}
+
void QIOSEventDispatcher::handleRunLoopExit(CFRunLoopActivity activity)
{
Q_UNUSED(activity);
diff --git a/src/plugins/platforms/ios/qiosmenu.h b/src/plugins/platforms/ios/qiosmenu.h
index 4fa0416df7..ec23b55507 100644
--- a/src/plugins/platforms/ios/qiosmenu.h
+++ b/src/plugins/platforms/ios/qiosmenu.h
@@ -62,7 +62,7 @@ public:
void setRole(MenuRole role) Q_DECL_OVERRIDE;
void setCheckable(bool) Q_DECL_OVERRIDE {}
void setChecked(bool) Q_DECL_OVERRIDE {}
- void setShortcut(const QKeySequence&) Q_DECL_OVERRIDE {}
+ void setShortcut(const QKeySequence&) Q_DECL_OVERRIDE;
void setEnabled(bool enabled) Q_DECL_OVERRIDE;
void setIconSize(int) Q_DECL_OVERRIDE {}
@@ -73,6 +73,7 @@ public:
bool m_enabled;
bool m_separator;
QIOSMenu *m_menu;
+ QKeySequence m_shortcut;
private:
QString removeMnemonics(const QString &original);
@@ -134,6 +135,7 @@ private:
void toggleShowUsingUIMenuController(bool show);
void toggleShowUsingUIPickerView(bool show);
QIOSMenuItemList visibleMenuItems() const;
+ QIOSMenuItemList filterFirstResponderActions(const QIOSMenuItemList &menuItems);
void repositionMenu();
};
diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm
index 045d39e328..7aea3729fd 100644
--- a/src/plugins/platforms/ios/qiosmenu.mm
+++ b/src/plugins/platforms/ios/qiosmenu.mm
@@ -277,6 +277,11 @@ void QIOSMenuItem::setRole(QPlatformMenuItem::MenuRole role)
m_role = role;
}
+void QIOSMenuItem::setShortcut(const QKeySequence &sequence)
+{
+ m_shortcut = sequence;
+}
+
void QIOSMenuItem::setEnabled(bool enabled)
{
m_enabled = enabled;
@@ -364,7 +369,7 @@ void QIOSMenu::syncMenuItem(QPlatformMenuItem *)
switch (m_effectiveMenuType) {
case EditMenu:
- [m_menuController setVisibleMenuItems:visibleMenuItems()];
+ [m_menuController setVisibleMenuItems:filterFirstResponderActions(visibleMenuItems())];
break;
default:
[m_pickerView setVisibleMenuItems:visibleMenuItems() selectItem:m_targetItem];
@@ -469,7 +474,7 @@ void QIOSMenu::toggleShowUsingUIMenuController(bool show)
{
if (show) {
Q_ASSERT(!m_menuController);
- m_menuController = [[QUIMenuController alloc] initWithVisibleMenuItems:visibleMenuItems()];
+ m_menuController = [[QUIMenuController alloc] initWithVisibleMenuItems:filterFirstResponderActions(visibleMenuItems())];
repositionMenu();
connect(qGuiApp->inputMethod(), &QInputMethod::keyboardRectangleChanged, this, &QIOSMenu::repositionMenu);
} else {
@@ -542,6 +547,36 @@ QIOSMenuItemList QIOSMenu::visibleMenuItems() const
return visibleMenuItems;
}
+QIOSMenuItemList QIOSMenu::filterFirstResponderActions(const QIOSMenuItemList &menuItems)
+{
+ // UIResponderStandardEditActions found in first responder will be prepended to the edit
+ // menu automatically (or e.g made available as buttons on the virtual keyboard). So we
+ // filter them out to avoid duplicates, and let first responder handle the actions instead.
+ // In case of QIOSTextResponder, edit actions will be converted to key events that ends up
+ // triggering the shortcuts of the filtered menu items.
+ QIOSMenuItemList filteredMenuItems;
+ UIResponder *responder = [UIResponder currentFirstResponder];
+
+ for (int i = 0; i < menuItems.count(); ++i) {
+ QIOSMenuItem *menuItem = menuItems.at(i);
+ QKeySequence shortcut = menuItem->m_shortcut;
+ if ((shortcut == QKeySequence::Cut && [responder canPerformAction:@selector(cut:) withSender:nil])
+ || (shortcut == QKeySequence::Copy && [responder canPerformAction:@selector(copy:) withSender:nil])
+ || (shortcut == QKeySequence::Paste && [responder canPerformAction:@selector(paste:) withSender:nil])
+ || (shortcut == QKeySequence::Delete && [responder canPerformAction:@selector(delete:) withSender:nil])
+ || (shortcut == QKeySequence::SelectAll && [responder canPerformAction:@selector(selectAll:) withSender:nil])
+ || (shortcut == QKeySequence::Undo && [responder canPerformAction:@selector(undo:) withSender:nil])
+ || (shortcut == QKeySequence::Redo && [responder canPerformAction:@selector(redo:) withSender:nil])
+ || (shortcut == QKeySequence::Bold && [responder canPerformAction:@selector(toggleBoldface:) withSender:nil])
+ || (shortcut == QKeySequence::Italic && [responder canPerformAction:@selector(toggleItalics:) withSender:nil])
+ || (shortcut == QKeySequence::Underline && [responder canPerformAction:@selector(toggleUnderline:) withSender:nil])) {
+ continue;
+ }
+ filteredMenuItems.append(menuItem);
+ }
+ return filteredMenuItems;
+}
+
void QIOSMenu::repositionMenu()
{
switch (m_effectiveMenuType) {
diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index e4917593db..b95be7a883 100644
--- a/src/plugins/platforms/ios/qiostextresponder.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -231,6 +231,9 @@
if (UIView *accessoryView = static_cast<UIView *>(platformData.value(kImePlatformDataInputAccessoryView).value<void *>()))
self.inputAccessoryView = [[[WrapperView alloc] initWithView:accessoryView] autorelease];
+ self.undoManager.groupsByEvent = NO;
+ [self rebuildUndoStack];
+
return self;
}
@@ -346,44 +349,183 @@
- (void)sendKeyPressRelease:(Qt::Key)key modifiers:(Qt::KeyboardModifiers)modifiers
{
- QKeyEvent press(QEvent::KeyPress, key, modifiers);
- QKeyEvent release(QEvent::KeyRelease, key, modifiers);
- [self sendEventToFocusObject:press];
- [self sendEventToFocusObject:release];
+ QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyPress, key, modifiers);
+ QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyRelease, key, modifiers);
+}
+
+#ifndef QT_NO_SHORTCUT
+
+- (void)sendShortcut:(QKeySequence::StandardKey)standardKey
+{
+ const int keys = QKeySequence(standardKey)[0];
+ Qt::Key key = Qt::Key(keys & 0x0000FFFF);
+ Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(keys & 0xFFFF0000);
+ [self sendKeyPressRelease:key modifiers:modifiers];
}
- (void)cut:(id)sender
{
Q_UNUSED(sender);
- [self sendKeyPressRelease:Qt::Key_X modifiers:Qt::ControlModifier];
+ [self sendShortcut:QKeySequence::Cut];
}
- (void)copy:(id)sender
{
Q_UNUSED(sender);
- [self sendKeyPressRelease:Qt::Key_C modifiers:Qt::ControlModifier];
+ [self sendShortcut:QKeySequence::Copy];
}
- (void)paste:(id)sender
{
Q_UNUSED(sender);
- [self sendKeyPressRelease:Qt::Key_V modifiers:Qt::ControlModifier];
+ [self sendShortcut:QKeySequence::Paste];
}
- (void)selectAll:(id)sender
{
Q_UNUSED(sender);
- [self sendKeyPressRelease:Qt::Key_A modifiers:Qt::ControlModifier];
+ [self sendShortcut:QKeySequence::SelectAll];
}
- (void)delete:(id)sender
{
Q_UNUSED(sender);
- [self sendKeyPressRelease:Qt::Key_Delete modifiers:Qt::ControlModifier];
+ [self sendShortcut:QKeySequence::Delete];
+}
+
+- (void)toggleBoldface:(id)sender
+{
+ Q_UNUSED(sender);
+ [self sendShortcut:QKeySequence::Bold];
+}
+
+- (void)toggleItalics:(id)sender
+{
+ Q_UNUSED(sender);
+ [self sendShortcut:QKeySequence::Italic];
+}
+
+- (void)toggleUnderline:(id)sender
+{
+ Q_UNUSED(sender);
+ [self sendShortcut:QKeySequence::Underline];
+}
+
+// -------------------------------------------------------------------------
+
+- (void)undo
+{
+ [self sendShortcut:QKeySequence::Undo];
+ [self rebuildUndoStack];
+}
+
+- (void)redo
+{
+ [self sendShortcut:QKeySequence::Redo];
+ [self rebuildUndoStack];
+}
+
+- (void)registerRedo
+{
+ NSUndoManager *undoMgr = self.undoManager;
+ [undoMgr beginUndoGrouping];
+ [undoMgr registerUndoWithTarget:self selector:@selector(redo) object:nil];
+ [undoMgr endUndoGrouping];
+}
+
+- (void)rebuildUndoStack
+{
+ dispatch_async(dispatch_get_main_queue (), ^{
+ // Register dummy undo/redo operations to enable Cmd-Z and Cmd-Shift-Z
+ // Ensure we do this outside any undo/redo callback since NSUndoManager
+ // will treat registerUndoWithTarget as registering a redo when called
+ // from within a undo callback.
+ NSUndoManager *undoMgr = self.undoManager;
+ [undoMgr removeAllActions];
+ [undoMgr beginUndoGrouping];
+ [undoMgr registerUndoWithTarget:self selector:@selector(undo) object:nil];
+ [undoMgr endUndoGrouping];
+
+ // Schedule an operation that we immediately pop off to be able to schedule a redo
+ [undoMgr beginUndoGrouping];
+ [undoMgr registerUndoWithTarget:self selector:@selector(registerRedo) object:nil];
+ [undoMgr endUndoGrouping];
+ [undoMgr undo];
+
+ // Note that, perhaps because of a bug in UIKit, the buttons on the shortcuts bar ends up
+ // disabled if a undo/redo callback doesn't lead to a [UITextInputDelegate textDidChange].
+ // And we only call that method if Qt made changes to the text. The effect is that the buttons
+ // become disabled when there is nothing more to undo (Qt didn't change anything upon receiving
+ // an undo request). This seems to be OK behavior, so we let it stay like that unless it shows
+ // to cause problems.
+ });
}
// -------------------------------------------------------------------------
+- (void)keyCommandTriggered:(UIKeyCommand *)keyCommand
+{
+ Qt::Key key = Qt::Key_unknown;
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+
+ if (keyCommand.input == UIKeyInputLeftArrow)
+ key = Qt::Key_Left;
+ else if (keyCommand.input == UIKeyInputRightArrow)
+ key = Qt::Key_Right;
+ else if (keyCommand.input == UIKeyInputUpArrow)
+ key = Qt::Key_Up;
+ else if (keyCommand.input == UIKeyInputDownArrow)
+ key = Qt::Key_Down;
+ else
+ Q_UNREACHABLE();
+
+ if (keyCommand.modifierFlags & UIKeyModifierAlternate)
+ modifiers |= Qt::AltModifier;
+ if (keyCommand.modifierFlags & UIKeyModifierShift)
+ modifiers |= Qt::ShiftModifier;
+ if (keyCommand.modifierFlags & UIKeyModifierCommand)
+ modifiers |= Qt::ControlModifier;
+
+ [self sendKeyPressRelease:key modifiers:modifiers];
+}
+
+- (void)addKeyCommandsToArray:(NSMutableArray *)array key:(NSString *)key
+{
+ SEL s = @selector(keyCommandTriggered:);
+ [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:0 action:s]];
+ [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierShift action:s]];
+ [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierAlternate action:s]];
+ [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierAlternate|UIKeyModifierShift action:s]];
+ [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierCommand action:s]];
+ [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierCommand|UIKeyModifierShift action:s]];
+}
+
+- (NSArray *)keyCommands
+{
+ // Since keyCommands is called for every key
+ // press/release, we cache the result
+ static dispatch_once_t once;
+ static NSMutableArray *array;
+
+ dispatch_once(&once, ^{
+ // We let Qt move the cursor around when the arrow keys are being used. This
+ // is normally implemented through UITextInput, but since IM in Qt have poor
+ // support for moving the cursor vertically, and even less support for selecting
+ // text across multiple paragraphs, we do this through key events.
+ array = [NSMutableArray new];
+ [self addKeyCommandsToArray:array key:UIKeyInputUpArrow];
+ [self addKeyCommandsToArray:array key:UIKeyInputDownArrow];
+ [self addKeyCommandsToArray:array key:UIKeyInputLeftArrow];
+ [self addKeyCommandsToArray:array key:UIKeyInputRightArrow];
+ });
+
+ return array;
+}
+
+#endif // QT_NO_SHORTCUT
+
+// -------------------------------------------------------------------------
+
- (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties
{
// As documented, we should not report textWillChange/textDidChange unless the text
@@ -540,7 +682,17 @@
- (UITextPosition *)positionFromPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction offset:(NSInteger)offset
{
int p = static_cast<QUITextPosition *>(position).index;
- return [QUITextPosition positionWithIndex:(direction == UITextLayoutDirectionRight ? p + offset : p - offset)];
+
+ switch (direction) {
+ case UITextLayoutDirectionLeft:
+ return [QUITextPosition positionWithIndex:p - offset];
+ case UITextLayoutDirectionRight:
+ return [QUITextPosition positionWithIndex:p + offset];
+ default:
+ // Qt doesn't support getting the position above or below the current position, so
+ // for those cases we just return the current position, making it a no-op.
+ return position;
+ }
}
- (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection:(UITextLayoutDirection)direction
@@ -608,6 +760,15 @@
return toCGRect(startRect.united(endRect));
}
+- (NSArray *)selectionRectsForRange:(UITextRange *)range
+{
+ Q_UNUSED(range);
+ // This method is supposed to return a rectangle for each line with selection. Since we don't
+ // expose an API in Qt/IM for getting this information, and since we never seems to be getting
+ // a call from UIKit for this, we return an empty array until a need arise.
+ return [[NSArray new] autorelease];
+}
+
- (CGRect)caretRectForPosition:(UITextPosition *)position
{
Q_UNUSED(position);
@@ -734,10 +895,10 @@
- (void)deleteBackward
{
- // Since we're posting im events directly to the focus object, we should do the
- // same for key events. Otherwise they might end up in a different place or out
- // of sync with im events.
+ // UITextInput selects the text to be deleted before calling this method. To avoid
+ // drawing the selection, we flush after posting the key press/release.
[self sendKeyPressRelease:Qt::Key_Backspace modifiers:Qt::NoModifier];
+ QWindowSystemInterface::flushWindowSystemEvents();
}
@end
diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm
index edeabf66dc..bc40069670 100644
--- a/src/plugins/platforms/ios/qiostheme.mm
+++ b/src/plugins/platforms/ios/qiostheme.mm
@@ -107,6 +107,8 @@ QVariant QIOSTheme::themeHint(ThemeHint hint) const
switch (hint) {
case QPlatformTheme::StyleNames:
return QStringList(QStringLiteral("fusion"));
+ case KeyboardScheme:
+ return QVariant(int(MacKeyboardScheme));
default:
return QPlatformTheme::themeHint(hint);
}
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
index 67b33ce235..94d894bba7 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.mm
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -185,7 +185,14 @@
- (void)setFrame:(CGRect)newFrame
{
- [super setFrame:CGRectMake(0, 0, CGRectGetWidth(newFrame), CGRectGetHeight(self.window.bounds))];
+ Q_UNUSED(newFrame);
+ Q_ASSERT(!self.window || self.window.rootViewController.view == self);
+
+ // When presenting view controllers our view may be temporarily reparented into a UITransitionView
+ // instead of the UIWindow, and the UITransitionView may have a transform set, so we need to do a
+ // mapping even if we still expect to always be the root view-controller.
+ CGRect transformedWindowBounds = [self.superview convertRect:self.window.bounds fromView:self.window];
+ [super setFrame:transformedWindowBounds];
}
- (void)setBounds:(CGRect)newBounds
diff --git a/src/plugins/platforms/offscreen/qoffscreencommon.cpp b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
index 11977fc6ed..31d7397f6f 100644
--- a/src/plugins/platforms/offscreen/qoffscreencommon.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
@@ -75,13 +75,13 @@ public:
QOffscreenScreen::windowContainingCursor = containing ? containing->handle() : 0;
}
-
+#ifndef QT_NO_CURSOR
void changeCursor(QCursor *windowCursor, QWindow *window) Q_DECL_OVERRIDE
{
Q_UNUSED(windowCursor);
Q_UNUSED(window);
}
-
+#endif
private:
QPoint m_pos;
};
diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
index 392d45c5b4..2c7a28e835 100644
--- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
+++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
@@ -121,7 +121,7 @@ bool QQnxVirtualKeyboardPps::connect()
if (m_fd == -1)
{
qVirtualKeyboardDebug() << Q_FUNC_INFO << ": Unable to open" << ms_PPSPath
- << ":" << strerror(errno);
+ << ':' << strerror(errno);
close();
return false;
}
diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json
index b00c9df408..f1500409fe 100644
--- a/src/plugins/platforms/windows/openglblacklists/default.json
+++ b/src/plugins/platforms/windows/openglblacklists/default.json
@@ -4,7 +4,7 @@
"entries": [
{
"id": 1,
- "description": "Desktop OpenGL is unreliable on some Intel HD laptops (QTBUG-43263, QTBUG-42240)",
+ "description": "Desktop OpenGL is unreliable on some Intel HD laptops (QTBUG-43263)",
"vendor_id": "0x8086",
"device_id": [ "0x0A16" ],
"os": {
@@ -42,6 +42,18 @@
"features": [
"disable_desktopgl"
]
+ },
+ {
+ "id": 4,
+ "description": "Intel HD Graphics 3000 crashes when initializing the OpenGL driver (QTBUG-42240)",
+ "vendor_id": "0x8086",
+ "device_id": [ "0x0102", "0x0116" ],
+ "os": {
+ "type": "win"
+ },
+ "features": [
+ "disable_desktopgl"
+ ]
}
]
}
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp
index e4ec3f3cf8..02073f5098 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp
@@ -152,7 +152,7 @@ bool QWindowsLibEGL::init()
eglGetCurrentSurface = RESOLVE((EGLSurface (EGLAPIENTRY *)(EGLint )), eglGetCurrentSurface);
eglGetCurrentDisplay = RESOLVE((EGLDisplay (EGLAPIENTRY *)(void)), eglGetCurrentDisplay);
eglSwapBuffers = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface)), eglSwapBuffers);
- eglGetProcAddress = RESOLVE((__eglMustCastToProperFunctionPointerType (EGLAPIENTRY * )(const char *)), eglGetProcAddress);
+ eglGetProcAddress = RESOLVE((QFunctionPointer (EGLAPIENTRY * )(const char *)), eglGetProcAddress);
if (!eglGetError || !eglGetDisplay || !eglInitialize || !eglGetProcAddress)
return false;
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h
index d8302c97a7..555d633a78 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.h
+++ b/src/plugins/platforms/windows/qwindowseglcontext.h
@@ -71,7 +71,7 @@ struct QWindowsLibEGL
EGLSurface (EGLAPIENTRY * eglGetCurrentSurface)(EGLint readdraw);
EGLDisplay (EGLAPIENTRY * eglGetCurrentDisplay)(void);
EGLBoolean (EGLAPIENTRY * eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
- __eglMustCastToProperFunctionPointerType (EGLAPIENTRY * eglGetProcAddress)(const char *procname);
+ QFunctionPointer (EGLAPIENTRY *eglGetProcAddress)(const char *procname);
EGLDisplay (EGLAPIENTRY * eglGetPlatformDisplayEXT)(EGLenum platform, void *native_display, const EGLint *attrib_list);
diff --git a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp
index 0dd2facd4d..0bfa0239aa 100644
--- a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp
+++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp
@@ -67,18 +67,20 @@ QWindowsGuiEventDispatcher::QWindowsGuiEventDispatcher(QObject *parent) :
bool QWindowsGuiEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
{
+ const QEventLoop::ProcessEventsFlags oldFlags = m_flags;
m_flags = flags;
if (QWindowsContext::verbose > 2 && lcQpaEvents().isDebugEnabled())
qCDebug(lcQpaEvents) << '>' << __FUNCTION__ << objectName() << flags;
const bool rc = QEventDispatcherWin32::processEvents(flags);
if (QWindowsContext::verbose > 2 && lcQpaEvents().isDebugEnabled())
qCDebug(lcQpaEvents) << '<' << __FUNCTION__ << "returns" << rc;
+ m_flags = oldFlags;
return rc;
}
void QWindowsGuiEventDispatcher::sendPostedEvents()
{
- QCoreApplication::sendPostedEvents();
+ QEventDispatcherWin32::sendPostedEvents();
QWindowSystemInterface::sendWindowSystemEvents(m_flags);
}
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
index 375a7f11db..52a4ca26dc 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -1579,7 +1579,11 @@ QVector<FORMATETC> QWindowsMimeConverter::allFormatsForMime(const QMimeData *mim
void QWindowsMimeConverter::ensureInitialized() const
{
if (m_mimes.isEmpty()) {
- m_mimes << new QWindowsMimeImage << new QLastResortMimes
+ m_mimes
+#ifndef QT_NO_IMAGEFORMAT_BMP
+ << new QWindowsMimeImage
+#endif //QT_NO_IMAGEFORMAT_BMP
+ << new QLastResortMimes
<< new QWindowsMimeText << new QWindowsMimeURI
<< new QWindowsMimeHtml << new QBuiltInMimes;
m_internalMimeCount = m_mimes.size();
diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp
index 52e83395d1..befd06f1a2 100644
--- a/src/plugins/platforms/windows/qwindowsopengltester.cpp
+++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp
@@ -276,7 +276,7 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedGlesRenderers()
{
const GpuDescription gpu = GpuDescription::detect();
const QWindowsOpenGLTester::Renderers result = detectSupportedRenderers(gpu, true);
- qDebug(lcQpaGl) << __FUNCTION__ << gpu << "renderer: " << result;
+ qCDebug(lcQpaGl) << __FUNCTION__ << gpu << "renderer: " << result;
return result;
}
@@ -284,7 +284,7 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedRenderers()
{
const GpuDescription gpu = GpuDescription::detect();
const QWindowsOpenGLTester::Renderers result = detectSupportedRenderers(gpu, false);
- qDebug(lcQpaGl) << __FUNCTION__ << gpu << "renderer: " << result;
+ qCDebug(lcQpaGl) << __FUNCTION__ << gpu << "renderer: " << result;
return result;
}
diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp
index 68bf1fdcac..bb04144563 100644
--- a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp
+++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp
@@ -133,45 +133,46 @@ bool QWinRTMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModa
RETURN_FALSE_IF_FAILED("Failed to create dialog");
}
- // Add Buttons
- ComPtr<IVector<IUICommand *>> dialogCommands;
- hr = dialog->get_Commands(&dialogCommands);
- RETURN_FALSE_IF_FAILED("Failed to get dialog commands");
-
- // If no button is specified we need to create one to get close notification
- int buttons = options->standardButtons();
- if (buttons == 0)
- buttons = Ok;
-
- for (int i = FirstButton; i < LastButton; i<<=1) {
- if (!(buttons & i))
- continue;
- // Add native command
- const QString label = d->theme->standardButtonText(i);
- HStringReference nativeLabel(reinterpret_cast<LPCWSTR>(label.utf16()), label.size());
- ComPtr<IUICommand> command;
- hr = commandFactory->Create(nativeLabel.Get(), &command);
- RETURN_FALSE_IF_FAILED("Failed to create message box command");
- ComPtr<IInspectable> id = Make<CommandId>(static_cast<StandardButton>(i));
- hr = command->put_Id(id.Get());
- RETURN_FALSE_IF_FAILED("Failed to set command ID");
- hr = dialogCommands->Append(command.Get());
- if (hr == E_BOUNDS) {
- qErrnoWarning(hr, "The WinRT message dialog supports a maximum of three buttons");
- continue;
- }
- RETURN_FALSE_IF_FAILED("Failed to append message box command");
- if (i == Abort || i == Cancel || i == Close) {
- quint32 size;
- hr = dialogCommands->get_Size(&size);
- RETURN_FALSE_IF_FAILED("Failed to get command list size");
- hr = dialog->put_CancelCommandIndex(size - 1);
- RETURN_FALSE_IF_FAILED("Failed to set cancel index");
+ hr = QEventDispatcherWinRT::runOnXamlThread([this, d, options, commandFactory, dialog]() {
+ HRESULT hr;
+
+ // Add Buttons
+ ComPtr<IVector<IUICommand *>> dialogCommands;
+ hr = dialog->get_Commands(&dialogCommands);
+ RETURN_HR_IF_FAILED("Failed to get dialog commands");
+
+ // If no button is specified we need to create one to get close notification
+ int buttons = options->standardButtons();
+ if (buttons == 0)
+ buttons = Ok;
+
+ for (int i = FirstButton; i < LastButton; i<<=1) {
+ if (!(buttons & i))
+ continue;
+ // Add native command
+ const QString label = d->theme->standardButtonText(i);
+ HStringReference nativeLabel(reinterpret_cast<LPCWSTR>(label.utf16()), label.size());
+ ComPtr<IUICommand> command;
+ hr = commandFactory->Create(nativeLabel.Get(), &command);
+ RETURN_HR_IF_FAILED("Failed to create message box command");
+ ComPtr<IInspectable> id = Make<CommandId>(static_cast<StandardButton>(i));
+ hr = command->put_Id(id.Get());
+ RETURN_HR_IF_FAILED("Failed to set command ID");
+ hr = dialogCommands->Append(command.Get());
+ if (hr == E_BOUNDS) {
+ qErrnoWarning(hr, "The WinRT message dialog supports a maximum of three buttons");
+ continue;
+ }
+ RETURN_HR_IF_FAILED("Failed to append message box command");
+ if (i == Abort || i == Cancel || i == Close) {
+ quint32 size;
+ hr = dialogCommands->get_Size(&size);
+ RETURN_HR_IF_FAILED("Failed to get command list size");
+ hr = dialog->put_CancelCommandIndex(size - 1);
+ RETURN_HR_IF_FAILED("Failed to set cancel index");
+ }
}
- }
- hr = QEventDispatcherWinRT::runOnXamlThread([this, d, dialog]() {
- HRESULT hr;
ComPtr<IAsyncOperation<IUICommand *>> op;
hr = dialog->ShowAsync(&op);
RETURN_HR_IF_FAILED("Failed to show dialog");
@@ -206,8 +207,7 @@ HRESULT QWinRTMessageDialogHelper::onCompleted(IAsyncOperation<IUICommand *> *as
Q_UNUSED(status);
Q_D(QWinRTMessageDialogHelper);
- if (d->loop.isRunning())
- d->loop.exit();
+ QEventLoopLocker locker(&d->loop);
d->shown = false;
diff --git a/src/plugins/platforms/winrt/qwinrttheme.cpp b/src/plugins/platforms/winrt/qwinrttheme.cpp
index a0fa2798a8..c32ec8a151 100644
--- a/src/plugins/platforms/winrt/qwinrttheme.cpp
+++ b/src/plugins/platforms/winrt/qwinrttheme.cpp
@@ -218,7 +218,7 @@ QVariant QWinRTTheme::styleHint(QPlatformIntegration::StyleHint hint)
case QPlatformIntegration::KeyboardAutoRepeatRate:
return defaultThemeHint(KeyboardAutoRepeatRate);
case QPlatformIntegration::ShowIsFullScreen:
- return true;
+ return false;
case QPlatformIntegration::PasswordMaskDelay:
return defaultThemeHint(PasswordMaskDelay);
case QPlatformIntegration::FontSmoothingGamma:
@@ -232,7 +232,7 @@ QVariant QWinRTTheme::styleHint(QPlatformIntegration::StyleHint hint)
case QPlatformIntegration::SetFocusOnTouchRelease:
return false;
case QPlatformIntegration::ShowIsMaximized:
- return false;
+ return true;
case QPlatformIntegration::MousePressAndHoldInterval:
return defaultThemeHint(MousePressAndHoldInterval);
default:
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index c35b019f7e..13d73c7194 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -476,7 +476,7 @@ void QXcbConnection::initializeScreens()
// Push the screens to QApplication
QXcbIntegration *integration = QXcbIntegration::instance();
foreach (QXcbScreen* screen, m_screens) {
- qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")";
+ qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ')';
integration->screenAdded(screen, screen->isPrimary());
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 6ee32bf600..fb5b941fff 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -376,8 +376,10 @@ public:
QXcbConnection *connection() const { return const_cast<QXcbConnection *>(this); }
+ const QList<QXcbVirtualDesktop *> &virtualDesktops() const { return m_virtualDesktops; }
const QList<QXcbScreen *> &screens() const { return m_screens; }
int primaryScreenNumber() const { return m_primaryScreenNumber; }
+ QXcbVirtualDesktop *primaryVirtualDesktop() const { return m_virtualDesktops.value(m_primaryScreenNumber); }
QXcbScreen *primaryScreen() const;
inline xcb_atom_t atom(QXcbAtom::Atom atom) const { return m_allAtoms[atom]; }
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
index 0cd9159052..b321ed95dc 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -607,30 +607,33 @@ xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor)
}
#endif
-void QXcbCursor::queryPointer(QXcbConnection *c, xcb_window_t *rootWin, QPoint *pos, int *keybMask)
+void QXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask)
{
if (pos)
*pos = QPoint();
- xcb_screen_iterator_t it = xcb_setup_roots_iterator(c->setup());
- while (it.rem) {
- xcb_window_t root = it.data->root;
- xcb_query_pointer_cookie_t cookie = xcb_query_pointer(c->xcb_connection(), root);
- xcb_generic_error_t *err = 0;
- xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(c->xcb_connection(), cookie, &err);
- if (!err && reply) {
- if (pos)
- *pos = QPoint(reply->root_x, reply->root_y);
- if (rootWin)
- *rootWin = root;
- if (keybMask)
- *keybMask = reply->mask;
- free(reply);
- return;
+
+ xcb_window_t root = c->primaryVirtualDesktop()->root();
+ xcb_query_pointer_cookie_t cookie = xcb_query_pointer(c->xcb_connection(), root);
+ xcb_generic_error_t *err = 0;
+ xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(c->xcb_connection(), cookie, &err);
+ if (!err && reply) {
+ if (virtualDesktop) {
+ foreach (QXcbVirtualDesktop *vd, c->virtualDesktops()) {
+ if (vd->root() == reply->root) {
+ *virtualDesktop = vd;
+ break;
+ }
+ }
}
- free(err);
+ if (pos)
+ *pos = QPoint(reply->root_x, reply->root_y);
+ if (keybMask)
+ *keybMask = reply->mask;
free(reply);
- xcb_screen_next(&it);
+ return;
}
+ free(err);
+ free(reply);
}
QPoint QXcbCursor::pos() const
@@ -642,9 +645,9 @@ QPoint QXcbCursor::pos() const
void QXcbCursor::setPos(const QPoint &pos)
{
- xcb_window_t root = 0;
- queryPointer(connection(), &root, 0);
- xcb_warp_pointer(xcb_connection(), XCB_NONE, root, 0, 0, 0, 0, pos.x(), pos.y());
+ QXcbVirtualDesktop *virtualDesktop = Q_NULLPTR;
+ queryPointer(connection(), &virtualDesktop, 0);
+ xcb_warp_pointer(xcb_connection(), XCB_NONE, virtualDesktop->root(), 0, 0, 0, 0, pos.x(), pos.y());
xcb_flush(xcb_connection());
}
diff --git a/src/plugins/platforms/xcb/qxcbcursor.h b/src/plugins/platforms/xcb/qxcbcursor.h
index f4f6e61706..3c6dece1f2 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.h
+++ b/src/plugins/platforms/xcb/qxcbcursor.h
@@ -75,7 +75,7 @@ public:
QPoint pos() const Q_DECL_OVERRIDE;
void setPos(const QPoint &pos) Q_DECL_OVERRIDE;
- static void queryPointer(QXcbConnection *c, xcb_window_t *rootWin, QPoint *pos, int *keybMask = 0);
+ static void queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask = 0);
private:
#ifndef QT_NO_CURSOR
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index de23c59a63..f9c3aa7fed 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -39,6 +39,7 @@
#include "qxcbwindow.h"
#include "qxcbscreen.h"
#include "qwindow.h"
+#include "qxcbcursor.h"
#include <private/qdnd_p.h>
#include <qdebug.h>
#include <qevent.h>
@@ -160,7 +161,7 @@ void QXcbDrag::init()
source_time = XCB_CURRENT_TIME;
target_time = XCB_CURRENT_TIME;
- current_screen = 0;
+ QXcbCursor::queryPointer(connection(), &current_virtual_desktop, 0);
drag_types.clear();
}
@@ -308,38 +309,20 @@ void QXcbDrag::move(const QPoint &globalPos)
if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid())
return;
- const QList<QXcbScreen *> &screens = connection()->screens();
- QXcbScreen *screen = connection()->primaryScreen();
- for (int i = 0; i < screens.size(); ++i) {
- if (screens.at(i)->geometry().contains(globalPos)) {
- screen = screens.at(i);
- break;
- }
- }
+ QXcbVirtualDesktop *virtualDesktop = Q_NULLPTR;
+ QPoint cursorPos;
+ QXcbCursor::queryPointer(connection(), &virtualDesktop, &cursorPos);
+ QXcbScreen *screen = virtualDesktop->screenAt(cursorPos);
+ QPoint deviceIndependentPos = QHighDpiScaling::mapPositionFromNative(globalPos, screen);
- QBasicDrag::moveShapedPixmapWindow(QHighDpiScaling::mapPositionFromNative(globalPos, screen));
-
- if (screen != current_screen) {
- // ### need to recreate the shaped pixmap window?
-// int screen = QCursor::x11Screen();
-// if ((qt_xdnd_current_screen == -1 && screen != X11->defaultScreen) || (screen != qt_xdnd_current_screen)) {
-// // recreate the pixmap on the new screen...
-// delete xdnd_data.deco;
-// QWidget* parent = object->source()->window()->x11Info().screen() == screen
-// ? object->source()->window() : QApplication::desktop()->screen(screen);
-// xdnd_data.deco = new QShapedPixmapWidget(parent);
-// if (!QWidget::mouseGrabber()) {
-// updatePixmap();
-// xdnd_data.deco->grabMouse();
-// }
-// }
-// xdnd_data.deco->move(QCursor::pos() - xdnd_data.deco->pm_hot);
- current_screen = screen;
+ if (virtualDesktop != current_virtual_desktop) {
+ recreateShapedPixmapWindow(static_cast<QPlatformScreen*>(screen)->screen(), deviceIndependentPos);
+ current_virtual_desktop = virtualDesktop;
+ } else {
+ QBasicDrag::moveShapedPixmapWindow(deviceIndependentPos);
}
-
-// qt_xdnd_current_screen = screen;
- xcb_window_t rootwin = current_screen->root();
+ xcb_window_t rootwin = current_virtual_desktop->root();
xcb_translate_coordinates_reply_t *translate =
::translateCoordinates(connection(), rootwin, rootwin, globalPos.x(), globalPos.y());
if (!translate)
diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h
index 9584c04238..c9d257906f 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.h
+++ b/src/plugins/platforms/xcb/qxcbdrag.h
@@ -133,7 +133,7 @@ private:
// window to send events to (always valid if current_target)
xcb_window_t current_proxy_target;
- QXcbScreen *current_screen;
+ QXcbVirtualDesktop *current_virtual_desktop;
// 10 minute timer used to discard old XdndDrop transactions
enum { XdndDropTransactionTimeout = 600000 };
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 82cd1b86c9..da4db5edcb 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -61,6 +61,15 @@ QXcbVirtualDesktop::~QXcbVirtualDesktop()
delete m_xSettings;
}
+QXcbScreen *QXcbVirtualDesktop::screenAt(const QPoint &pos) const
+{
+ foreach (QXcbScreen *screen, connection()->screens()) {
+ if (screen->virtualDesktop() == this && screen->nativeGeometry().contains(pos))
+ return screen;
+ }
+ return Q_NULLPTR;
+}
+
QXcbXSettings *QXcbVirtualDesktop::xSettings() const
{
if (!m_xSettings) {
@@ -724,7 +733,7 @@ QDebug operator<<(QDebug debug, const QXcbScreen *screen)
formatSizeF(debug, screen->physicalSize());
// TODO 5.6 if (debug.verbosity() > 2) {
debug << ", screenNumber=" << screen->screenNumber();
- debug << ", virtualSize=" << screen->virtualSize().width() << "x" << screen->virtualSize().height() << " (";
+ debug << ", virtualSize=" << screen->virtualSize().width() << 'x' << screen->virtualSize().height() << " (";
formatSizeF(debug, screen->virtualSize());
debug << "), nativeGeometry=";
formatRect(debug, screen->nativeGeometry());
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index cbb6307d6e..d8d63608e7 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -64,6 +64,8 @@ public:
int number() const { return m_number; }
QSize size() const { return QSize(m_screen->width_in_pixels, m_screen->height_in_pixels); }
QSize physicalSize() const { return QSize(m_screen->width_in_millimeters, m_screen->height_in_millimeters); }
+ xcb_window_t root() const { return m_screen->root; }
+ QXcbScreen *screenAt(const QPoint &pos) const;
QXcbXSettings *xSettings() const;
@@ -104,6 +106,7 @@ public:
void setVirtualSiblings(QList<QPlatformScreen *> sl) { m_siblings = sl; }
void removeVirtualSibling(QPlatformScreen *s) { m_siblings.removeOne(s); }
void addVirtualSibling(QPlatformScreen *s) { ((QXcbScreen *) s)->isPrimary() ? m_siblings.prepend(s) : m_siblings.append(s); }
+ QXcbVirtualDesktop *virtualDesktop() const { return m_virtualDesktop; }
void setPrimary(bool primary) { m_primary = primary; }
bool isPrimary() const { return m_primary; }
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index d751c6d48a..e7f5bbf0e9 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -775,6 +775,13 @@ void QXcbWindow::setVisible(bool visible)
hide();
}
+static inline bool testShowWithoutActivating(const QWindow *window)
+{
+ // QWidget-attribute Qt::WA_ShowWithoutActivating.
+ const QVariant showWithoutActivating = window->property("_q_showWithoutActivating");
+ return showWithoutActivating.isValid() && showWithoutActivating.toBool();
+}
+
void QXcbWindow::show()
{
if (window()->isTopLevel()) {
@@ -822,7 +829,9 @@ void QXcbWindow::show()
updateNetWmStateBeforeMap();
}
- if (connection()->time() != XCB_TIME_CURRENT_TIME)
+ if (testShowWithoutActivating(window()))
+ updateNetWmUserTime(0);
+ else if (connection()->time() != XCB_TIME_CURRENT_TIME)
updateNetWmUserTime(connection()->time());
if (window()->objectName() == QLatin1String("QSystemTrayIconSysWindow"))
@@ -1112,6 +1121,9 @@ void QXcbWindow::setMotifWindowFlags(Qt::WindowFlags flags)
mwmhints.flags |= MWM_HINTS_DECORATIONS;
bool customize = flags & Qt::CustomizeWindowHint;
+ if (type == Qt::Window && !customize)
+ flags |= Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint;
+
if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) {
mwmhints.decorations |= MWM_DECOR_BORDER;
mwmhints.decorations |= MWM_DECOR_RESIZEH;
@@ -1326,7 +1338,11 @@ void QXcbWindow::updateNetWmStateBeforeMap()
void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
{
xcb_window_t wid = m_window;
- connection()->setNetWmUserTime(timestamp);
+ // If timestamp == 0, then it means that the window should not be
+ // initially activated. Don't update global user time for this
+ // special case.
+ if (timestamp != 0)
+ connection()->setNetWmUserTime(timestamp);
const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW));
if (m_netWmUserTimeWindow || isSupportedByWM) {