summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-05-12 07:31:50 +0200
committerLiang Qi <liang.qi@qt.io>2016-05-12 08:33:08 +0200
commit990969655c5fb4d03682e96df9b12101f5ee9815 (patch)
treeb8fb5c50285105c8bc5a938fb50f93ff9f24889d /src/plugins/platforms
parenta213011a53f12f101d08a04afc8fdacd2d54a232 (diff)
parente64b2234e829cc47872225debcf80d6c06db18f0 (diff)
Merge remote-tracking branch 'origin/5.7' into dev
Conflicts: config_help.txt configure src/corelib/io/qprocess_wince.cpp src/plugins/platforms/windows/qwindowstheme.cpp src/plugins/platforms/xcb/qxcbbackingstore.cpp tests/auto/corelib/tools/qtimezone/BLACKLIST tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp Change-Id: I26644d1cb3b78412c8ff285e2a55bea1bd641c01
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp5
-rw-r--r--src/plugins/platforms/android/androidjnimenu.cpp9
-rw-r--r--src/plugins/platforms/android/qandroideventdispatcher.cpp6
-rw-r--r--src/plugins/platforms/android/qandroidplatformfontdatabase.cpp3
-rw-r--r--src/plugins/platforms/android/qandroidplatformmenu.cpp2
-rw-r--r--src/plugins/platforms/android/qandroidplatformmenubar.cpp2
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.cpp14
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm10
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm2
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h2
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm44
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp9
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp5
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h8
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp12
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h2
-rw-r--r--src/plugins/platforms/ios/ios.pro6
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h2
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm2
-rw-r--r--src/plugins/platforms/ios/qiosscreen.h2
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm27
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.h64
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.mm995
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm2
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp26
-rw-r--r--src/plugins/platforms/windows/accessible/iaccessible2.cpp19
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp5
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp10
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp2
-rw-r--r--src/plugins/platforms/winrt/qwinrteglcontext.cpp1
-rw-r--r--src/plugins/platforms/winrt/qwinrtfileengine.cpp12
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.cpp260
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.h18
-rw-r--r--src/plugins/platforms/winrt/qwinrtwindow.cpp5
-rw-r--r--src/plugins/platforms/winrt/winrt.pro2
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp18
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp65
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h16
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp84
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp5
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp55
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp30
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp30
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp77
56 files changed, 1600 insertions, 410 deletions
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index 51849aa688..52f34166eb 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -494,7 +494,7 @@ static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring para
const char *nativeString = env->GetStringUTFChars(environmentString, 0);
const QList<QByteArray> envVars = QByteArray(nativeString).split('\t');
env->ReleaseStringUTFChars(environmentString, nativeString);
- foreach (const QByteArray &envVar, envVars) {
+ for (const QByteArray &envVar : envVars) {
const QList<QByteArray> envVarPair = envVar.split('=');
if (envVarPair.size() == 2 && ::setenv(envVarPair[0], envVarPair[1], 1) != 0)
qWarning() << "Can't set environment" << envVarPair;
@@ -627,7 +627,8 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
return;
if (QGuiApplication::instance() != nullptr) {
- foreach (QWindow *w, QGuiApplication::topLevelWindows()) {
+ const auto tlw = QGuiApplication::topLevelWindows();
+ for (QWindow *w : tlw) {
QRect availableGeometry = w->screen()->availableGeometry();
if (w->geometry().width() > 0 && w->geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
QWindowSystemInterface::handleExposeEvent(w, QRegion(QRect(QPoint(), w->geometry().size())));
diff --git a/src/plugins/platforms/android/androidjnimenu.cpp b/src/plugins/platforms/android/androidjnimenu.cpp
index 551931b688..6f548aba52 100644
--- a/src/plugins/platforms/android/androidjnimenu.cpp
+++ b/src/plugins/platforms/android/androidjnimenu.cpp
@@ -152,7 +152,7 @@ namespace QtAndroidMenu
visibleMenuBar = 0;
activeTopLevelWindow = window;
- foreach (QAndroidPlatformMenuBar *menuBar, menuBars) {
+ for (QAndroidPlatformMenuBar *menuBar : qAsConst(menuBars)) {
if (menuBar->parentWindow() == window) {
visibleMenuBar = menuBar;
resetMenuBar();
@@ -218,7 +218,8 @@ namespace QtAndroidMenu
static int addAllMenuItemsToMenu(JNIEnv *env, jobject menu, QAndroidPlatformMenu *platformMenu) {
int order = 0;
QMutexLocker lock(platformMenu->menuItemsMutex());
- foreach (QAndroidPlatformMenuItem *item, platformMenu->menuItems()) {
+ const auto items = platformMenu->menuItems();
+ for (QAndroidPlatformMenuItem *item : items) {
if (item->isSeparator())
continue;
QString itemText = removeAmpersandEscapes(item->text());
@@ -257,7 +258,7 @@ namespace QtAndroidMenu
if (menus.size() == 1) { // Expand the menu
order = addAllMenuItemsToMenu(env, menu, static_cast<QAndroidPlatformMenu *>(menus.front()));
} else {
- foreach (QAndroidPlatformMenu *item, menus) {
+ for (QAndroidPlatformMenu *item : menus) {
QString itemText = removeAmpersandEscapes(item->text());
jstring jtext = env->NewString(reinterpret_cast<const jchar *>(itemText.data()),
itemText.length());
@@ -350,7 +351,7 @@ namespace QtAndroidMenu
item->activated();
visibleMenu->aboutToHide();
visibleMenu = 0;
- foreach (QAndroidPlatformMenu *menu, pendingContextMenus) {
+ for (QAndroidPlatformMenu *menu : qAsConst(pendingContextMenus)) {
if (menu->isVisible())
menu->aboutToHide();
}
diff --git a/src/plugins/platforms/android/qandroideventdispatcher.cpp b/src/plugins/platforms/android/qandroideventdispatcher.cpp
index 72f093a6eb..104e905b8f 100644
--- a/src/plugins/platforms/android/qandroideventdispatcher.cpp
+++ b/src/plugins/platforms/android/qandroideventdispatcher.cpp
@@ -112,7 +112,7 @@ void QAndroidEventDispatcherStopper::startAll()
return;
started = true;
- foreach (QAndroidEventDispatcher *d, m_dispatchers)
+ for (QAndroidEventDispatcher *d : qAsConst(m_dispatchers))
d->start();
}
@@ -123,7 +123,7 @@ void QAndroidEventDispatcherStopper::stopAll()
return;
started = false;
- foreach (QAndroidEventDispatcher *d, m_dispatchers)
+ for (QAndroidEventDispatcher *d : qAsConst(m_dispatchers))
d->stop();
}
@@ -142,6 +142,6 @@ void QAndroidEventDispatcherStopper::removeEventDispatcher(QAndroidEventDispatch
void QAndroidEventDispatcherStopper::goingToStop(bool stop)
{
QMutexLocker lock(&m_mutex);
- foreach (QAndroidEventDispatcher *d, m_dispatchers)
+ for (QAndroidEventDispatcher *d : qAsConst(m_dispatchers))
d->goingToStop(stop);
}
diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
index efa8681d3d..0667a9073f 100644
--- a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
+++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
@@ -62,7 +62,8 @@ void QAndroidPlatformFontDatabase::populateFontDatabase()
nameFilters << QLatin1String("*.ttf")
<< QLatin1String("*.otf");
- foreach (const QFileInfo &fi, dir.entryInfoList(nameFilters, QDir::Files)) {
+ const auto entries = dir.entryInfoList(nameFilters, QDir::Files);
+ for (const QFileInfo &fi : entries) {
const QByteArray file = QFile::encodeName(fi.absoluteFilePath());
QBasicFontDatabase::addTTFile(QByteArray(), file);
}
diff --git a/src/plugins/platforms/android/qandroidplatformmenu.cpp b/src/plugins/platforms/android/qandroidplatformmenu.cpp
index 83e79eb76e..06b297a1ad 100644
--- a/src/plugins/platforms/android/qandroidplatformmenu.cpp
+++ b/src/plugins/platforms/android/qandroidplatformmenu.cpp
@@ -159,7 +159,7 @@ QPlatformMenuItem *QAndroidPlatformMenu::menuItemAt(int position) const
QPlatformMenuItem *QAndroidPlatformMenu::menuItemForTag(quintptr tag) const
{
- foreach (QPlatformMenuItem *menuItem, m_menuItems) {
+ for (QPlatformMenuItem *menuItem : m_menuItems) {
if (menuItem->tag() == tag)
return menuItem;
}
diff --git a/src/plugins/platforms/android/qandroidplatformmenubar.cpp b/src/plugins/platforms/android/qandroidplatformmenubar.cpp
index 56ccbe1afe..35930f0628 100644
--- a/src/plugins/platforms/android/qandroidplatformmenubar.cpp
+++ b/src/plugins/platforms/android/qandroidplatformmenubar.cpp
@@ -86,7 +86,7 @@ void QAndroidPlatformMenuBar::handleReparent(QWindow *newParentWindow)
QPlatformMenu *QAndroidPlatformMenuBar::menuForTag(quintptr tag) const
{
- foreach (QPlatformMenu *menu, m_menus) {
+ for (QPlatformMenu *menu : m_menus) {
if (menu->tag() == tag)
return menu;
}
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp
index 35a93bb847..155d6bfb8d 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.cpp
+++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp
@@ -117,7 +117,7 @@ QAndroidPlatformScreen::~QAndroidPlatformScreen()
QWindow *QAndroidPlatformScreen::topWindow() const
{
- foreach (QAndroidPlatformWindow *w, m_windowStack) {
+ for (QAndroidPlatformWindow *w : m_windowStack) {
if (w->window()->type() == Qt::Window ||
w->window()->type() == Qt::Popup ||
w->window()->type() == Qt::Dialog) {
@@ -129,7 +129,7 @@ QWindow *QAndroidPlatformScreen::topWindow() const
QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const
{
- foreach (QAndroidPlatformWindow *w, m_windowStack) {
+ for (QAndroidPlatformWindow *w : m_windowStack) {
if (w->geometry().contains(p, false) && w->window()->isVisible())
return w->window();
}
@@ -263,7 +263,7 @@ void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect)
void QAndroidPlatformScreen::applicationStateChanged(Qt::ApplicationState state)
{
- foreach (QAndroidPlatformWindow *w, m_windowStack)
+ for (QAndroidPlatformWindow *w : qAsConst(m_windowStack))
w->applicationStateChanged(state);
if (state <= Qt::ApplicationHidden) {
@@ -304,7 +304,7 @@ void QAndroidPlatformScreen::doRedraw()
// windows that have renderToTexture children (i.e. they need the OpenGL path) then
// we do not need an overlay surface.
bool hasVisibleRasterWindows = false;
- foreach (QAndroidPlatformWindow *window, m_windowStack) {
+ for (QAndroidPlatformWindow *window : qAsConst(m_windowStack)) {
if (window->window()->isVisible() && window->isRaster() && !qt_window_private(window->window())->compositing) {
hasVisibleRasterWindows = true;
break;
@@ -357,14 +357,14 @@ void QAndroidPlatformScreen::doRedraw()
compositePainter.setCompositionMode(QPainter::CompositionMode_Source);
QRegion visibleRegion(m_dirtyRect);
- foreach (QAndroidPlatformWindow *window, m_windowStack) {
+ for (QAndroidPlatformWindow *window : qAsConst(m_windowStack)) {
if (!window->window()->isVisible()
|| qt_window_private(window->window())->compositing
|| !window->isRaster())
continue;
- QVector<QRect> visibleRects = visibleRegion.rects();
- foreach (const QRect &rect, visibleRects) {
+ const QVector<QRect> visibleRects = visibleRegion.rects();
+ for (const QRect &rect : visibleRects) {
QRect targetRect = window->geometry();
targetRect &= rect;
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index c021a551a7..f6a3b3943f 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -337,10 +337,20 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
[newDelegate setMenuLoader:qtMenuLoader];
}
+ // The presentation options such as whether or not the dock and/or menu bar is
+ // hidden (automatically by the system) affects the main screen's available
+ // geometry. Since we're initializing the screens synchronously at application
+ // startup we need to ensure that the presentation options have been propagated
+ // to the screen before we read out its properties. Normally OS X does this in
+ // an asynchronous callback, but that's too late for us. We force the propagation
+ // by explicitly setting the presentation option to the magic 'default value',
+ // which will resolve to an actual value and result in screen invalidation.
+ cocoaApplication.presentationOptions = NSApplicationPresentationDefault;
updateScreens();
QMacInternalPasteboardMime::initializeMimeTypes();
QCocoaMimeTypes::initializeMimeTypes();
+ QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
}
QCocoaIntegration::~QCocoaIntegration()
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 0690a8e0fa..a388155c03 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -105,7 +105,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate);
- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
{
Q_ASSERT(m_menu->nsMenu() == menu);
- return m_menu->items().count();
+ return menu.numberOfItems;
}
- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index b5738abf4c..00d65ea7f8 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -140,7 +140,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
- (void)otherMouseUp:(NSEvent *)theEvent;
- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent;
-- (void)handleTabletEvent: (NSEvent *)theEvent;
+- (bool)handleTabletEvent: (NSEvent *)theEvent;
- (void)tabletPoint: (NSEvent *)theEvent;
- (void)tabletProximity: (NSEvent *)theEvent;
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 66df5c724b..c9783df44b 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -52,6 +52,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/QTextFormat>
#include <QtCore/QDebug>
+#include <QtCore/qsysinfo.h>
#include <private/qguiapplication_p.h>
#include "qcocoabackingstore.h"
#ifndef QT_NO_OPENGL
@@ -74,6 +75,8 @@ static QTouchDevice *touchDevice = 0;
// ### HACK Remove once 10.8 is unsupported
static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
+static bool _q_dontOverrideCtrlLMB = false;
+
@interface NSEvent (Qt_Compile_Leopard_DeviceDelta)
- (CGFloat)deviceDeltaX;
- (CGFloat)deviceDeltaY;
@@ -134,6 +137,8 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
NSString **notificationNameVar = (NSString **)dlsym(RTLD_NEXT, "NSWindowDidChangeOcclusionStateNotification");
if (notificationNameVar)
_q_NSWindowDidChangeOcclusionStateNotification = *notificationNameVar;
+
+ _q_dontOverrideCtrlLMB = qt_mac_resolveOption(false, "QT_MAC_DONT_OVERRIDE_CTRL_LMB");
}
- (id) init
@@ -746,7 +751,7 @@ QT_WARNING_POP
- (void)handleMouseEvent:(NSEvent *)theEvent
{
- [self handleTabletEvent: theEvent];
+ bool isTabletEvent = [self handleTabletEvent: theEvent];
QPointF qtWindowPoint;
QPointF qtScreenPoint;
@@ -775,7 +780,8 @@ QT_WARNING_POP
nativeDrag->setLastMouseEvent(theEvent, self);
Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
- QWindowSystemInterface::handleMouseEvent(targetView->m_window, timestamp, qtWindowPoint, qtScreenPoint, m_buttons, keyboardModifiers);
+ QWindowSystemInterface::handleMouseEvent(targetView->m_window, timestamp, qtWindowPoint, qtScreenPoint, m_buttons, keyboardModifiers,
+ isTabletEvent ? Qt::MouseEventSynthesizedByQt : Qt::MouseEventNotSynthesized);
}
- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent
@@ -967,7 +973,7 @@ QT_WARNING_POP
if ([self hasMarkedText]) {
[[NSTextInputContext currentInputContext] handleEvent:theEvent];
} else {
- if ([QNSView convertKeyModifiers:[theEvent modifierFlags]] & Qt::MetaModifier) {
+ if (!_q_dontOverrideCtrlLMB && [QNSView convertKeyModifiers:[theEvent modifierFlags]] & Qt::MetaModifier) {
m_buttons |= Qt::RightButton;
m_sendUpAsRightButton = true;
} else {
@@ -1152,11 +1158,11 @@ struct QCocoaTabletDeviceData
typedef QHash<uint, QCocoaTabletDeviceData> QCocoaTabletDeviceDataHash;
Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
-- (void)handleTabletEvent: (NSEvent *)theEvent
+- (bool)handleTabletEvent: (NSEvent *)theEvent
{
NSEventType eventType = [theEvent type];
if (eventType != NSTabletPoint && [theEvent subtype] != NSTabletPointEventSubtype)
- return; // Not a tablet event.
+ return false; // Not a tablet event.
ulong timestamp = [theEvent timestamp] * 1000;
@@ -1169,7 +1175,7 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
// Error: Unknown tablet device. Qt also gets into this state
// when running on a VM. This appears to be harmless; don't
// print a warning.
- return;
+ return false;
}
const QCocoaTabletDeviceData &deviceData = tabletDeviceDataHash->value(deviceId);
@@ -1210,6 +1216,7 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
deviceData.device, deviceData.pointerType, buttons, pressure, xTilt, yTilt,
tangentialPressure, rotation, z, deviceData.uid,
keyboardModifiers);
+ return true;
}
- (void)tabletPoint: (NSEvent *)theEvent
@@ -1349,8 +1356,29 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
}
#ifndef QT_NO_GESTURES
+
+- (bool)handleGestureAsBeginEnd:(NSEvent *)event
+{
+ if (QSysInfo::QSysInfo::MacintoshVersion < QSysInfo::MV_10_11)
+ return false;
+
+ if ([event phase] == NSEventPhaseBegan) {
+ [self beginGestureWithEvent:event];
+ return true;
+ }
+
+ if ([event phase] == NSEventPhaseEnded) {
+ [self endGestureWithEvent:event];
+ return true;
+ }
+
+ return false;
+}
- (void)magnifyWithEvent:(NSEvent *)event
{
+ if ([self handleGestureAsBeginEnd:event])
+ return;
+
qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
@@ -1377,7 +1405,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)rotateWithEvent:(NSEvent *)event
{
- qCDebug(lcQpaGestures) << "rotateWithEvent" << [event rotation];
+ if ([self handleGestureAsBeginEnd:event])
+ return;
+
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
index 82877710fc..979bfe3ea9 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
@@ -1,7 +1,7 @@
TARGET = qeglfs-kms-integration
PLUGIN_TYPE = egldeviceintegrations
-PLUGIN_CLASS_NAME = QEglFSKmsIntegrationPlugin
+PLUGIN_CLASS_NAME = QEglFSKmsGbmIntegrationPlugin
load(qt_plugin)
QT += core-private gui-private platformsupport-private eglfs_device_lib-private eglfs_kms_support-private
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
index 8536e2c239..d96c3964df 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
@@ -107,8 +107,10 @@ QEglFSKmsGbmCursor::~QEglFSKmsGbmCursor()
drmModeMoveCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0);
}
- gbm_bo_destroy(m_bo);
- m_bo = Q_NULLPTR;
+ if (m_bo) {
+ gbm_bo_destroy(m_bo);
+ m_bo = Q_NULLPTR;
+ }
}
void QEglFSKmsGbmCursor::pointerEvent(const QMouseEvent &event)
@@ -121,6 +123,9 @@ void QEglFSKmsGbmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
{
Q_UNUSED(window);
+ if (!m_bo)
+ return;
+
if (!m_visible)
return;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
index 9bb489d6b4..278752bddf 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
@@ -116,9 +116,9 @@ void QEglFSKmsGbmDevice::close()
m_globalCursor = Q_NULLPTR;
}
-EGLNativeDisplayType QEglFSKmsGbmDevice::device() const
+EGLNativeDisplayType QEglFSKmsGbmDevice::nativeDisplay() const
{
- return 0;
+ return reinterpret_cast<EGLNativeDisplayType>(m_gbm_device);
}
gbm_device * QEglFSKmsGbmDevice::gbmDevice() const
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h
index 6203a6dc7f..6a45f9ffa0 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h
@@ -59,7 +59,7 @@ public:
bool open() Q_DECL_OVERRIDE;
void close() Q_DECL_OVERRIDE;
- EGLNativeDisplayType device() const Q_DECL_OVERRIDE;
+ EGLNativeDisplayType nativeDisplay() const Q_DECL_OVERRIDE;
gbm_device *gbmDevice() const;
QPlatformCursor *globalCursor() const;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp
index e09f2fdb18..743f714cf0 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp
@@ -39,6 +39,7 @@
#include "qeglfskmsegldevice.h"
#include "qeglfskmsegldevicescreen.h"
+#include "qeglfskmsegldeviceintegration.h"
#include <QtCore/private/qcore_unix_p.h>
@@ -68,9 +69,9 @@ void QEglFSKmsEglDevice::close()
setFd(-1);
}
-EGLNativeDisplayType QEglFSKmsEglDevice::device() const
+EGLNativeDisplayType QEglFSKmsEglDevice::nativeDisplay() const
{
- return 0;
+ return static_cast<QEglFSKmsEglDeviceIntegration *>(m_integration)->eglDevice();
}
QEglFSKmsScreen *QEglFSKmsEglDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output, QPoint position)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h
index f85ec27fa2..b1c98f3fe6 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h
@@ -50,7 +50,7 @@ public:
virtual bool open() Q_DECL_OVERRIDE;
virtual void close() Q_DECL_OVERRIDE;
- virtual EGLNativeDisplayType device() const Q_DECL_OVERRIDE;
+ virtual EGLNativeDisplayType nativeDisplay() const Q_DECL_OVERRIDE;
virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration,
QEglFSKmsDevice *device,
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
index 43c1945a7f..f04c42267a 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
@@ -62,6 +62,9 @@ public:
QEglFSWindow *createWindow(QWindow *window) const Q_DECL_OVERRIDE;
virtual bool separateScreens() const Q_DECL_OVERRIDE;
+
+ EGLDeviceEXT eglDevice() const { return m_egl_device; }
+
protected:
QEglFSKmsDevice *createDevice(const QString &devicePath) Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h
index ffa8bcbaa5..041c063695 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h
@@ -61,7 +61,7 @@ public:
virtual void createScreens();
- virtual EGLNativeDisplayType device() const = 0;
+ virtual EGLNativeDisplayType nativeDisplay() const = 0;
int fd() const;
QString devicePath() const;
@@ -72,9 +72,6 @@ protected:
QPoint position);
void setFd(int fd);
-private:
- Q_DISABLE_COPY(QEglFSKmsDevice)
-
QEglFSKmsIntegration *m_integration;
QString m_path;
int m_dri_fd;
@@ -91,6 +88,9 @@ private:
unsigned int tv_sec,
unsigned int tv_usec,
void *user_data);
+
+private:
+ Q_DISABLE_COPY(QEglFSKmsDevice)
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
index e25e481878..07ea7d4439 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
@@ -90,7 +90,7 @@ void QEglFSKmsIntegration::platformDestroy()
EGLNativeDisplayType QEglFSKmsIntegration::platformDisplay() const
{
Q_ASSERT(m_device);
- return reinterpret_cast<EGLNativeDisplayType>(m_device->device());
+ return m_device->nativeDisplay();
}
bool QEglFSKmsIntegration::usesDefaultScreen()
@@ -183,12 +183,12 @@ void QEglFSKmsIntegration::loadConfig()
const QJsonObject object = doc.object();
- m_hwCursor = object.value(QStringLiteral("hwcursor")).toBool(m_hwCursor);
- m_pbuffers = object.value(QStringLiteral("pbuffers")).toBool(m_pbuffers);
- m_devicePath = object.value(QStringLiteral("device")).toString();
- m_separateScreens = object.value(QStringLiteral("separateScreens")).toBool(m_separateScreens);
+ m_hwCursor = object.value(QLatin1String("hwcursor")).toBool(m_hwCursor);
+ m_pbuffers = object.value(QLatin1String("pbuffers")).toBool(m_pbuffers);
+ m_devicePath = object.value(QLatin1String("device")).toString();
+ m_separateScreens = object.value(QLatin1String("separateScreens")).toBool(m_separateScreens);
- const QJsonArray outputs = object.value(QStringLiteral("outputs")).toArray();
+ const QJsonArray outputs = object.value(QLatin1String("outputs")).toArray();
for (int i = 0; i < outputs.size(); i++) {
const QVariantMap outputSettings = outputs.at(i).toObject().toVariantMap();
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h
index c630d93fce..34ac5385a5 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h
@@ -77,7 +77,6 @@ public:
protected:
virtual QEglFSKmsDevice *createDevice(const QString &devicePath) = 0;
-private:
void loadConfig();
QEglFSKmsDevice *m_device;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
index f614351a40..e6b256f6b2 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
@@ -73,7 +73,7 @@ QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsIntegration *integration,
QEglFSKmsDevice *device,
QEglFSKmsOutput output,
QPoint position)
- : QEglFSScreen(eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(device->device())))
+ : QEglFSScreen(eglGetDisplay(device->nativeDisplay()))
, m_integration(integration)
, m_device(device)
, m_output(output)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
index ed26ca0419..aa698e1b5d 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
@@ -111,7 +111,7 @@ public:
QPlatformScreen::PowerState powerState() const Q_DECL_OVERRIDE;
void setPowerState(QPlatformScreen::PowerState state) Q_DECL_OVERRIDE;
-private:
+protected:
QEglFSKmsIntegration *m_integration;
QEglFSKmsDevice *m_device;
diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro
index d82b47fb74..7b0a573ffa 100644
--- a/src/plugins/platforms/ios/ios.pro
+++ b/src/plugins/platforms/ios/ios.pro
@@ -26,7 +26,8 @@ OBJECTIVE_SOURCES = \
qiosmenu.mm \
qiosfileengineassetslibrary.mm \
qiosfiledialog.mm \
- qiosmessagedialog.mm
+ qiosmessagedialog.mm \
+ qiostextinputoverlay.mm
HEADERS = \
qiosintegration.h \
@@ -51,7 +52,8 @@ HEADERS = \
qiosfileenginefactory.h \
qiosfileengineassetslibrary.h \
qiosfiledialog.h \
- qiosmessagedialog.h
+ qiosmessagedialog.h \
+ qiostextinputoverlay.h
OTHER_FILES = \
quiview_textinput.mm \
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
index 3372fd539b..a50d9aa571 100644
--- a/src/plugins/platforms/ios/qiosintegration.h
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -46,6 +46,7 @@
#include "qiosapplicationstate.h"
#include "qiosfileenginefactory.h"
+#include "qiostextinputoverlay.h"
QT_BEGIN_NAMESPACE
@@ -108,6 +109,7 @@ private:
QIOSServices *m_platformServices;
mutable QPlatformAccessibility *m_accessibility;
QIOSFileEngineFactory m_fileEngineFactory;
+ QIOSTextInputOverlay m_textInputOverlay;
bool m_debugWindowManagement;
};
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index 346c1f21aa..fa12d54b28 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -233,6 +233,8 @@ QPlatformServices *QIOSIntegration::services() const
QVariant QIOSIntegration::styleHint(StyleHint hint) const
{
switch (hint) {
+ case StartDragTime:
+ return 300;
case PasswordMaskDelay:
// this number is based on timing the native delay
// since there is no API to get it
diff --git a/src/plugins/platforms/ios/qiosscreen.h b/src/plugins/platforms/ios/qiosscreen.h
index 461298269d..56a0874bb4 100644
--- a/src/plugins/platforms/ios/qiosscreen.h
+++ b/src/plugins/platforms/ios/qiosscreen.h
@@ -79,7 +79,7 @@ private:
QRect m_geometry;
QRect m_availableGeometry;
int m_depth;
- uint m_pixelDensity;
+ uint m_physicalDpi;
QSizeF m_physicalSize;
QIOSOrientationListener *m_orientationListener;
};
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index 29cb5876af..bfd22abaa4 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -186,18 +186,18 @@ QIOSScreen::QIOSScreen(UIScreen *screen)
if (deviceIdentifier.contains(QRegularExpression("^iPhone(7,1|8,2)$"))) {
// iPhone 6 Plus or iPhone 6S Plus
- m_pixelDensity = 401;
+ m_physicalDpi = 401;
} else if (deviceIdentifier.contains(QRegularExpression("^iPad(1,1|2,[1-4]|3,[1-6]|4,[1-3]|5,[3-4]|6,[7-8])$"))) {
// All iPads except the iPad Mini series
- m_pixelDensity = 132 * devicePixelRatio();
+ m_physicalDpi = 132 * devicePixelRatio();
} else {
// All non-Plus iPhones, and iPad Minis
- m_pixelDensity = 163 * devicePixelRatio();
+ m_physicalDpi = 163 * devicePixelRatio();
}
} else {
// External display, hard to say
m_depth = 24;
- m_pixelDensity = 96;
+ m_physicalDpi = 96;
}
for (UIWindow *existingWindow in [[UIApplication sharedApplication] windows]) {
@@ -259,8 +259,23 @@ void QIOSScreen::updateProperties()
}
if (m_geometry != previousGeometry) {
- const qreal millimetersPerInch = 25.4;
- m_physicalSize = QSizeF(m_geometry.size() * devicePixelRatio()) / m_pixelDensity * millimetersPerInch;
+ QRectF physicalGeometry;
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0) {
+ // We can't use the primaryOrientation of screen(), as we haven't reported the new geometry yet
+ Qt::ScreenOrientation primaryOrientation = m_geometry.width() >= m_geometry.height() ?
+ Qt::LandscapeOrientation : Qt::PortraitOrientation;
+
+ // On iPhone 6+ devices, or when display zoom is enabled, the render buffer is scaled
+ // before being output on the physical display. We have to take this into account when
+ // computing the physical size. Note that unlike the native bounds, the physical size
+ // follows the primary orientation of the screen.
+ physicalGeometry = mapBetween(nativeOrientation(), primaryOrientation, fromCGRect(m_uiScreen.nativeBounds).toRect());
+ } else {
+ physicalGeometry = QRectF(0, 0, m_geometry.width() * devicePixelRatio(), m_geometry.height() * devicePixelRatio());
+ }
+
+ static const qreal millimetersPerInch = 25.4;
+ m_physicalSize = physicalGeometry.size() / m_physicalDpi * millimetersPerInch;
}
// At construction time, we don't yet have an associated QScreen, but we still want
diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.h b/src/plugins/platforms/ios/qiostextinputoverlay.h
new file mode 100644
index 0000000000..2f01993b19
--- /dev/null
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 QIOSTEXTEDITOVERLAY_H
+#define QIOSTEXTEDITOVERLAY_H
+
+#include <QtCore/QObject>
+
+Q_FORWARD_DECLARE_OBJC_CLASS(QIOSEditMenu);
+Q_FORWARD_DECLARE_OBJC_CLASS(QIOSCursorRecognizer);
+Q_FORWARD_DECLARE_OBJC_CLASS(QIOSSelectionRecognizer);
+Q_FORWARD_DECLARE_OBJC_CLASS(QIOSTapRecognizer);
+
+QT_BEGIN_NAMESPACE
+
+class QIOSTextInputOverlay : public QObject
+{
+public:
+ QIOSTextInputOverlay();
+ ~QIOSTextInputOverlay();
+
+ static QIOSEditMenu *s_editMenu;
+
+private:
+ QIOSCursorRecognizer *m_cursorRecognizer;
+ QIOSSelectionRecognizer *m_selectionRecognizer;
+ QIOSTapRecognizer *m_openMenuOnTapRecognizer;
+
+ void updateFocusObject();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm
new file mode 100644
index 0000000000..3fa9341540
--- /dev/null
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm
@@ -0,0 +1,995 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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$
+**
+****************************************************************************/
+
+#import <UIKit/UIGestureRecognizerSubclass.h>
+#import <UIKit/UITextView.h>
+
+#include <QtGui/QGuiApplication>
+#include <QtGui/QInputMethod>
+#include <QtGui/QStyleHints>
+
+#include <QtGui/private/qinputmethod_p.h>
+#include <QtCore/private/qobject_p.h>
+
+#include "qiosglobal.h"
+#include "qiostextinputoverlay.h"
+
+typedef QPair<int, int> SelectionPair;
+
+static const CGFloat kKnobWidth = 10;
+
+static QPlatformInputContext *platformInputContext()
+{
+ return static_cast<QInputMethodPrivate *>(QObjectPrivate::get(QGuiApplication::inputMethod()))->platformInputContext();
+}
+
+static SelectionPair querySelection()
+{
+ QInputMethodQueryEvent query(Qt::ImAnchorPosition | Qt::ImCursorPosition);
+ QGuiApplication::sendEvent(QGuiApplication::focusObject(), &query);
+ int anchorPos = query.value(Qt::ImAnchorPosition).toInt();
+ int cursorPos = query.value(Qt::ImCursorPosition).toInt();
+ return qMakePair<int, int>(anchorPos, cursorPos);
+}
+
+static bool hasSelection()
+{
+ SelectionPair selection = querySelection();
+ return selection.first != selection.second;
+}
+
+static void executeBlockWithoutAnimation(void (^block)(void))
+{
+ [CATransaction begin];
+ [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
+ block();
+ [CATransaction commit];
+}
+
+// -------------------------------------------------------------------------
+/**
+ QIOSEditMenu is just a wrapper class around UIMenuController to
+ ease showing and hiding it correcly.
+ */
+@interface QIOSEditMenu : NSObject
+@property (nonatomic, assign) BOOL visible;
+@property (nonatomic, readonly) BOOL isHiding;
+@property (nonatomic, assign) BOOL reshowAfterHidden;
+@end
+
+@implementation QIOSEditMenu
+
+- (id)init
+{
+ if (self = [super init]) {
+ NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+
+ [center addObserverForName:UIMenuControllerWillHideMenuNotification
+ object:nil queue:nil usingBlock:^(NSNotification *) {
+ _isHiding = YES;
+ }];
+
+ [center addObserverForName:UIMenuControllerDidHideMenuNotification
+ object:nil queue:nil usingBlock:^(NSNotification *) {
+ _isHiding = NO;
+ if (self.reshowAfterHidden) {
+ // To not abort an ongoing hide transition when showing the menu, you can set
+ // reshowAfterHidden to wait until the transition finishes before reshowing it.
+ self.reshowAfterHidden = NO;
+ dispatch_async(dispatch_get_main_queue (), ^{ self.visible = YES; });
+ }
+ }];
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:nil];
+ [super dealloc];
+}
+
+- (BOOL)visible
+{
+ return [UIMenuController sharedMenuController].menuVisible;
+}
+
+- (void)setVisible:(BOOL)visible
+{
+ if (visible == self.visible)
+ return;
+
+ if (visible) {
+ // Note that the contents of the edit menu is decided by
+ // first responder, which is normally QIOSTextResponder.
+ QRectF cr = qApp->inputMethod()->cursorRectangle();
+ QRectF ar = qApp->inputMethod()->anchorRectangle();
+ CGRect targetRect = toCGRect(cr.united(ar));
+ UIView *focusView = reinterpret_cast<UIView *>(qApp->focusWindow()->winId());
+ [[UIMenuController sharedMenuController] setTargetRect:targetRect inView:focusView];
+ [[UIMenuController sharedMenuController] setMenuVisible:YES animated:YES];
+ } else {
+ [[UIMenuController sharedMenuController] setMenuVisible:NO animated:YES];
+ }
+}
+
+@end
+
+// -------------------------------------------------------------------------
+
+@interface QIOSLoupeLayer : CALayer {
+ UIView *_snapshotView;
+ BOOL _pendingSnapshotUpdate;
+ UIView *_loupeImageView;
+ CALayer *_containerLayer;
+ CGFloat _loupeOffset;
+ QTimer _updateTimer;
+}
+@property (nonatomic, retain) UIView *targetView;
+@property (nonatomic, assign) CGPoint focalPoint;
+@property (nonatomic, assign) BOOL visible;
+@end
+
+@implementation QIOSLoupeLayer
+
+- (id)initWithSize:(CGSize)size cornerRadius:(CGFloat)cornerRadius bottomOffset:(CGFloat)bottomOffset
+{
+ if (self = [super init]) {
+ _loupeOffset = bottomOffset + (size.height / 2);
+ _snapshotView = nil;
+ _pendingSnapshotUpdate = YES;
+ _updateTimer.setInterval(100);
+ _updateTimer.setSingleShot(true);
+ QObject::connect(&_updateTimer, &QTimer::timeout, [self](){ [self updateSnapshot]; });
+
+ // Create own geometry and outer shadow
+ self.frame = CGRectMake(0, 0, size.width, size.height);
+ self.cornerRadius = cornerRadius;
+ self.shadowColor = [[UIColor grayColor] CGColor];
+ self.shadowOffset = CGSizeMake(0, 1);
+ self.shadowRadius = 2.0;
+ self.shadowOpacity = 0.75;
+ self.transform = CATransform3DMakeScale(0, 0, 0);
+
+ // Create container view for the snapshots
+ _containerLayer = [[CALayer new] autorelease];
+ _containerLayer.frame = self.bounds;
+ _containerLayer.cornerRadius = cornerRadius;
+ _containerLayer.masksToBounds = YES;
+ [self addSublayer:_containerLayer];
+
+ // Create inner loupe shadow
+ const CGFloat inset = 30;
+ CALayer *topShadeLayer = [[CALayer new] autorelease];
+ topShadeLayer.frame = CGRectOffset(CGRectInset(self.bounds, -inset, -inset), 0, inset / 2);
+ topShadeLayer.borderWidth = inset / 2;
+ topShadeLayer.cornerRadius = cornerRadius;
+ topShadeLayer.borderColor = [[UIColor blackColor] CGColor];
+ topShadeLayer.shadowColor = [[UIColor blackColor] CGColor];
+ topShadeLayer.shadowOffset = CGSizeMake(0, 0);
+ topShadeLayer.shadowRadius = 15.0;
+ topShadeLayer.shadowOpacity = 0.6;
+ // Keep the shadow inside the loupe
+ CALayer *mask = [[CALayer new] autorelease];
+ mask.frame = CGRectOffset(self.bounds, inset, inset / 2);
+ mask.backgroundColor = [[UIColor blackColor] CGColor];
+ mask.cornerRadius = cornerRadius;
+ topShadeLayer.mask = mask;
+ [self addSublayer:topShadeLayer];
+
+ // Create border around the loupe. We need to do this in a separate
+ // layer (as opposed to on self) to not draw the border on top of
+ // overlapping external children (arrow).
+ CALayer *borderLayer = [[CALayer new] autorelease];
+ borderLayer.frame = self.bounds;
+ borderLayer.borderWidth = 0.75;
+ borderLayer.cornerRadius = cornerRadius;
+ borderLayer.borderColor = [[UIColor lightGrayColor] CGColor];
+ [self addSublayer:borderLayer];
+
+ if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_7_0) {
+ // [UIView snapshotViewAfterScreenUpdates:] is available since iOS 7.0.
+ // Just silently ignore showing the loupe for older versions.
+ self.hidden = YES;
+ }
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ _targetView = nil;
+ [super dealloc];
+}
+
+- (void)setVisible:(BOOL)visible
+{
+ if (_visible == visible)
+ return;
+
+ _visible = visible;
+
+ dispatch_async(dispatch_get_main_queue (), ^{
+ // Setting transform later, since CA will not perform an animation if
+ // changing values directly after init, and if the scale ends up empty.
+ self.transform = _visible ? CATransform3DMakeScale(1, 1, 1) : CATransform3DMakeScale(0.0, 0.0, 1);
+ });
+}
+
+- (void)updateSnapshot
+{
+ _pendingSnapshotUpdate = YES;
+ [self setNeedsDisplay];
+}
+
+- (void)setFocalPoint:(CGPoint)point
+{
+ _focalPoint = point;
+ [self updateSnapshot];
+
+ // Schedule a delayed update as well to ensure that we end up with a correct
+ // snapshot of the cursor, since QQuickRenderThread lags a bit behind
+ _updateTimer.start();
+}
+
+- (void)display
+{
+ if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_7_0)
+ return;
+
+ // Take a snapshow of the target view, magnify the area around the focal
+ // point, and add the snapshow layer as a child of the container layer
+ // to make it look like a loupe. Then place this layer at the position of
+ // the focal point with the requested offset.
+ executeBlockWithoutAnimation(^{
+ if (_pendingSnapshotUpdate) {
+ UIView *newSnapshot = [_targetView snapshotViewAfterScreenUpdates:NO];
+ [_snapshotView.layer removeFromSuperlayer];
+ [_snapshotView release];
+ _snapshotView = [newSnapshot retain];
+ [_containerLayer addSublayer:_snapshotView.layer];
+ _pendingSnapshotUpdate = NO;
+ }
+
+ self.position = CGPointMake(_focalPoint.x, _focalPoint.y - _loupeOffset);
+
+ const CGFloat loupeScale = 1.5;
+ CGFloat x = -(_focalPoint.x * loupeScale) + self.frame.size.width / 2;
+ CGFloat y = -(_focalPoint.y * loupeScale) + self.frame.size.height / 2;
+ CGFloat w = _targetView.frame.size.width * loupeScale;
+ CGFloat h = _targetView.frame.size.height * loupeScale;
+ _snapshotView.layer.frame = CGRectMake(x, y, w, h);
+ });
+}
+
+@end
+
+// -------------------------------------------------------------------------
+
+@interface QIOSHandleLayer : CALayer {
+ CALayer *_handleCursorLayer;
+ CALayer *_handleKnobLayer;
+ Qt::Edge _selectionEdge;
+}
+@property (nonatomic, assign) CGRect cursorRectangle;
+@property (nonatomic, assign) CGFloat handleScale;
+@property (nonatomic, assign) BOOL visible;
+@end
+
+@implementation QIOSHandleLayer
+
+@dynamic handleScale;
+
+- (id)initWithKnobAtEdge:(Qt::Edge)selectionEdge
+{
+ if (self = [super init]) {
+ CGColorRef bgColor = [UIColor colorWithRed:0.1 green:0.4 blue:0.9 alpha:1].CGColor;
+ _selectionEdge = selectionEdge;
+ self.handleScale = 0;
+
+ _handleCursorLayer = [[CALayer new] autorelease];
+ _handleCursorLayer.masksToBounds = YES;
+ _handleCursorLayer.backgroundColor = bgColor;
+ [self addSublayer:_handleCursorLayer];
+
+ _handleKnobLayer = [[CALayer new] autorelease];
+ _handleKnobLayer.masksToBounds = YES;
+ _handleKnobLayer.backgroundColor = bgColor;
+ _handleKnobLayer.cornerRadius = kKnobWidth / 2;
+ [self addSublayer:_handleKnobLayer];
+ }
+ return self;
+}
+
++ (BOOL)needsDisplayForKey:(NSString *)key
+{
+ if ([key isEqualToString:@"handleScale"])
+ return YES;
+ return [super needsDisplayForKey:key];
+}
+
+- (id<CAAction>)actionForKey:(NSString *)key
+{
+ if ([key isEqualToString:@"handleScale"]) {
+ if (_visible) {
+ // The handle should "bounce" in when becoming visible
+ CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:key];
+ [animation setDuration:0.5];
+ animation.values = [NSArray arrayWithObjects:
+ [NSNumber numberWithFloat:0],
+ [NSNumber numberWithFloat:1.3],
+ [NSNumber numberWithFloat:1.3],
+ [NSNumber numberWithFloat:1], nil];
+ animation.keyTimes = [NSArray arrayWithObjects:
+ [NSNumber numberWithFloat:0],
+ [NSNumber numberWithFloat:0.3],
+ [NSNumber numberWithFloat:0.9],
+ [NSNumber numberWithFloat:1], nil];
+ return animation;
+ } else {
+ CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:key];
+ animation.fromValue = [self valueForKey:key];
+ [animation setDuration:0.2];
+ return animation;
+ }
+ }
+ return [super actionForKey:key];
+}
+
+- (void)setVisible:(BOOL)visible
+{
+ if (visible == _visible)
+ return;
+
+ _visible = visible;
+
+ self.handleScale = visible ? 1 : 0;
+}
+
+- (void)setCursorRectangle:(CGRect)cursorRect
+{
+ if (CGRectEqualToRect(_cursorRectangle, cursorRect))
+ return;
+
+ _cursorRectangle = cursorRect;
+
+ executeBlockWithoutAnimation(^{
+ [self setNeedsDisplay];
+ [self displayIfNeeded];
+ });
+}
+
+- (void)display
+{
+ CGFloat cursorWidth = 2;
+ CGPoint origin = _cursorRectangle.origin;
+ CGSize size = _cursorRectangle.size;
+ CGFloat scale = ((QIOSHandleLayer *)[self presentationLayer]).handleScale;
+ CGFloat edgeAdjustment = (_selectionEdge == Qt::LeftEdge) ? 0.5 - cursorWidth : -0.5;
+
+ CGFloat cursorX = origin.x + (size.width / 2) + edgeAdjustment;
+ CGFloat cursorY = origin.y;
+ CGFloat knobX = cursorX - (kKnobWidth - cursorWidth) / 2;
+ CGFloat knobY = origin.y + ((_selectionEdge == Qt::LeftEdge) ? -kKnobWidth : size.height);
+
+ _handleCursorLayer.frame = CGRectMake(cursorX, cursorY, cursorWidth, size.height);
+ _handleKnobLayer.frame = CGRectMake(knobX, knobY, kKnobWidth, kKnobWidth);
+ _handleCursorLayer.transform = CATransform3DMakeScale(1, scale, scale);
+ _handleKnobLayer.transform = CATransform3DMakeScale(scale, scale, scale);
+}
+
+@end
+
+// -------------------------------------------------------------------------
+
+/**
+ QIOSLoupeRecognizer is only a base class from which other recognisers
+ below will inherit. It takes care of creating and showing a magnifier
+ glass depending on the current gesture state.
+ */
+@interface QIOSLoupeRecognizer : UIGestureRecognizer <UIGestureRecognizerDelegate> {
+@public
+ QIOSLoupeLayer *_loupeLayer;
+ UIView *_desktopView;
+ CGPoint _firstTouchPoint;
+ CGPoint _lastTouchPoint;
+ QTimer _triggerStateBeganTimer;
+ int _originalCursorFlashTime;
+}
+@property (nonatomic, assign) QPointF focalPoint;
+@property (nonatomic, assign) BOOL dragTriggersGesture;
+@property (nonatomic, readonly) UIView *focusView;
+@end
+
+@implementation QIOSLoupeRecognizer
+
+- (id)init
+{
+ if (self = [super initWithTarget:self action:@selector(gestureStateChanged)]) {
+ self.enabled = NO;
+ _triggerStateBeganTimer.setInterval(QGuiApplication::styleHints()->startDragTime());
+ _triggerStateBeganTimer.setSingleShot(true);
+ QObject::connect(&_triggerStateBeganTimer, &QTimer::timeout, [=](){
+ self.state = UIGestureRecognizerStateBegan;
+ });
+ }
+
+ return self;
+}
+
+- (void)setEnabled:(BOOL)enabled
+{
+ if (enabled == self.enabled)
+ return;
+
+ [super setEnabled:enabled];
+
+ if (enabled) {
+ _focusView = [reinterpret_cast<UIView *>(qApp->focusWindow()->winId()) retain];
+ _desktopView = [[UIApplication sharedApplication].keyWindow.rootViewController.view retain];
+ Q_ASSERT(_focusView && _desktopView && _desktopView.superview);
+ [_desktopView addGestureRecognizer:self];
+ } else {
+ [_desktopView removeGestureRecognizer:self];
+ [_desktopView release];
+ _desktopView = nil;
+ [_focusView release];
+ _focusView = nil;
+ _triggerStateBeganTimer.stop();
+ if (_loupeLayer) {
+ [_loupeLayer removeFromSuperlayer];
+ [_loupeLayer release];
+ _loupeLayer = nil;
+ }
+ }
+}
+
+- (void)gestureStateChanged
+{
+ switch (self.state) {
+ case UIGestureRecognizerStateBegan:
+ // Stop cursor blinking, and show the loupe
+ _originalCursorFlashTime = QGuiApplication::styleHints()->cursorFlashTime();
+ QGuiApplication::styleHints()->setCursorFlashTime(0);
+ if (!_loupeLayer)
+ [self createLoupe];
+ [self updateFocalPoint:fromCGPoint(_lastTouchPoint)];
+ _loupeLayer.visible = YES;
+ break;
+ case UIGestureRecognizerStateChanged:
+ // Tell the sub class to move the loupe to the correct position
+ [self updateFocalPoint:fromCGPoint(_lastTouchPoint)];
+ break;
+ case UIGestureRecognizerStateEnded:
+ // Restore cursor blinking, and hide the loupe
+ QGuiApplication::styleHints()->setCursorFlashTime(_originalCursorFlashTime);
+ QIOSTextInputOverlay::s_editMenu.visible = YES;
+ _loupeLayer.visible = NO;
+ break;
+ default:
+ _loupeLayer.visible = NO;
+ break;
+ }
+}
+
+- (void)createLoupe
+{
+ // We magnify the the desktop view. But the loupe itself will be added as a child
+ // of the desktop view's parent, so it doesn't become a part of what we magnify.
+ _loupeLayer = [[self createLoupeLayer] retain];
+ _loupeLayer.targetView = _desktopView;
+ [_desktopView.superview.layer addSublayer:_loupeLayer];
+}
+
+- (QPointF)focalPoint
+{
+ return fromCGPoint([_loupeLayer.targetView convertPoint:_loupeLayer.focalPoint toView:_focusView]);
+}
+
+- (void)setFocalPoint:(QPointF)point
+{
+ _loupeLayer.focalPoint = [_loupeLayer.targetView convertPoint:toCGPoint(point) fromView:_focusView];
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ [super touchesBegan:touches withEvent:event];
+ if ([event allTouches].count > 1) {
+ // We only support text selection with one finger
+ self.state = UIGestureRecognizerStateFailed;
+ return;
+ }
+
+ _firstTouchPoint = [static_cast<UITouch *>([touches anyObject]) locationInView:_focusView];
+ _lastTouchPoint = _firstTouchPoint;
+
+ // If the touch point is accepted by the sub class (e.g touch on cursor), we start a
+ // press'n'hold timer that eventually will move the state to UIGestureRecognizerStateBegan.
+ if ([self acceptTouchesBegan:fromCGPoint(_firstTouchPoint)])
+ _triggerStateBeganTimer.start();
+ else
+ self.state = UIGestureRecognizerStateFailed;
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ [super touchesMoved:touches withEvent:event];
+ _lastTouchPoint = [static_cast<UITouch *>([touches anyObject]) locationInView:_focusView];
+
+ if (self.state == UIGestureRecognizerStatePossible) {
+ // If the touch was moved too far before the timer triggered (meaning that this
+ // is a drag, not a press'n'hold), we should either fail, or trigger the gesture
+ // immediately, depending on self.dragTriggersGesture.
+ int startDragDistance = QGuiApplication::styleHints()->startDragDistance();
+ int dragDistance = hypot(_firstTouchPoint.x - _lastTouchPoint.x, _firstTouchPoint.y - _lastTouchPoint.y);
+ if (dragDistance > startDragDistance) {
+ _triggerStateBeganTimer.stop();
+ self.state = self.dragTriggersGesture ? UIGestureRecognizerStateBegan : UIGestureRecognizerStateFailed;
+ }
+ } else {
+ self.state = UIGestureRecognizerStateChanged;
+ }
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ [super touchesEnded:touches withEvent:event];
+ _triggerStateBeganTimer.stop();
+ _lastTouchPoint = [static_cast<UITouch *>([touches anyObject]) locationInView:_focusView];
+ self.state = self.state == UIGestureRecognizerStatePossible ? UIGestureRecognizerStateFailed : UIGestureRecognizerStateEnded;
+}
+
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ [super touchesCancelled:touches withEvent:event];
+ _triggerStateBeganTimer.stop();
+ _lastTouchPoint = [static_cast<UITouch *>([touches anyObject]) locationInView:_focusView];
+ self.state = UIGestureRecognizerStateCancelled;
+}
+
+// Methods implemented by subclasses:
+
+- (BOOL)acceptTouchesBegan:(QPointF)touchPoint
+{
+ Q_UNUSED(touchPoint)
+ Q_UNREACHABLE();
+ return NO;
+}
+
+- (QIOSLoupeLayer *)createLoupeLayer
+{
+ Q_UNREACHABLE();
+ return Q_NULLPTR;
+}
+
+- (void)updateFocalPoint:(QPointF)touchPoint
+{
+ Q_UNUSED(touchPoint)
+ Q_UNREACHABLE();
+}
+
+@end
+
+// -------------------------------------------------------------------------
+
+/**
+ This recognizer will be active when there's no selection. It will trigger if
+ the user does a press and hold, which will start a session where the user can move
+ the cursor around with his finger together with a magnifier glass.
+ */
+@interface QIOSCursorRecognizer : QIOSLoupeRecognizer
+@end
+
+@implementation QIOSCursorRecognizer
+
+- (QIOSLoupeLayer *)createLoupeLayer
+{
+ return [[[QIOSLoupeLayer alloc] initWithSize:CGSizeMake(120, 120) cornerRadius:60 bottomOffset:4] autorelease];
+}
+
+- (BOOL)acceptTouchesBegan:(QPointF)touchPoint
+{
+ QRectF inputRect = QGuiApplication::inputMethod()->inputItemClipRectangle();
+ return !hasSelection() && inputRect.contains(touchPoint);
+}
+
+- (void)updateFocalPoint:(QPointF)touchPoint
+{
+ platformInputContext()->setSelectionOnFocusObject(touchPoint, touchPoint);
+ self.focalPoint = touchPoint;
+}
+
+@end
+
+// -------------------------------------------------------------------------
+
+/**
+ This recognizer will watch for selections, and draw handles as overlay
+ on the sides. If the user starts dragging on a handle (or do a press and
+ hold), it will show a magnifier glass that follows the handle as it moves.
+ */
+@interface QIOSSelectionRecognizer : QIOSLoupeRecognizer {
+ CALayer *_clipRectLayer;
+ QIOSHandleLayer *_cursorLayer;
+ QIOSHandleLayer *_anchorLayer;
+ QPointF _touchOffset;
+ bool _dragOnCursor;
+ bool _multiLine;
+ QTimer _updateSelectionTimer;
+ QMetaObject::Connection _cursorConnection;
+ QMetaObject::Connection _anchorConnection;
+ QMetaObject::Connection _clipRectConnection;
+}
+@end
+
+@implementation QIOSSelectionRecognizer
+
+- (id)init
+{
+ if (self = [super init]) {
+ self.delaysTouchesBegan = YES;
+ self.dragTriggersGesture = YES;
+ _multiLine = QInputMethod::queryFocusObject(Qt::ImHints, QVariant()).toUInt() & Qt::ImhMultiLine;
+ _updateSelectionTimer.setInterval(1);
+ _updateSelectionTimer.setSingleShot(true);
+ QObject::connect(&_updateSelectionTimer, &QTimer::timeout, [self](){ [self updateSelection]; });
+ }
+
+ return self;
+}
+
+- (void)setEnabled:(BOOL)enabled
+{
+ if (enabled == self.enabled)
+ return;
+
+ [super setEnabled:enabled];
+
+ if (enabled) {
+ // Create a layer that clips the handles inside the input field
+ _clipRectLayer = [[CALayer new] autorelease];
+ _clipRectLayer.masksToBounds = YES;
+ [self.focusView.layer addSublayer:_clipRectLayer];
+
+ // Create the handle layers, and add them to the clipped input rect layer
+ _cursorLayer = [[[QIOSHandleLayer alloc] initWithKnobAtEdge:Qt::RightEdge] autorelease];
+ _anchorLayer = [[[QIOSHandleLayer alloc] initWithKnobAtEdge:Qt::LeftEdge] autorelease];
+ bool selection = hasSelection();
+ _cursorLayer.visible = selection;
+ _anchorLayer.visible = selection;
+ [_clipRectLayer addSublayer:_cursorLayer];
+ [_clipRectLayer addSublayer:_anchorLayer];
+
+ // iOS text input will sometimes set a temporary text selection to perform operations
+ // such as backspace (select last character + cut selection). To avoid briefly showing
+ // the selection handles for such cases, and to avoid calling updateSelection when
+ // both handles and clip rectangle change, we use a timer to wait a cycle before we update.
+ // (Note that since QTimer::start is overloaded, we need some extra syntax for the connections).
+ QInputMethod *im = QGuiApplication::inputMethod();
+ void(QTimer::*start)(void) = &QTimer::start;
+ _cursorConnection = QObject::connect(im, &QInputMethod::cursorRectangleChanged, &_updateSelectionTimer, start);
+ _anchorConnection = QObject::connect(im, &QInputMethod::anchorRectangleChanged, &_updateSelectionTimer, start);
+ _clipRectConnection = QObject::connect(im, &QInputMethod::inputItemClipRectangleChanged, &_updateSelectionTimer, start);
+
+ [self updateSelection];
+ } else {
+ [_clipRectLayer removeFromSuperlayer];
+ _clipRectLayer = 0;
+ _cursorLayer = 0;
+ _anchorLayer = 0;
+ _updateSelectionTimer.stop();
+
+ QObject::disconnect(_cursorConnection);
+ QObject::disconnect(_anchorConnection);
+ QObject::disconnect(_clipRectConnection);
+ }
+}
+
+- (QIOSLoupeLayer *)createLoupeLayer
+{
+ CGSize loupeSize = CGSizeMake(123, 33);
+ CGSize arrowSize = CGSizeMake(25, 12);
+ CGFloat loupeOffset = arrowSize.height + 20;
+
+ // Create loupe and arrow layers
+ QIOSLoupeLayer *loupeLayer = [[[QIOSLoupeLayer alloc] initWithSize:loupeSize cornerRadius:5 bottomOffset:loupeOffset] autorelease];
+ CAShapeLayer *arrowLayer = [[[CAShapeLayer alloc] init] autorelease];
+
+ // Build a triangular path to both draw and mask the arrow layer as a triangle
+ UIBezierPath *path = [[UIBezierPath new] autorelease];
+ [path moveToPoint:CGPointMake(0, 0)];
+ [path addLineToPoint:CGPointMake(arrowSize.width / 2, arrowSize.height)];
+ [path addLineToPoint:CGPointMake(arrowSize.width, 0)];
+
+ arrowLayer.frame = CGRectMake((loupeSize.width - arrowSize.width) / 2, loupeSize.height - 1, arrowSize.width, arrowSize.height);
+ arrowLayer.path = path.CGPath;
+ arrowLayer.backgroundColor = [[UIColor whiteColor] CGColor];
+ arrowLayer.strokeColor = [[UIColor lightGrayColor] CGColor];
+ arrowLayer.lineWidth = 0.75 * 2;
+ arrowLayer.fillColor = nil;
+
+ CAShapeLayer *mask = [[CAShapeLayer new] autorelease];
+ mask.frame = arrowLayer.bounds;
+ mask.path = path.CGPath;
+ arrowLayer.mask = mask;
+
+ [loupeLayer addSublayer:arrowLayer];
+
+ return loupeLayer;
+}
+
+- (BOOL)acceptTouchesBegan:(QPointF)touchPoint
+{
+ if (!hasSelection())
+ return NO;
+
+ // Accept the touch if it "overlaps" with any of the handles
+ const int handleRadius = 50;
+ QPointF cursorCenter = qApp->inputMethod()->cursorRectangle().center();
+ QPointF anchorCenter = qApp->inputMethod()->anchorRectangle().center();
+ QPointF cursorOffset = QPointF(cursorCenter.x() - touchPoint.x(), cursorCenter.y() - touchPoint.y());
+ QPointF anchorOffset = QPointF(anchorCenter.x() - touchPoint.x(), anchorCenter.y() - touchPoint.y());
+ double cursorDist = hypot(cursorOffset.x(), cursorOffset.y());
+ double anchorDist = hypot(anchorOffset.x(), anchorOffset.y());
+
+ if (cursorDist > handleRadius && anchorDist > handleRadius)
+ return NO;
+
+ if (cursorDist < anchorDist) {
+ _touchOffset = cursorOffset;
+ _dragOnCursor = YES;
+ } else {
+ _touchOffset = anchorOffset;
+ _dragOnCursor = NO;
+ }
+
+ return YES;
+}
+
+- (void)updateFocalPoint:(QPointF)touchPoint
+{
+ touchPoint += _touchOffset;
+
+ // Get the text position under the touch
+ SelectionPair selection = querySelection();
+ const QTransform mapToLocal = QGuiApplication::inputMethod()->inputItemTransform().inverted();
+ int touchTextPos = QInputMethod::queryFocusObject(Qt::ImCursorPosition, touchPoint * mapToLocal).toInt();
+
+ // Ensure that the handels cannot be dragged past each other
+ if (_dragOnCursor)
+ selection.second = (touchTextPos > selection.first) ? touchTextPos : selection.first + 1;
+ else
+ selection.first = (touchTextPos < selection.second) ? touchTextPos : selection.second - 1;
+
+ // Set new selection
+ QList<QInputMethodEvent::Attribute> imAttributes;
+ imAttributes.append(QInputMethodEvent::Attribute(
+ QInputMethodEvent::Selection, selection.first, selection.second - selection.first, QVariant()));
+ QInputMethodEvent event(QString(), imAttributes);
+ QGuiApplication::sendEvent(qApp->focusObject(), &event);
+
+ // Move loupe to new position
+ QRectF handleRect = _dragOnCursor ?
+ qApp->inputMethod()->cursorRectangle() :
+ qApp->inputMethod()->anchorRectangle();
+ self.focalPoint = QPointF(touchPoint.x(), handleRect.center().y());
+}
+
+- (void)updateSelection
+{
+ if (!hasSelection()) {
+ _cursorLayer.visible = NO;
+ _anchorLayer.visible = NO;
+ QIOSTextInputOverlay::s_editMenu.visible = NO;
+ return;
+ }
+
+ if (!_cursorLayer.visible && QIOSTextInputOverlay::s_editMenu.isHiding) {
+ // Since the edit menu is hiding and this is the first selection thereafter, we
+ // assume that the selection came from the user tapping on a menu item. In that
+ // case, we reshow the menu after it has closed (but then with selection based
+ // menu items, as specified by first responder).
+ QIOSTextInputOverlay::s_editMenu.reshowAfterHidden = YES;
+ }
+
+ // Adjust handles and input rect to match the new selection
+ QRectF inputRect = QGuiApplication::inputMethod()->inputItemClipRectangle();
+ CGRect cursorRect = toCGRect(QGuiApplication::inputMethod()->cursorRectangle());
+ CGRect anchorRect = toCGRect(QGuiApplication::inputMethod()->anchorRectangle());
+
+ if (!_multiLine) {
+ // Resize the layer a bit bigger to ensure that the handles are
+ // not cut if if they are otherwise visible inside the clip rect.
+ int margin = kKnobWidth + 5;
+ inputRect.adjust(-margin / 2, -margin, margin / 2, margin);
+ }
+
+ executeBlockWithoutAnimation(^{ _clipRectLayer.frame = toCGRect(inputRect); });
+ _cursorLayer.cursorRectangle = [self.focusView.layer convertRect:cursorRect toLayer:_clipRectLayer];
+ _anchorLayer.cursorRectangle = [self.focusView.layer convertRect:anchorRect toLayer:_clipRectLayer];
+ _cursorLayer.visible = YES;
+ _anchorLayer.visible = YES;
+}
+
+@end
+
+// -------------------------------------------------------------------------
+
+/**
+ This recognizer will trigger if the user taps inside the edit rectangle.
+ If there's no selection, and the tap doesn't change the cursor position, the
+ visibility of the edit menu will be toggled. Otherwise, if there's a selection, a
+ first tap will close the edit menu (if any), and a second tap will remove the selection.
+ */
+@interface QIOSTapRecognizer : UITapGestureRecognizer {
+ int _cursorPosOnPress;
+ UIView *_focusView;
+}
+@end
+
+@implementation QIOSTapRecognizer
+
+- (id)init
+{
+ if (self = [super initWithTarget:self action:@selector(gestureStateChanged)]) {
+ self.enabled = NO;
+ }
+
+ return self;
+}
+
+- (void)setEnabled:(BOOL)enabled
+{
+ if (enabled == self.enabled)
+ return;
+
+ [super setEnabled:enabled];
+
+ if (enabled) {
+ _focusView = [reinterpret_cast<UIView *>(qApp->focusWindow()->winId()) retain];
+ [_focusView addGestureRecognizer:self];
+ } else {
+ [_focusView removeGestureRecognizer:self];
+ [_focusView release];
+ _focusView = nil;
+ }
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ [super touchesBegan:touches withEvent:event];
+
+ if (hasSelection() && !QIOSTextInputOverlay::s_editMenu.isHiding) {
+ // If there's a selection and the menu is visible, UIKit will hide the menu on the
+ // first tap. But if we get a second tap while the menu is hidden, we choose to diverge
+ // a bit from native behavior and instead fail the tap and forward the touch
+ // to Qt. This will effectively move the cursor (and remove the selection).
+ // This is needed to ensure that the user can remove the selection at any time, but
+ // at the same time, also be able to tap on other items in the UI while keeping the
+ // selection (e.g make the selection bold by tapping on a bold button in the UI).
+ self.state = UIGestureRecognizerStateFailed;
+ return;
+ }
+
+ QRectF inputRect = QGuiApplication::inputMethod()->inputItemClipRectangle();
+ QPointF touchPos = fromCGPoint([static_cast<UITouch *>([touches anyObject]) locationInView:_focusView]);
+ if (!inputRect.contains(touchPos))
+ self.state = UIGestureRecognizerStateFailed;
+
+ _cursorPosOnPress = QInputMethod::queryFocusObject(Qt::ImCursorPosition, QVariant()).toInt();
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ QPointF touchPos = fromCGPoint([static_cast<UITouch *>([touches anyObject]) locationInView:_focusView]);
+ const QTransform mapToLocal = QGuiApplication::inputMethod()->inputItemTransform().inverted();
+ int cursorPosOnRelease = QInputMethod::queryFocusObject(Qt::ImCursorPosition, touchPos * mapToLocal).toInt();
+
+ if (!QIOSTextInputOverlay::s_editMenu.isHiding && cursorPosOnRelease != _cursorPosOnPress) {
+ // We also want to track if the user taps on the screen to close the edit menu. And
+ // the way we detect that is to check if the edit menu is hiding when we receive this
+ // call. If that's the case, we leave the state as-is to allow a tap to be recognized.
+ // Otherwise, if we also see that the cursor will change position, we fail, so that
+ // touch events for Qt are not cancelled.
+ self.state = UIGestureRecognizerStateFailed;
+ }
+
+ [super touchesEnded:touches withEvent:event];
+}
+
+- (void)gestureStateChanged
+{
+ if (self.state != UIGestureRecognizerStateEnded)
+ return;
+
+ if (QIOSTextInputOverlay::s_editMenu.isHiding) {
+ // Closing the menu is what we want for the first tap, so just return
+ return;
+ }
+
+ QIOSTextInputOverlay::s_editMenu.visible = !QIOSTextInputOverlay::s_editMenu.visible;
+}
+
+@end
+
+// -------------------------------------------------------------------------
+
+QT_BEGIN_NAMESPACE
+
+QIOSEditMenu *QIOSTextInputOverlay::s_editMenu = Q_NULLPTR;
+
+QIOSTextInputOverlay::QIOSTextInputOverlay()
+ : m_cursorRecognizer(Q_NULLPTR)
+ , m_selectionRecognizer(Q_NULLPTR)
+ , m_openMenuOnTapRecognizer(Q_NULLPTR)
+{
+ connect(qApp, &QGuiApplication::focusObjectChanged, this, &QIOSTextInputOverlay::updateFocusObject);
+}
+
+QIOSTextInputOverlay::~QIOSTextInputOverlay()
+{
+ disconnect(qApp, 0, this, 0);
+}
+
+void QIOSTextInputOverlay::updateFocusObject()
+{
+ if (m_cursorRecognizer) {
+ // Destroy old recognizers since they were created with
+ // dependencies to the old focus object (focus view).
+ m_cursorRecognizer.enabled = NO;
+ m_selectionRecognizer.enabled = NO;
+ m_openMenuOnTapRecognizer.enabled = NO;
+ [m_cursorRecognizer release];
+ [m_selectionRecognizer release];
+ [m_openMenuOnTapRecognizer release];
+ [s_editMenu release];
+ m_cursorRecognizer = Q_NULLPTR;
+ m_selectionRecognizer = Q_NULLPTR;
+ m_openMenuOnTapRecognizer = Q_NULLPTR;
+ s_editMenu = Q_NULLPTR;
+ }
+
+ if (platformInputContext()->inputMethodAccepted()) {
+ s_editMenu = [QIOSEditMenu new];
+ m_cursorRecognizer = [QIOSCursorRecognizer new];
+ m_selectionRecognizer = [QIOSSelectionRecognizer new];
+ m_openMenuOnTapRecognizer = [QIOSTapRecognizer new];
+ m_cursorRecognizer.enabled = YES;
+ m_selectionRecognizer.enabled = YES;
+ m_openMenuOnTapRecognizer.enabled = YES;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index 6a66bf213e..eb12739e98 100644
--- a/src/plugins/platforms/ios/qiostextresponder.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -324,7 +324,7 @@
// a regular responder transfer to another window. In the former case, iOS
// will set the new first-responder to our next-responder, and in the latter
// case we'll have an active responder candidate.
- if (![UIResponder currentFirstResponder]) {
+ if (![UIResponder currentFirstResponder] && !FirstResponderCandidate::currentCandidate()) {
// No first responder set anymore, sync this with Qt by clearing the
// focus object.
m_inputContext->clearCurrentFocusObject();
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
index 025dc22111..f0c29130f8 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
@@ -263,15 +263,15 @@ static int openTtyDevice(const QString &device)
return fd;
}
-static bool switchToGraphicsMode(int ttyfd, int *oldMode)
+static void switchToGraphicsMode(int ttyfd, bool doSwitch, int *oldMode)
{
- ioctl(ttyfd, KDGETMODE, oldMode);
- if (*oldMode != KD_GRAPHICS) {
- if (ioctl(ttyfd, KDSETMODE, KD_GRAPHICS) != 0)
- return false;
+ // Do not warn if the switch fails: the ioctl fails when launching from a
+ // remote console and there is nothing we can do about it. The matching
+ // call in resetTty should at least fail then, too, so we do no harm.
+ if (ioctl(ttyfd, KDGETMODE, oldMode) == 0) {
+ if (doSwitch && *oldMode != KD_GRAPHICS)
+ ioctl(ttyfd, KDSETMODE, KD_GRAPHICS);
}
-
- return true;
}
static void resetTty(int ttyfd, int oldMode)
@@ -287,14 +287,16 @@ static void blankScreen(int fd, bool on)
}
QLinuxFbScreen::QLinuxFbScreen(const QStringList &args)
- : mArgs(args), mFbFd(-1), mBlitter(0)
+ : mArgs(args), mFbFd(-1), mTtyFd(-1), mBlitter(0)
{
+ mMmap.data = 0;
}
QLinuxFbScreen::~QLinuxFbScreen()
{
if (mFbFd != -1) {
- munmap(mMmap.data - mMmap.offset, mMmap.size);
+ if (mMmap.data)
+ munmap(mMmap.data - mMmap.offset, mMmap.size);
close(mFbFd);
}
@@ -394,11 +396,7 @@ bool QLinuxFbScreen::initialize()
if (mTtyFd == -1)
qErrnoWarning(errno, "Failed to open tty");
- if (doSwitchToGraphicsMode)
- switchToGraphicsMode(mTtyFd, &mOldTtyMode);
- // Do not warn if the switch fails: the ioctl fails when launching from
- // a remote console and there is nothing we can do about it.
-
+ switchToGraphicsMode(mTtyFd, doSwitchToGraphicsMode, &mOldTtyMode);
blankScreen(mFbFd, false);
return true;
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
index f34649e327..5ba49a8a98 100644
--- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp
+++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
@@ -45,6 +45,7 @@
#include <QtGui/qaccessible.h>
#include <QtGui/qclipboard.h>
#include <QtGui/qguiapplication.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtCore/qdebug.h>
#include <algorithm>
@@ -607,7 +608,8 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_keyBinding(long actionIndex
// The IDL documents that the client must free with CoTaskMemFree
arrayOfBindingsToReturn = coTaskMemAllocArray<BSTR>(numBindings);
std::transform(keyBindings.constBegin(), keyBindings.constEnd(),
- arrayOfBindingsToReturn, QStringToBSTR);
+ QT_MAKE_CHECKED_ARRAY_ITERATOR(arrayOfBindingsToReturn, numBindings),
+ QStringToBSTR);
}
}
*keyBindings = arrayOfBindingsToReturn;
@@ -666,9 +668,11 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locationInParent(long *x, l
QAccessibleInterface *parentIface = accessible->parent();
if (parentIface && parentIface->isValid())
topLeft -= parentIface->rect().topLeft();
+ const QPoint nativeTopLeft = QHighDpi::toNativeLocalPosition(topLeft, accessible->window());
- *x = topLeft.x();
- *y = topLeft.y();
+
+ *x = nativeTopLeft.x();
+ *y = nativeTopLeft.y();
return S_OK;
}
@@ -989,7 +993,8 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedColumns(long **sele
*selectedColumns = Q_NULLPTR;
if (count) {
*selectedColumns = coTaskMemAllocArray<long>(count);
- std::copy(selectedIndices.constBegin(), selectedIndices.constEnd(), *selectedColumns);
+ std::copy(selectedIndices.constBegin(), selectedIndices.constEnd(),
+ QT_MAKE_CHECKED_ARRAY_ITERATOR(*selectedColumns, count));
}
return count ? S_OK : S_FALSE;
}
@@ -1011,7 +1016,8 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedRows(long **selecte
*selectedRows = Q_NULLPTR;
if (count) {
*selectedRows = coTaskMemAllocArray<long>(count);
- std::copy(selectedIndices.constBegin(), selectedIndices.constEnd(), *selectedRows);
+ std::copy(selectedIndices.constBegin(), selectedIndices.constEnd(),
+ QT_MAKE_CHECKED_ARRAY_ITERATOR(*selectedRows, count));
}
return count ? S_OK : S_FALSE;
}
@@ -1680,7 +1686,8 @@ HRESULT QWindowsIA2Accessible::wrapListOfCells(const QList<QAccessibleInterface*
if (count) {
*outputAccessibles = coTaskMemAllocArray<IUnknown *>(count);
std::transform(inputCells.constBegin(), inputCells.constEnd(),
- *outputAccessibles, QWindowsAccessibility::wrap);
+ QT_MAKE_CHECKED_ARRAY_ITERATOR(*outputAccessibles, count),
+ QWindowsAccessibility::wrap);
}
return count > 0 ? S_OK : S_FALSE;
}
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
index 0fff804e29..5fb06a6ed1 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
@@ -55,6 +55,7 @@
#include <QtGui/qguiapplication.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/qwindow.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
//#include <uiautomationcoreapi.h>
#ifndef UiaRootObjectId
@@ -503,7 +504,8 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accHitTest(long xLeft, long yT
if (!accessible)
return E_FAIL;
- QAccessibleInterface *child = accessible->childAt(xLeft, yTop);
+ const QPoint pos = QHighDpi::fromNativeLocalPosition(QPoint(xLeft, yTop), accessible->window());
+ QAccessibleInterface *child = accessible->childAt(pos.x(), pos.y());
if (child == 0) {
// no child found, return this item if it contains the coordinates
if (accessible->rect().contains(xLeft, yTop)) {
@@ -545,7 +547,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accLocation(long *pxLeft, long
QAccessibleInterface *acc = childPointer(accessible, varID);
if (!acc || !acc->isValid())
return E_FAIL;
- const QRect rect = acc->rect();
+ const QRect rect = QHighDpi::toNativePixels(acc->rect(), accessible->window());
*pxLeft = rect.x();
*pyTop = rect.y();
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp
index 96cabb20e4..23a6f35576 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp
@@ -556,7 +556,7 @@ QFunctionPointer QWindowsEGLContext::getProcAddress(const char *procName)
// return a function pointer for standard GLES2 functions too. These are not
// guaranteed to be queryable via eglGetProcAddress().
if (!procAddress) {
-#if defined(QT_STATIC)
+#if defined(QT_STATIC) && !defined(QT_OPENGL_DYNAMIC)
static struct StdFunc {
const char *name;
void *func;
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
index ddadbbea5d..8adbd494c4 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
@@ -650,7 +650,7 @@ int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv)
reconv->dwTargetStrOffset = reconv->dwCompStrOffset;
ushort *pastReconv = reinterpret_cast<ushort *>(reconv + 1);
std::copy(surroundingText.utf16(), surroundingText.utf16() + surroundingText.size(),
- pastReconv);
+ QT_MAKE_UNCHECKED_ARRAY_ITERATOR(pastReconv));
return memSize;
}
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index b2fde7a0c6..8a229db812 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -371,13 +371,11 @@ QWindowsWindow *QWindowsIntegration::createPlatformWindowHelper(QWindow *window,
QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate()
{
#if defined(QT_OPENGL_DYNAMIC)
- const QWindowsOpenGLTester::Renderers supportedRenderers = QWindowsOpenGLTester::supportedRenderers();
-
QWindowsOpenGLTester::Renderer requestedRenderer = QWindowsOpenGLTester::requestedRenderer();
switch (requestedRenderer) {
case QWindowsOpenGLTester::DesktopGl:
if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) {
- if ((supportedRenderers & QWindowsOpenGLTester::DisableRotationFlag)
+ if ((QWindowsOpenGLTester::supportedRenderers() & QWindowsOpenGLTester::DisableRotationFlag)
&& !QWindowsScreen::setOrientationPreference(Qt::LandscapeOrientation)) {
qCWarning(lcQpaGl, "Unable to disable rotation.");
}
@@ -403,6 +401,7 @@ QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate()
break;
}
+ const QWindowsOpenGLTester::Renderers supportedRenderers = QWindowsOpenGLTester::supportedRenderers();
if (supportedRenderers & QWindowsOpenGLTester::DesktopGl) {
if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) {
if ((supportedRenderers & QWindowsOpenGLTester::DisableRotationFlag)
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index 046c32a80a..a9307f79fb 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -484,11 +484,8 @@ static QPixmap loadIconFromShell32(int resourceId, QSizeF size)
return QPixmap();
}
-QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
+QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSize) const
{
- const QScreen *primaryScreen = QGuiApplication::primaryScreen();
- const int scaleFactor = primaryScreen ? qRound(QHighDpiScaling::factor(primaryScreen)) : 1;
- const QSizeF pixmapSize = size * scaleFactor;
int resourceId = -1;
SHSTOCKICONID stockId = SIID_INVALID;
UINT stockFlags = 0;
@@ -584,7 +581,6 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) con
stockFlags |= (pixmapSize.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON);
if (SHGetStockIconInfo(stockId, SHGFI_ICON | stockFlags, &iconInfo) == S_OK) {
pixmap = qt_pixmapFromWinHICON(iconInfo.hIcon);
- pixmap.setDevicePixelRatio(scaleFactor);
DestroyIcon(iconInfo.hIcon);
return pixmap;
}
@@ -598,7 +594,6 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) con
QPixmap link = loadIconFromShell32(30, pixmapSize);
painter.drawPixmap(0, 0, int(pixmapSize.width()), int(pixmapSize.height()), link);
}
- pixmap.setDevicePixelRatio(scaleFactor);
return pixmap;
}
}
@@ -606,13 +601,12 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) con
if (iconName) {
HICON iconHandle = LoadIcon(NULL, iconName);
QPixmap pixmap = qt_pixmapFromWinHICON(iconHandle);
- pixmap.setDevicePixelRatio(scaleFactor);
DestroyIcon(iconHandle);
if (!pixmap.isNull())
return pixmap;
}
- return QPlatformTheme::standardPixmap(sp, size);
+ return QPlatformTheme::standardPixmap(sp, pixmapSize);
}
enum { // Shell image list ids
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index c369bafafc..4aa6eaea4a 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -432,6 +432,8 @@ static inline void fixTopLevelWindowFlags(Qt::WindowFlags &flags)
default:
break;
}
+ if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
+ flags |= Qt::FramelessWindowHint;
}
void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flagsIn,
diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp
index fc5cabc033..5c3ecd8726 100644
--- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp
+++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp
@@ -138,6 +138,7 @@ void QWinRTEGLContext::initialize()
EGL_CONTEXT_CLIENT_VERSION, d->format.majorVersion(),
EGL_CONTEXT_MINOR_VERSION_KHR, d->format.minorVersion(),
EGL_CONTEXT_FLAGS_KHR, flags,
+ EGL_CONTEXT_OPENGL_NO_ERROR_KHR, true,
EGL_NONE
};
d->eglContext = eglCreateContext(g->eglDisplay, d->eglConfig, d->eglShareContext, attributes);
diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.cpp b/src/plugins/platforms/winrt/qwinrtfileengine.cpp
index ad81ef4f5f..53e7ebd30d 100644
--- a/src/plugins/platforms/winrt/qwinrtfileengine.cpp
+++ b/src/plugins/platforms/winrt/qwinrtfileengine.cpp
@@ -466,14 +466,20 @@ qint64 QWinRTFileEngine::read(char *data, qint64 maxlen)
hr = stream->ReadAsync(buffer.Get(), length, InputStreamOptions_None, &op);
RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
- hr = QWinRTFunctions::await(op, buffer.GetAddressOf());
+ // Quoting MSDN IInputStream::ReadAsync() documentation:
+ // "Depending on the implementation, the data that's read might be placed
+ // into the input buffer, or it might be returned in a different buffer."
+ // Using GetAddressOf can cause ref counting errors leaking the original
+ // buffer.
+ ComPtr<IBuffer> effectiveBuffer;
+ hr = QWinRTFunctions::await(op, effectiveBuffer.GetAddressOf());
RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
- hr = buffer->get_Length(&length);
+ hr = effectiveBuffer->get_Length(&length);
RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
- hr = buffer.As(&byteArrayAccess);
+ hr = effectiveBuffer.As(&byteArrayAccess);
RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
byte *bytes;
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp
index 562372d0b8..aed33f6b48 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.cpp
+++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp
@@ -88,9 +88,9 @@ typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler;
typedef ITypedEventHandler<CoreWindow*, WindowSizeChangedEventArgs*> SizeChangedHandler;
typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler;
typedef ITypedEventHandler<DisplayInformation*, IInspectable*> DisplayInformationHandler;
-#ifdef Q_OS_WINPHONE
-typedef ITypedEventHandler<StatusBar*, IInspectable*> StatusBarHandler;
-#endif
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+typedef ITypedEventHandler<ApplicationView*, IInspectable*> VisibleBoundsChangedHandler;
+#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
QT_BEGIN_NAMESPACE
@@ -451,10 +451,10 @@ typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistr
uint qHash(CoreWindowCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
typedef HRESULT (__stdcall IDisplayInformation::*DisplayCallbackRemover)(EventRegistrationToken);
uint qHash(DisplayCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
-#ifdef Q_OS_WINPHONE
-typedef HRESULT (__stdcall IStatusBar::*StatusBarCallbackRemover)(EventRegistrationToken);
-uint qHash(StatusBarCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
-#endif
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+typedef HRESULT (__stdcall IApplicationView2::*ApplicationView2CallbackRemover)(EventRegistrationToken);
+uint qHash(ApplicationView2CallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
+#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
class QWinRTScreenPrivate
{
@@ -464,13 +464,11 @@ public:
ComPtr<Xaml::IDependencyObject> canvas;
ComPtr<IApplicationView> view;
ComPtr<IDisplayInformation> displayInformation;
-#ifdef Q_OS_WINPHONE
- ComPtr<IStatusBar> statusBar;
-#endif
QScopedPointer<QWinRTCursor> cursor;
QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints;
- QSizeF logicalSize;
+ QRectF logicalRect;
+ QRectF visibleRect;
QSurfaceFormat surfaceFormat;
qreal logicalDpi;
QDpi physicalDpi;
@@ -481,9 +479,10 @@ public:
QHash<Qt::Key, KeyInfo> activeKeys;
QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens;
QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens;
-#ifdef Q_OS_WINPHONE
- QHash<StatusBarCallbackRemover, EventRegistrationToken> statusBarTokens;
-#endif
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+ QHash<ApplicationView2CallbackRemover, EventRegistrationToken> view2Tokens;
+ ComPtr<IApplicationView2> view2;
+#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
};
// To be called from the XAML thread
@@ -514,7 +513,8 @@ QWinRTScreen::QWinRTScreen()
Rect rect;
hr = d->coreWindow->get_Bounds(&rect);
Q_ASSERT_SUCCEEDED(hr);
- d->logicalSize = QSizeF(rect.Width, rect.Height);
+ d->logicalRect = QRectF(0.0f, 0.0f, rect.Width, rect.Height);
+ d->visibleRect = QRectF(0.0f, 0.0f, rect.Width, rect.Height);
// Orientation handling
ComPtr<IDisplayInformationStatics> displayInformationStatics;
@@ -549,9 +549,9 @@ QWinRTScreen::QWinRTScreen()
ComPtr<Xaml::IFrameworkElement> frameworkElement;
hr = canvas.As(&frameworkElement);
Q_ASSERT_SUCCEEDED(hr);
- hr = frameworkElement->put_Width(d->logicalSize.width());
+ hr = frameworkElement->put_Width(d->logicalRect.width());
Q_ASSERT_SUCCEEDED(hr);
- hr = frameworkElement->put_Height(d->logicalSize.height());
+ hr = frameworkElement->put_Height(d->logicalRect.height());
Q_ASSERT_SUCCEEDED(hr);
ComPtr<Xaml::IUIElement> uiElement;
hr = canvas.As(&uiElement);
@@ -563,14 +563,10 @@ QWinRTScreen::QWinRTScreen()
d->cursor.reset(new QWinRTCursor);
-#ifdef Q_OS_WINPHONE
- ComPtr<IStatusBarStatics> statusBarStatics;
- hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_StatusBar).Get(),
- IID_PPV_ARGS(&statusBarStatics));
- Q_ASSERT_SUCCEEDED(hr);
- hr = statusBarStatics->GetForCurrentView(&d->statusBar);
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+ hr = d->view.As(&d->view2);
Q_ASSERT_SUCCEEDED(hr);
-#endif // Q_OS_WINPHONE
+#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
}
QWinRTScreen::~QWinRTScreen()
@@ -590,12 +586,12 @@ QWinRTScreen::~QWinRTScreen()
hr = (d->displayInformation.Get()->*i.key())(i.value());
Q_ASSERT_SUCCEEDED(hr);
}
-#ifdef Q_OS_WINPHONE
- for (QHash<StatusBarCallbackRemover, EventRegistrationToken>::const_iterator i = d->statusBarTokens.begin(); i != d->statusBarTokens.end(); ++i) {
- hr = (d->statusBar.Get()->*i.key())(i.value());
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+ for (QHash<ApplicationView2CallbackRemover, EventRegistrationToken>::const_iterator i = d->view2Tokens.begin(); i != d->view2Tokens.end(); ++i) {
+ hr = (d->view2.Get()->*i.key())(i.value());
Q_ASSERT_SUCCEEDED(hr);
}
-#endif //Q_OS_WINPHONE
+#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
return hr;
});
RETURN_VOID_IF_FAILED("Failed to unregister screen event callbacks");
@@ -604,33 +600,17 @@ QWinRTScreen::~QWinRTScreen()
QRect QWinRTScreen::geometry() const
{
Q_D(const QWinRTScreen);
- return QRect(QPoint(), (d->logicalSize * d->scaleFactor).toSize());
+ return QRect(QPoint(), QSizeF(d->logicalRect.size() * d->scaleFactor).toSize());
}
-#ifdef Q_OS_WINPHONE
QRect QWinRTScreen::availableGeometry() const
{
Q_D(const QWinRTScreen);
- QRect statusBar;
- QEventDispatcherWinRT::runOnXamlThread([d, &statusBar]() {
- HRESULT hr;
- Rect rect;
- hr = d->statusBar->get_OccludedRect(&rect);
- Q_ASSERT_SUCCEEDED(hr);
- statusBar.setRect(qRound(rect.X * d->scaleFactor),
- qRound(rect.Y * d->scaleFactor),
- qRound(rect.Width * d->scaleFactor),
- qRound(rect.Height * d->scaleFactor));
- return S_OK;
- });
-
- return geometry().adjusted(
- d->orientation == Qt::LandscapeOrientation ? statusBar.width() : 0,
- d->orientation == Qt::PortraitOrientation ? statusBar.height() : 0,
- d->orientation == Qt::InvertedLandscapeOrientation ? -statusBar.width() : 0,
- 0);
+ return QRectF((d->visibleRect.x() - d->logicalRect.x())* d->scaleFactor,
+ (d->visibleRect.y() - d->logicalRect.y()) * d->scaleFactor,
+ d->visibleRect.width() * d->scaleFactor,
+ d->visibleRect.height() * d->scaleFactor).toRect();
}
-#endif //Q_OS_WINPHONE
int QWinRTScreen::depth() const
{
@@ -645,8 +625,8 @@ QImage::Format QWinRTScreen::format() const
QSizeF QWinRTScreen::physicalSize() const
{
Q_D(const QWinRTScreen);
- return QSizeF(d->logicalSize.width() * d->scaleFactor / d->physicalDpi.first * qreal(25.4),
- d->logicalSize.height() * d->scaleFactor / d->physicalDpi.second * qreal(25.4));
+ return QSizeF(d->logicalRect.width() * d->scaleFactor / d->physicalDpi.first * qreal(25.4),
+ d->logicalRect.height() * d->scaleFactor / d->physicalDpi.second * qreal(25.4));
}
QDpi QWinRTScreen::logicalDpi() const
@@ -723,29 +703,6 @@ Xaml::IDependencyObject *QWinRTScreen::canvas() const
return d->canvas.Get();
}
-#ifdef Q_OS_WINPHONE
-void QWinRTScreen::setStatusBarVisibility(bool visible, QWindow *window)
-{
- Q_D(QWinRTScreen);
- qCDebug(lcQpaWindows) << __FUNCTION__ << window << visible;
-
- const Qt::WindowFlags windowType = window->flags() & Qt::WindowType_Mask;
- if (!window || (windowType != Qt::Window && windowType != Qt::Dialog))
- return;
-
- QEventDispatcherWinRT::runOnXamlThread([d, visible]() {
- HRESULT hr;
- ComPtr<IAsyncAction> op;
- if (visible)
- hr = d->statusBar->ShowAsync(&op);
- else
- hr = d->statusBar->HideAsync(&op);
- Q_ASSERT_SUCCEEDED(hr);
- return S_OK;
- });
-}
-#endif //Q_OS_WINPHONE
-
void QWinRTScreen::initialize()
{
Q_D(QWinRTScreen);
@@ -768,15 +725,14 @@ void QWinRTScreen::initialize()
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]);
Q_ASSERT_SUCCEEDED(hr);
-#ifndef Q_OS_WINPHONE
- hr = d->coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]);
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+ hr = d->view2->add_VisibleBoundsChanged(Callback<VisibleBoundsChangedHandler>(this, &QWinRTScreen::onWindowSizeChanged).Get(), &d->view2Tokens[&IApplicationView2::remove_VisibleBoundsChanged]);
Q_ASSERT_SUCCEEDED(hr);
#else
- hr = d->statusBar->add_Showing(Callback<StatusBarHandler>(this, &QWinRTScreen::onStatusBarShowing).Get(), &d->statusBarTokens[&IStatusBar::remove_Showing]);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->statusBar->add_Hiding(Callback<StatusBarHandler>(this, &QWinRTScreen::onStatusBarHiding).Get(), &d->statusBarTokens[&IStatusBar::remove_Hiding]);
- Q_ASSERT_SUCCEEDED(hr);
-#endif
+ hr = d->coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onWindowSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]);
+ Q_ASSERT_SUCCEEDED(hr)
+#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+
hr = d->coreWindow->add_Activated(Callback<ActivatedHandler>(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_Closed(Callback<ClosedHandler>(this, &QWinRTScreen::onClosed).Get(), &d->windowTokens[&ICoreWindow::remove_Closed]);
@@ -804,11 +760,6 @@ void QWinRTScreen::addWindow(QWindow *window)
if (window == topWindow())
return;
-#ifdef Q_OS_WINPHONE
- if (window->visibility() != QWindow::Maximized && window->visibility() != QWindow::Windowed)
- setStatusBarVisibility(false, window);
-#endif
-
d->visibleWindows.prepend(window);
QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason);
handleExpose();
@@ -820,11 +771,6 @@ void QWinRTScreen::removeWindow(QWindow *window)
Q_D(QWinRTScreen);
qCDebug(lcQpaWindows) << __FUNCTION__ << window;
-#ifdef Q_OS_WINPHONE
- if (window->visibility() == QWindow::Minimized)
- setStatusBarVisibility(false, window);
-#endif
-
const bool wasTopWindow = window == topWindow();
if (!d->visibleWindows.removeAll(window))
return;
@@ -1009,8 +955,20 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args)
return S_OK;
}
-HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *)
+HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args)
{
+ Q_D(QWinRTScreen);
+
+ ComPtr<IPointerPoint> pointerPoint;
+ if (FAILED(args->get_CurrentPoint(&pointerPoint)))
+ return E_INVALIDARG;
+
+ quint32 id;
+ if (FAILED(pointerPoint->get_PointerId(&id)))
+ return E_INVALIDARG;
+
+ d->touchPoints.remove(id);
+
QWindowSystemInterface::handleLeaveEvent(0);
return S_OK;
}
@@ -1094,6 +1052,7 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
break;
}
+ case PointerDeviceType_Pen:
case PointerDeviceType_Touch: {
if (!d->touchDevice) {
d->touchDevice = new QTouchDevice;
@@ -1112,51 +1071,45 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
float pressure;
properties->get_Pressure(&pressure);
- QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator it = d->touchPoints.find(id);
- if (it != d->touchPoints.end()) {
- boolean isPressed;
+ boolean isPressed;
#ifndef Q_OS_WINPHONE
- pointerPoint->get_IsInContact(&isPressed);
+ pointerPoint->get_IsInContact(&isPressed);
#else
- properties->get_IsLeftButtonPressed(&isPressed); // IsInContact not reliable on phone
+ properties->get_IsLeftButtonPressed(&isPressed); // IsInContact not reliable on phone
#endif
- it.value().state = isPressed ? Qt::TouchPointMoved : Qt::TouchPointReleased;
- } else {
+
+ const QRectF areaRect(area.X * d->scaleFactor, area.Y * d->scaleFactor,
+ area.Width * d->scaleFactor, area.Height * d->scaleFactor);
+
+ QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator it = d->touchPoints.find(id);
+ if (it == d->touchPoints.end()) {
it = d->touchPoints.insert(id, QWindowSystemInterface::TouchPoint());
- it.value().state = Qt::TouchPointPressed;
it.value().id = id;
}
- it.value().area = QRectF(area.X * d->scaleFactor, area.Y * d->scaleFactor,
- area.Width * d->scaleFactor, area.Height * d->scaleFactor);
- it.value().normalPosition = QPointF(point.X/d->logicalSize.width(), point.Y/d->logicalSize.height());
- it.value().pressure = pressure;
- QWindowSystemInterface::handleTouchEvent(topWindow(), d->touchDevice, d->touchPoints.values(), mods);
+ if (isPressed && it.value().pressure == 0.)
+ it.value().state = Qt::TouchPointPressed;
+ else if (!isPressed && it.value().pressure > 0.)
+ it.value().state = Qt::TouchPointReleased;
+ else if (it.value().area == areaRect)
+ it.value().state = Qt::TouchPointStationary;
+ else
+ it.value().state = Qt::TouchPointMoved;
- // Remove released points, station others
- for (QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator i = d->touchPoints.begin(); i != d->touchPoints.end();) {
- if (i.value().state == Qt::TouchPointReleased)
- i = d->touchPoints.erase(i);
- else
- (i++).value().state = Qt::TouchPointStationary;
- }
+ it.value().area = areaRect;
+ it.value().normalPosition = QPointF(point.X/d->logicalRect.width(), point.Y/d->logicalRect.height());
+ it.value().pressure = pressure;
- break;
- }
- case PointerDeviceType_Pen: {
- quint32 id;
- pointerPoint->get_PointerId(&id);
+ QWindowSystemInterface::handleTouchEvent(topWindow(), d->touchDevice, d->touchPoints.values(), mods);
- boolean isPressed;
- pointerPoint->get_IsInContact(&isPressed);
+ // Fall-through for pen to generate tablet event
+ if (pointerDeviceType != PointerDeviceType_Pen)
+ break;
boolean isEraser;
properties->get_IsEraser(&isEraser);
int pointerType = isEraser ? 3 : 1;
- float pressure;
- properties->get_Pressure(&pressure);
-
float xTilt;
properties->get_XTilt(&xTilt);
@@ -1177,22 +1130,6 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
return S_OK;
}
-HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *)
-{
- Q_D(QWinRTScreen);
-
- Rect size;
- HRESULT hr;
- hr = d->coreWindow->get_Bounds(&size);
- RETURN_OK_IF_FAILED("Failed to get window bounds");
- d->logicalSize = QSizeF(size.Width, size.Height);
- qCDebug(lcQpaWindows) << __FUNCTION__ << d->logicalSize;
- QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
- QPlatformScreen::resizeMaximizedWindows();
- handleExpose();
- return S_OK;
-}
-
HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args)
{
Q_D(QWinRTScreen);
@@ -1205,6 +1142,8 @@ HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args
return S_OK;
}
+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
+
// Activate topWindow
if (!d->visibleWindows.isEmpty()) {
Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated
@@ -1231,8 +1170,10 @@ HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *, IVisibilityChangedEvent
RETURN_OK_IF_FAILED("Failed to get visibility.");
qCDebug(lcQpaWindows) << __FUNCTION__ << visible;
QWindowSystemInterface::handleApplicationStateChanged(visible ? Qt::ApplicationActive : Qt::ApplicationHidden);
- if (visible)
+ if (visible) {
handleExpose();
+ onWindowSizeChanged(nullptr, nullptr);
+ }
return S_OK;
}
@@ -1248,9 +1189,7 @@ HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable *
if (d->orientation != newOrientation) {
d->orientation = newOrientation;
qCDebug(lcQpaWindows) << " New orientation:" << newOrientation;
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
- onSizeChanged(nullptr, nullptr);
-#endif
+ onWindowSizeChanged(nullptr, nullptr);
QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation);
handleExpose(); // Clean broken frames caused by race between Qt and ANGLE
}
@@ -1294,20 +1233,35 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *)
return S_OK;
}
-#ifdef Q_OS_WINPHONE
-HRESULT QWinRTScreen::onStatusBarShowing(IStatusBar *, IInspectable *)
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *, IInspectable *)
+#else
+HRESULT QWinRTScreen::onWindowSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *)
+#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
{
- qCDebug(lcQpaWindows) << __FUNCTION__;
- onSizeChanged(nullptr, nullptr);
- return S_OK;
-}
+ Q_D(QWinRTScreen);
-HRESULT QWinRTScreen::onStatusBarHiding(IStatusBar *, IInspectable *)
-{
- qCDebug(lcQpaWindows) << __FUNCTION__;
- onSizeChanged(nullptr, nullptr);
+ HRESULT hr;
+ Rect windowSize;
+
+ hr = d->coreWindow->get_Bounds(&windowSize);
+ RETURN_OK_IF_FAILED("Failed to get window bounds");
+ d->logicalRect = QRectF(windowSize.X, windowSize.Y, windowSize.Width, windowSize.Height);
+
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+ Rect visibleRect;
+ hr = d->view2->get_VisibleBounds(&visibleRect);
+ RETURN_OK_IF_FAILED("Failed to get window visible bounds");
+ d->visibleRect = QRectF(visibleRect.X, visibleRect.Y, visibleRect.Width, visibleRect.Height);
+#else
+ d->visibleRect = QRectF(windowSize.X, windowSize.Y, windowSize.Width, windowSize.Height);
+#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+
+ qCDebug(lcQpaWindows) << __FUNCTION__ << d->logicalRect;
+ QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
+ QPlatformScreen::resizeMaximizedWindows();
+ handleExpose();
return S_OK;
}
-#endif //Q_OS_WINPHONE
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h
index bfab1e8385..5cada9726d 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.h
+++ b/src/plugins/platforms/winrt/qwinrtscreen.h
@@ -65,7 +65,7 @@ namespace ABI {
struct IWindow;
}
namespace ViewManagement {
- struct IStatusBar;
+ struct IApplicationView;
}
}
namespace Graphics {
@@ -88,10 +88,9 @@ class QWinRTScreen : public QPlatformScreen
public:
explicit QWinRTScreen();
~QWinRTScreen();
+
QRect geometry() const Q_DECL_OVERRIDE;
-#ifdef Q_OS_WINPHONE
QRect availableGeometry() const Q_DECL_OVERRIDE;
-#endif
int depth() const Q_DECL_OVERRIDE;
QImage::Format format() const Q_DECL_OVERRIDE;
QSizeF physicalSize() const Q_DECL_OVERRIDE;
@@ -115,10 +114,6 @@ public:
ABI::Windows::UI::Core::ICoreWindow *coreWindow() const;
ABI::Windows::UI::Xaml::IDependencyObject *canvas() const;
-#ifdef Q_OS_WINPHONE
- void setStatusBarVisibility(bool visible, QWindow *window);
-#endif
-
void initialize();
private:
@@ -130,7 +125,6 @@ private:
HRESULT onPointerEntered(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *);
HRESULT onPointerExited(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *);
HRESULT onPointerUpdated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *);
- HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *);
HRESULT onActivated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowActivatedEventArgs *);
@@ -139,10 +133,10 @@ private:
HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *);
HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *);
-
-#ifdef Q_OS_WINPHONE
- HRESULT onStatusBarShowing(ABI::Windows::UI::ViewManagement::IStatusBar *, IInspectable *);
- HRESULT onStatusBarHiding(ABI::Windows::UI::ViewManagement::IStatusBar *, IInspectable *);
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+ HRESULT onWindowSizeChanged(ABI::Windows::UI::ViewManagement::IApplicationView *, IInspectable *);
+#else
+ HRESULT onWindowSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *);
#endif
QScopedPointer<QWinRTScreenPrivate> d_ptr;
diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp
index 9df087c055..3cae53d0a0 100644
--- a/src/plugins/platforms/winrt/qwinrtwindow.cpp
+++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp
@@ -42,7 +42,6 @@
#include <private/qeventdispatcher_winrt_p.h>
#include <EGL/egl.h>
-#define EGL_EGLEXT_PROTOTYPES
#include <EGL/eglext.h>
#include <qfunctions_winrt.h>
@@ -322,10 +321,6 @@ void QWinRTWindow::setWindowState(Qt::WindowState state)
if (d->state == state)
return;
-#ifdef Q_OS_WINPHONE
- d->screen->setStatusBarVisibility(state == Qt::WindowMaximized || state == Qt::WindowNoState, window());
-#endif
-
if (state == Qt::WindowMinimized)
setUIElementVisibility(d->uiElement.Get(), false);
diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro
index 261295ef0b..144c581015 100644
--- a/src/plugins/platforms/winrt/winrt.pro
+++ b/src/plugins/platforms/winrt/winrt.pro
@@ -4,7 +4,7 @@ CONFIG -= precompile_header
QT += core-private gui-private platformsupport-private
-DEFINES *= QT_NO_CAST_FROM_ASCII __WRL_NO_DEFAULT_LIB__ GL_GLEXT_PROTOTYPES
+DEFINES *= QT_NO_CAST_FROM_ASCII __WRL_NO_DEFAULT_LIB__
LIBS += $$QMAKE_LIBS_CORE -ldwrite -ld3d11
INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/freetype/include
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 2925917562..130ae9be0c 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -525,28 +525,36 @@ void QXcbBackingStore::beginPaint(const QRegion &region)
if (!m_image)
return;
- m_paintRegion = region;
- m_image->preparePaint(m_paintRegion);
+ m_paintRegions.push(region);
+ m_image->preparePaint(region);
if (m_image->hasAlpha()) {
QPainter p(paintDevice());
p.setCompositionMode(QPainter::CompositionMode_Source);
const QColor blank = Qt::transparent;
- for (const QRect &rect : m_paintRegion)
+ for (const QRect &rect : region)
p.fillRect(rect, blank);
}
}
void QXcbBackingStore::endPaint()
{
+ if (Q_UNLIKELY(m_paintRegions.isEmpty())) {
+ qWarning("%s: paint regions empty!", Q_FUNC_INFO);
+ return;
+ }
+
+ const QRegion region = m_paintRegions.pop();
+ m_image->preparePaint(region);
+
QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window()->handle());
if (!platformWindow || !platformWindow->imageNeedsRgbSwap())
return;
// Slow path: the paint device was m_rgbImage. Now copy with swapping red
// and blue into m_image.
- auto it = m_paintRegion.begin();
- const auto end = m_paintRegion.end();
+ auto it = region.begin();
+ const auto end = region.end();
if (it == end)
return;
QPainter p(m_image->image());
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h
index 4b8c040729..6af679d28a 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.h
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.h
@@ -41,6 +41,7 @@
#define QXCBBACKINGSTORE_H
#include <qpa/qplatformbackingstore.h>
+#include <QtCore/QStack>
#include <xcb/xcb.h>
@@ -75,7 +76,7 @@ public:
private:
QXcbShmImage *m_image;
- QRegion m_paintRegion;
+ QStack<QRegion> m_paintRegions;
QImage m_rgbImage;
};
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index cb222842db..87b4c7b91f 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -166,9 +166,9 @@ static int ioErrorHandler(Display *dpy)
}
#endif
-QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc)
+QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const
{
- foreach (QXcbScreen *screen, m_screens) {
+ for (QXcbScreen *screen : m_screens) {
if (screen->root() == rootWindow && screen->crtc() == crtc)
return screen;
}
@@ -176,9 +176,9 @@ QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr
return 0;
}
-QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output)
+QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) const
{
- foreach (QXcbScreen *screen, m_screens) {
+ for (QXcbScreen *screen : m_screens) {
if (screen->root() == rootWindow && screen->output() == output)
return screen;
}
@@ -186,9 +186,9 @@ QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_ran
return 0;
}
-QXcbVirtualDesktop* QXcbConnection::virtualDesktopForRootWindow(xcb_window_t rootWindow)
+QXcbVirtualDesktop* QXcbConnection::virtualDesktopForRootWindow(xcb_window_t rootWindow) const
{
- foreach (QXcbVirtualDesktop *virtualDesktop, m_virtualDesktops) {
+ for (QXcbVirtualDesktop *virtualDesktop : m_virtualDesktops) {
if (virtualDesktop->screen()->root == rootWindow)
return virtualDesktop;
}
@@ -215,6 +215,9 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
// CRTC with node mode could mean that output has been disabled, and we'll
// get RRNotifyOutputChange notification for that.
if (screen && crtc.mode) {
+ if (crtc.rotation == XCB_RANDR_ROTATION_ROTATE_90 ||
+ crtc.rotation == XCB_RANDR_ROTATION_ROTATE_270)
+ std::swap(crtc.width, crtc.height);
screen->updateGeometry(QRect(crtc.x, crtc.y, crtc.width, crtc.height), crtc.rotation);
if (screen->mode() != crtc.mode)
screen->updateRefreshRate(crtc.mode);
@@ -242,7 +245,8 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
xcb_randr_get_output_info_reply(xcb_connection(), outputInfoCookie, NULL));
// Find a fake screen
- foreach (QPlatformScreen *scr, virtualDesktop->screens()) {
+ const auto scrs = virtualDesktop->screens();
+ for (QPlatformScreen *scr : scrs) {
QXcbScreen *xcbScreen = (QXcbScreen *)scr;
if (xcbScreen->output() == XCB_NONE) {
screen = xcbScreen;
@@ -284,7 +288,7 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
}
}
- qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name();
+ qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name();
}
}
@@ -319,7 +323,7 @@ void QXcbConnection::updateScreen(QXcbScreen *screen, const xcb_randr_output_cha
// If the screen became primary, reshuffle the order in QGuiApplicationPrivate
const int idx = m_screens.indexOf(screen);
if (idx > 0) {
- m_screens.first()->setPrimary(false);
+ qAsConst(m_screens).first()->setPrimary(false);
m_screens.swap(0, idx);
}
screen->virtualDesktop()->setPrimaryScreen(screen);
@@ -339,7 +343,7 @@ QXcbScreen *QXcbConnection::createScreen(QXcbVirtualDesktop *virtualDesktop,
if (screen->isPrimary()) {
if (!m_screens.isEmpty())
- m_screens.first()->setPrimary(false);
+ qAsConst(m_screens).first()->setPrimary(false);
m_screens.prepend(screen);
} else {
@@ -518,7 +522,7 @@ void QXcbConnection::initializeScreens()
++xcbScreenNumber;
} // for each xcb screen
- foreach (QXcbVirtualDesktop *virtualDesktop, m_virtualDesktops)
+ for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops))
virtualDesktop->subscribeToXFixesSelectionNotify();
if (m_virtualDesktops.isEmpty()) {
@@ -526,19 +530,19 @@ void QXcbConnection::initializeScreens()
} else {
// Ensure the primary screen is first on the list
if (primaryScreen) {
- if (m_screens.first() != primaryScreen) {
+ if (qAsConst(m_screens).first() != primaryScreen) {
m_screens.removeOne(primaryScreen);
m_screens.prepend(primaryScreen);
}
}
// Push the screens to QGuiApplication
- foreach (QXcbScreen *screen, m_screens) {
+ for (QXcbScreen *screen : qAsConst(m_screens)) {
qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")";
QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary());
}
- qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name();
+ qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name();
}
}
@@ -563,6 +567,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
, m_buttons(0)
, m_focusWindow(0)
, m_mouseGrabber(0)
+ , m_mousePressWindow(0)
, m_clientLeader(0)
, m_systemTrayTracker(0)
, m_glIntegration(Q_NULLPTR)
@@ -1010,8 +1015,8 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error)
}
}
if (i == m_callLog.size() && !m_callLog.isEmpty())
- qDebug("Caused some time after: %s:%d", m_callLog.first().file.constData(),
- m_callLog.first().line);
+ qDebug("Caused some time after: %s:%d", qAsConst(m_callLog).first().file.constData(),
+ qAsConst(m_callLog).first().line);
#endif
}
@@ -1231,7 +1236,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
#ifndef QT_NO_CLIPBOARD
m_clipboard->handleXFixesSelectionRequest(notify_event);
#endif
- foreach (QXcbVirtualDesktop *virtualDesktop, m_virtualDesktops)
+ for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops))
virtualDesktop->handleXFixesSelectionNotify(notify_event);
handled = true;
@@ -1240,7 +1245,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
handled = true;
} else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
xcb_randr_screen_change_notify_event_t *change_event = (xcb_randr_screen_change_notify_event_t *)event;
- foreach (QXcbScreen *s, m_screens) {
+ for (QXcbScreen *s : qAsConst(m_screens)) {
if (s->root() == change_event->root )
s->handleScreenChange(change_event);
}
@@ -1375,6 +1380,11 @@ void QXcbConnection::setFocusWindow(QXcbWindow *w)
void QXcbConnection::setMouseGrabber(QXcbWindow *w)
{
m_mouseGrabber = w;
+ m_mousePressWindow = Q_NULLPTR;
+}
+void QXcbConnection::setMousePressWindow(QXcbWindow *w)
+{
+ m_mousePressWindow = w;
}
void QXcbConnection::grabServer()
@@ -1628,8 +1638,13 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex,
if (!m_xi2Enabled)
return false;
- // compress XI_Motion
+ // compress XI_Motion, but not from tablet devices
if (isXIType(event, m_xiOpCode, XI_Motion)) {
+#ifndef QT_NO_TABLETEVENT
+ xXIDeviceEvent *xdev = reinterpret_cast<xXIDeviceEvent *>(event);
+ if (const_cast<QXcbConnection *>(this)->tabletDataForDevice(xdev->sourceid))
+ return false;
+#endif // QT_NO_TABLETEVENT
for (int j = nextIndex; j < eventqueue->size(); ++j) {
xcb_generic_event_t *next = eventqueue->at(j);
if (!isValid(next))
@@ -1726,7 +1741,7 @@ void QXcbConnection::processXcbEvents()
// Indicate with a null event that the event the callbacks are waiting for
// is not in the queue currently.
- Q_FOREACH (PeekFunc f, m_peekFuncs)
+ for (PeekFunc f : qAsConst(m_peekFuncs))
f(this, 0);
m_peekFuncs.clear();
@@ -2248,7 +2263,7 @@ bool QXcbConnection::xi2MouseEvents() const
#endif
#if defined(XCB_USE_XINPUT2)
-static int xi2ValuatorOffset(unsigned char *maskPtr, int maskLen, int number)
+static int xi2ValuatorOffset(const unsigned char *maskPtr, int maskLen, int number)
{
int offset = 0;
for (int i = 0; i < maskLen; i++) {
@@ -2267,11 +2282,11 @@ static int xi2ValuatorOffset(unsigned char *maskPtr, int maskLen, int number)
return -1;
}
-bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value)
+bool QXcbConnection::xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value)
{
- xXIDeviceEvent *xideviceevent = static_cast<xXIDeviceEvent *>(event);
- unsigned char *buttonsMaskAddr = (unsigned char*)&xideviceevent[1];
- unsigned char *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4;
+ const xXIDeviceEvent *xideviceevent = static_cast<const xXIDeviceEvent *>(event);
+ const unsigned char *buttonsMaskAddr = (const unsigned char*)&xideviceevent[1];
+ const unsigned char *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4;
FP3232 *valuatorsValuesAddr = (FP3232*)(valuatorsMaskAddr + xideviceevent->valuators_len * 4);
int valuatorOffset = xi2ValuatorOffset(valuatorsMaskAddr, xideviceevent->valuators_len, valuatorNum);
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 9fed7b52f1..891f0fbcb5 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -481,6 +481,8 @@ public:
void setFocusWindow(QXcbWindow *);
QXcbWindow *mouseGrabber() const { return m_mouseGrabber; }
void setMouseGrabber(QXcbWindow *);
+ QXcbWindow *mousePressWindow() const { return m_mousePressWindow; }
+ void setMousePressWindow(QXcbWindow *);
QByteArray startupId() const { return m_startupId; }
void setStartupId(const QByteArray &nextId) { m_startupId = nextId; }
@@ -533,9 +535,9 @@ private:
void initializeXShape();
void initializeXKB();
void handleClientMessageEvent(const xcb_client_message_event_t *event);
- QXcbScreen* findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc);
- QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output);
- QXcbVirtualDesktop* virtualDesktopForRootWindow(xcb_window_t rootWindow);
+ QXcbScreen* findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const;
+ QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) const;
+ QXcbVirtualDesktop* virtualDesktopForRootWindow(xcb_window_t rootWindow) const;
void updateScreens(const xcb_randr_notify_event_t *event);
bool checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output);
void updateScreen(QXcbScreen *screen, const xcb_randr_output_change_t &outputChange);
@@ -579,9 +581,10 @@ private:
};
QHash<int, ValuatorClassInfo> valuatorInfo;
};
- bool xi2HandleTabletEvent(void *event, TabletData *tabletData, QXcbWindowEventListener *eventListener);
- void xi2ReportTabletEvent(TabletData &tabletData, void *event);
+ bool xi2HandleTabletEvent(const void *event, TabletData *tabletData);
+ void xi2ReportTabletEvent(const void *event, TabletData *tabletData);
QVector<TabletData> m_tabletData;
+ TabletData *tabletDataForDevice(int id);
#endif // !QT_NO_TABLETEVENT
struct ScrollingDevice {
ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0), legacyOrientations(0) { }
@@ -596,7 +599,7 @@ private:
void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice);
QHash<int, ScrollingDevice> m_scrollingDevices;
- static bool xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value);
+ static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value);
static void xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event);
#endif
@@ -668,6 +671,7 @@ private:
QXcbWindow *m_focusWindow;
QXcbWindow *m_mouseGrabber;
+ QXcbWindow *m_mousePressWindow;
xcb_window_t m_clientLeader;
QByteArray m_startupId;
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 63a650a514..5b7f45fb6c 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -42,7 +42,7 @@
#include "qxcbscreen.h"
#include "qxcbwindow.h"
#include "qtouchdevice.h"
-#include <qpa/qwindowsysteminterface.h>
+#include <qpa/qwindowsysteminterface_p.h>
#include <QDebug>
#include <cmath>
@@ -119,7 +119,7 @@ void QXcbConnection::xi2SetupDevices()
// Only non-master pointing devices are relevant here.
if (devices[i].use != XISlavePointer)
continue;
- qCDebug(lcQpaXInputDevices) << "input device "<< devices[i].name;
+ qCDebug(lcQpaXInputDevices) << "input device " << devices[i].name << "ID" << devices[i].deviceid;
#ifndef QT_NO_TABLETEVENT
TabletData tabletData;
#endif
@@ -274,7 +274,7 @@ void QXcbConnection::xi2SetupDevices()
void QXcbConnection::finalizeXInput2()
{
- foreach (XInput2TouchDeviceData *dev, m_touchDevices) {
+ for (XInput2TouchDeviceData *dev : qAsConst(m_touchDevices)) {
if (dev->xiDeviceInfo)
XIFreeDeviceInfo(dev->xiDeviceInfo);
delete dev;
@@ -313,12 +313,13 @@ void QXcbConnection::xi2Select(xcb_window_t window)
mask.mask_len = sizeof(bitMask);
mask.mask = xiBitMask;
// When xi2MouseEvents() is true (the default), pointer emulation for touch and tablet
- // events will get disabled. This is preferable for touch, as Qt Quick handles touch events
- // directly while for others QtGui synthesizes mouse events, not so much for tablets. For
- // the latter we will synthesize the events ourselves.
+ // events will get disabled. This is preferable, as Qt Quick handles touch events
+ // directly, while for other applications QtGui synthesizes mouse events.
mask.deviceid = XIAllMasterDevices;
Status result = XISelectEvents(xDisplay, window, &mask, 1);
- if (result != Success)
+ if (result == Success)
+ QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
+ else
qCDebug(lcQpaXInput, "XInput 2.2: failed to select pointer/touch events, window %x, result %d", window, result);
}
@@ -358,7 +359,7 @@ void QXcbConnection::xi2Select(xcb_window_t window)
scrollBitMask = XI_MotionMask;
scrollBitMask |= XI_ButtonReleaseMask;
int i=0;
- Q_FOREACH (const ScrollingDevice& scrollingDevice, m_scrollingDevices) {
+ for (const ScrollingDevice& scrollingDevice : qAsConst(m_scrollingDevices)) {
if (tabletDevices.contains(scrollingDevice.deviceId))
continue; // All necessary events are already captured.
xiEventMask[i].deviceid = scrollingDevice.deviceId;
@@ -536,12 +537,9 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
#ifndef QT_NO_TABLETEVENT
if (!xiEnterEvent) {
- for (int i = 0; i < m_tabletData.count(); ++i) {
- if (m_tabletData.at(i).deviceId == sourceDeviceId) {
- if (xi2HandleTabletEvent(xiEvent, &m_tabletData[i], eventListener))
- return;
- }
- }
+ QXcbConnection::TabletData *tablet = tabletDataForDevice(sourceDeviceId);
+ if (tablet && xi2HandleTabletEvent(xiEvent, tablet))
+ return;
}
#endif // QT_NO_TABLETEVENT
@@ -832,9 +830,8 @@ void QXcbConnection::xi2HandleHierachyEvent(void *event)
return;
xi2SetupDevices();
// Reselect events for all event-listening windows.
- Q_FOREACH (xcb_window_t window, m_mapper.keys()) {
- xi2Select(window);
- }
+ for (auto it = m_mapper.cbegin(), end = m_mapper.cend(); it != end; ++it)
+ xi2Select(it.key());
}
void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
@@ -1042,36 +1039,36 @@ static QTabletEvent::TabletDevice toolIdToTabletDevice(quint32 toolId) {
}
#ifndef QT_NO_TABLETEVENT
-bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, QXcbWindowEventListener *eventListener)
+bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletData)
{
bool handled = true;
Display *xDisplay = static_cast<Display *>(m_xlib_display);
- xXIGenericDeviceEvent *xiEvent = static_cast<xXIGenericDeviceEvent *>(event);
- xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(xiEvent);
+ const xXIGenericDeviceEvent *xiEvent = static_cast<const xXIGenericDeviceEvent *>(event);
+ const xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<const xXIDeviceEvent *>(xiEvent);
switch (xiEvent->evtype) {
case XI_ButtonPress: {
Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
tabletData->buttons |= b;
- xi2ReportTabletEvent(*tabletData, xiEvent);
+ xi2ReportTabletEvent(xiEvent, tabletData);
break;
}
case XI_ButtonRelease: {
Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
tabletData->buttons ^= b;
- xi2ReportTabletEvent(*tabletData, xiEvent);
+ xi2ReportTabletEvent(xiEvent, tabletData);
break;
}
case XI_Motion:
// Report TabletMove only when the stylus is touching the tablet or any button is pressed.
// TODO: report proximity (hover) motion (no suitable Qt event exists yet).
if (tabletData->buttons != Qt::NoButton)
- xi2ReportTabletEvent(*tabletData, xiEvent);
+ xi2ReportTabletEvent(xiEvent, tabletData);
break;
case XI_PropertyEvent: {
// This is the wacom driver's way of reporting tool proximity.
// The evdev driver doesn't do it this way.
- xXIPropertyEvent *ev = reinterpret_cast<xXIPropertyEvent *>(event);
+ const xXIPropertyEvent *ev = reinterpret_cast<const xXIPropertyEvent *>(event);
if (ev->what == XIPropertyModified) {
if (ev->property == atom(QXcbAtom::WacomSerialIDs)) {
enum WacomSerialIndex {
@@ -1132,21 +1129,12 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, Q
break;
}
-#ifdef XCB_USE_XINPUT22
- // Synthesize mouse events since otherwise there are no mouse events from
- // the pen on the XI 2.2+ path.
- if (xi2MouseEvents() && eventListener)
- eventListener->handleXIMouseEvent(reinterpret_cast<xcb_ge_event_t *>(event), Qt::MouseEventSynthesizedByQt);
-#else
- Q_UNUSED(eventListener);
-#endif
-
return handled;
}
-void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event)
+void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletData)
{
- xXIDeviceEvent *ev = reinterpret_cast<xXIDeviceEvent *>(event);
+ const xXIDeviceEvent *ev = reinterpret_cast<const xXIDeviceEvent *>(event);
QXcbWindow *xcbWindow = platformWindowFromId(ev->event);
if (!xcbWindow)
return;
@@ -1157,8 +1145,8 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event)
double pressure = 0, rotation = 0, tangentialPressure = 0;
int xTilt = 0, yTilt = 0;
- for (QHash<int, TabletData::ValuatorClassInfo>::iterator it = tabletData.valuatorInfo.begin(),
- ite = tabletData.valuatorInfo.end(); it != ite; ++it) {
+ for (QHash<int, TabletData::ValuatorClassInfo>::iterator it = tabletData->valuatorInfo.begin(),
+ ite = tabletData->valuatorInfo.end(); it != ite; ++it) {
int valuator = it.key();
TabletData::ValuatorClassInfo &classInfo(it.value());
xi2GetValuatorValueIfSet(event, classInfo.number, &classInfo.curVal);
@@ -1174,7 +1162,7 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event)
yTilt = classInfo.curVal;
break;
case QXcbAtom::AbsWheel:
- switch (tabletData.tool) {
+ switch (tabletData->tool) {
case QTabletEvent::Airbrush:
tangentialPressure = normalizedValue * 2.0 - 1.0; // Convert 0..1 range to -1..+1 range
break;
@@ -1193,17 +1181,27 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event)
if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled()))
qCDebug(lcQpaXInput, "XI2 event on tablet %d with tool %d type %d seq %d detail %d time %d "
"pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf",
- tabletData.deviceId, tabletData.tool, ev->evtype, ev->sequenceNumber, ev->detail, ev->time,
+ tabletData->deviceId, tabletData->tool, ev->evtype, ev->sequenceNumber, ev->detail, ev->time,
fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y),
fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y),
- (int)tabletData.buttons, pressure, xTilt, yTilt, rotation);
+ (int)tabletData->buttons, pressure, xTilt, yTilt, rotation);
QWindowSystemInterface::handleTabletEvent(window, ev->time, local, global,
- tabletData.tool, tabletData.pointerType,
- tabletData.buttons, pressure,
+ tabletData->tool, tabletData->pointerType,
+ tabletData->buttons, pressure,
xTilt, yTilt, tangentialPressure,
- rotation, 0, tabletData.serialId);
+ rotation, 0, tabletData->serialId);
}
+
+QXcbConnection::TabletData *QXcbConnection::tabletDataForDevice(int id)
+{
+ for (int i = 0; i < m_tabletData.count(); ++i) {
+ if (m_tabletData.at(i).deviceId == id)
+ return &m_tabletData[i];
+ }
+ return Q_NULLPTR;
+}
+
#endif // QT_NO_TABLETEVENT
#endif // XCB_USE_XINPUT2
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
index 0b539a2241..11e0c998b1 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -343,7 +343,7 @@ QXcbCursor::~QXcbCursor()
xcb_close_font(conn, cursorFont);
#ifndef QT_NO_CURSOR
- foreach (xcb_cursor_t cursor, m_cursorHash)
+ for (xcb_cursor_t cursor : qAsConst(m_cursorHash))
xcb_free_cursor(conn, cursor);
#endif
}
@@ -624,7 +624,8 @@ void QXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDes
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()) {
+ const auto virtualDesktops = c->virtualDesktops();
+ for (QXcbVirtualDesktop *vd : virtualDesktops) {
if (vd->root() == reply->root) {
*virtualDesktop = vd;
break;
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index ea20ef7a04..b55fbd8f03 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -1078,6 +1078,40 @@ void QXcbDrag::cancel()
send_leave();
}
+// find an ancestor with XdndAware on it
+static xcb_window_t findXdndAwareParent(QXcbConnection *c, xcb_window_t window)
+{
+ xcb_window_t target = 0;
+ forever {
+ // check if window has XdndAware
+ xcb_get_property_cookie_t gpCookie = Q_XCB_CALL(
+ xcb_get_property(c->xcb_connection(), false, window,
+ c->atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0));
+ xcb_get_property_reply_t *gpReply = xcb_get_property_reply(
+ c->xcb_connection(), gpCookie, 0);
+ bool aware = gpReply && gpReply->type != XCB_NONE;
+ free(gpReply);
+ if (aware) {
+ target = window;
+ break;
+ }
+
+ // try window's parent
+ xcb_query_tree_cookie_t qtCookie = Q_XCB_CALL(
+ xcb_query_tree_unchecked(c->xcb_connection(), window));
+ xcb_query_tree_reply_t *qtReply = xcb_query_tree_reply(
+ c->xcb_connection(), qtCookie, NULL);
+ if (!qtReply)
+ break;
+ xcb_window_t root = qtReply->root;
+ xcb_window_t parent = qtReply->parent;
+ free(qtReply);
+ if (window == root)
+ break;
+ window = parent;
+ }
+ return target;
+}
void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event)
{
@@ -1105,17 +1139,16 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event
// xcb_convert_selection() that we sent the XdndDrop event to.
at = findTransactionByWindow(event->requestor);
}
-// if (at == -1 && event->time == XCB_CURRENT_TIME) {
-// // previous Qt versions always requested the data on a child of the target window
-// // using CurrentTime... but it could be asking for either drop data or the current drag's data
-// Window target = findXdndAwareParent(event->requestor);
-// if (target) {
-// if (current_target && current_target == target)
-// at = -2;
-// else
-// at = findXdndDropTransactionByWindow(target);
-// }
-// }
+
+ if (at == -1) {
+ xcb_window_t target = findXdndAwareParent(connection(), event->requestor);
+ if (target) {
+ if (event->time == XCB_CURRENT_TIME && current_target == target)
+ at = -2;
+ else
+ at = findTransactionByWindow(target);
+ }
+ }
}
QDrag *transactionDrag = 0;
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index b5e03e68fe..703167c0cd 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -250,17 +250,25 @@ QPlatformOffscreenSurface *QXcbIntegration::createPlatformOffscreenSurface(QOffs
bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {
- case ThreadedPixmaps: return true;
- case OpenGL: return m_connections.first()->glIntegration();
- case ThreadedOpenGL: return m_connections.at(0)->threadedEventHandling()
- && m_connections.at(0)->glIntegration()
- && m_connections.at(0)->glIntegration()->supportsThreadedOpenGL();
- case WindowMasks: return true;
- case MultipleWindows: return true;
- case ForeignWindows: return true;
- case SyncState: return true;
- case RasterGLSurface: return true;
- case SwitchableWidgetComposition: return true;
+ case OpenGL:
+ case ThreadedOpenGL:
+ {
+ const auto *connection = qAsConst(m_connections).first();
+ if (const auto *integration = connection->glIntegration())
+ return cap != ThreadedOpenGL
+ || (connection->threadedEventHandling() && integration->supportsThreadedOpenGL());
+ return false;
+ }
+
+ case ThreadedPixmaps:
+ case WindowMasks:
+ case MultipleWindows:
+ case ForeignWindows:
+ case SyncState:
+ case RasterGLSurface:
+ case SwitchableWidgetComposition:
+ return true;
+
default: return QPlatformIntegration::hasCapability(cap);
}
}
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index 48912e0520..7168e6e3bd 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -692,8 +692,8 @@ void QXcbKeyboard::updateKeymap()
if (!xkb_context) {
if (qEnvironmentVariableIsSet("QT_XKB_CONFIG_ROOT")) {
xkb_context = xkb_context_new((xkb_context_flags)XKB_CONTEXT_NO_DEFAULT_INCLUDES);
- QList<QByteArray> xkbRootList = QByteArray(qgetenv("QT_XKB_CONFIG_ROOT")).split(':');
- foreach (const QByteArray &xkbRoot, xkbRootList)
+ const QList<QByteArray> xkbRootList = QByteArray(qgetenv("QT_XKB_CONFIG_ROOT")).split(':');
+ for (const QByteArray &xkbRoot : xkbRootList)
xkb_context_include_path_append(xkb_context, xkbRoot.constData());
} else {
xkb_context = xkb_context_new((xkb_context_flags)0);
@@ -1038,7 +1038,7 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
// catch only more specific shortcuts, i.e. Ctrl+Shift+= also generates Ctrl++ and +,
// but Ctrl++ is more specific than +, so we should skip the last one
bool ambiguous = false;
- foreach (int shortcut, result) {
+ for (int shortcut : qAsConst(result)) {
if (int(shortcut & ~Qt::KeyboardModifierMask) == qtKey && (shortcut & mods) == mods) {
ambiguous = true;
break;
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 4cb1b29152..dc6846b20b 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -76,7 +76,8 @@ QXcbVirtualDesktop::~QXcbVirtualDesktop()
QXcbScreen *QXcbVirtualDesktop::screenAt(const QPoint &pos) const
{
- foreach (QXcbScreen *screen, connection()->screens()) {
+ const auto screens = connection()->screens();
+ for (QXcbScreen *screen : screens) {
if (screen->virtualDesktop() == this && screen->geometry().contains(pos))
return screen;
}
@@ -157,7 +158,7 @@ void QXcbVirtualDesktop::updateWorkArea()
QRect workArea = getWorkArea();
if (m_workArea != workArea) {
m_workArea = workArea;
- foreach (QPlatformScreen *screen, m_screens)
+ for (QPlatformScreen *screen : qAsConst(m_screens))
((QXcbScreen *)screen)->updateAvailableGeometry();
}
}
@@ -386,10 +387,9 @@ QSurfaceFormat QXcbScreen::surfaceFormatFor(const QSurfaceFormat &format) const
const xcb_visualtype_t *QXcbScreen::visualForFormat(const QSurfaceFormat &format) const
{
- QVector<const xcb_visualtype_t *> candidates;
+ const xcb_visualtype_t *candidate = nullptr;
- for (auto ii = m_visuals.constBegin(); ii != m_visuals.constEnd(); ++ii) {
- const xcb_visualtype_t &xcb_visualtype = ii.value();
+ for (const xcb_visualtype_t &xcb_visualtype : m_visuals) {
const int redSize = qPopulationCount(xcb_visualtype.red_mask);
const int greenSize = qPopulationCount(xcb_visualtype.green_mask);
@@ -408,19 +408,17 @@ const xcb_visualtype_t *QXcbScreen::visualForFormat(const QSurfaceFormat &format
if (format.alphaBufferSize() != -1 && alphaSize != format.alphaBufferSize())
continue;
- candidates.append(&xcb_visualtype);
- }
-
- if (candidates.isEmpty())
- return nullptr;
+ // Try to find a RGB visual rather than e.g. BGR or GBR
+ if (qCountTrailingZeroBits(xcb_visualtype.blue_mask) == 0)
+ return &xcb_visualtype;
- // Try to find a RGB visual rather than e.g. BGR or GBR
- for (const xcb_visualtype_t *candidate : qAsConst(candidates))
- if (qCountTrailingZeroBits(candidate->blue_mask) == 0)
- return candidate;
+ // In case we do not find anything we like, just remember the first one
+ // and hope for the best:
+ if (!candidate)
+ candidate = &xcb_visualtype;
+ }
- // Did not find anything we like, just grab the first one and hope for the best
- return candidates.first();
+ return candidate;
}
void QXcbScreen::sendStartupMessage(const QByteArray &message) const
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index b0b21a5be4..17fafd5ef0 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -286,7 +286,7 @@ static inline XTextProperty* qstringToXTP(Display *dpy, const QString& s)
// TODO move this into a utility function in QWindow or QGuiApplication
static QWindow *childWindowAt(QWindow *win, const QPoint &p)
{
- foreach (QObject *obj, win->children()) {
+ for (QObject *obj : win->children()) {
if (obj->isWindowType()) {
QWindow *childWin = static_cast<QWindow *>(obj);
if (childWin->isVisible()) {
@@ -592,8 +592,12 @@ QXcbWindow::~QXcbWindow()
{
if (window()->type() != Qt::ForeignWindow)
destroy();
- else if (connection()->mouseGrabber() == this)
- connection()->setMouseGrabber(Q_NULLPTR);
+ else {
+ if (connection()->mouseGrabber() == this)
+ connection()->setMouseGrabber(Q_NULLPTR);
+ if (connection()->mousePressWindow() == this)
+ connection()->setMousePressWindow(Q_NULLPTR);
+ }
}
void QXcbWindow::destroy()
@@ -851,6 +855,16 @@ void QXcbWindow::hide()
if (connection()->mouseGrabber() == this)
connection()->setMouseGrabber(Q_NULLPTR);
+ if (QPlatformWindow *w = connection()->mousePressWindow()) {
+ // Unset mousePressWindow when it (or one of its parents) is unmapped
+ while (w) {
+ if (w == this) {
+ connection()->setMousePressWindow(Q_NULLPTR);
+ break;
+ }
+ w = w->parent();
+ }
+ }
m_mapped = false;
@@ -864,7 +878,8 @@ void QXcbWindow::hide()
// Find the top level window at cursor position.
// Don't use QGuiApplication::topLevelAt(): search only the virtual siblings of this window's screen
QWindow *enterWindow = Q_NULLPTR;
- foreach (QPlatformScreen *screen, xcbScreen()->virtualSiblings()) {
+ const auto screens = xcbScreen()->virtualSiblings();
+ for (QPlatformScreen *screen : screens) {
if (screen->geometry().contains(cursorPos)) {
const QPoint devicePosition = QHighDpi::toNativePixels(cursorPos, screen->screen());
enterWindow = screen->topLevelAt(devicePosition);
@@ -2198,6 +2213,8 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
return;
}
+ connection()->setMousePressWindow(this);
+
handleMouseEvent(timestamp, local, global, modifiers, source);
}
@@ -2212,19 +2229,44 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x,
return;
}
+ if (connection()->buttons() == Qt::NoButton)
+ connection()->setMousePressWindow(Q_NULLPTR);
+
handleMouseEvent(timestamp, local, global, modifiers, source);
}
-static bool ignoreLeaveEvent(quint8 mode, quint8 detail)
+static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
+{
+ /* Checking for XCB_NOTIFY_MODE_GRAB and XCB_NOTIFY_DETAIL_ANCESTOR prevents unwanted
+ * enter/leave events on AwesomeWM on mouse button press. It also ignores duplicated
+ * enter/leave events on Alt+Tab switching on some WMs with XInput2 events.
+ * Without XInput2 events the (Un)grabAncestor cannot be checked when mouse button is
+ * not pressed, otherwise (e.g. on Alt+Tab) it can igonre important enter/leave events.
+ */
+ if (conn) {
+ const bool mouseButtonsPressed = (conn->buttons() != Qt::NoButton);
+#ifdef XCB_USE_XINPUT22
+ return mouseButtonsPressed || (conn->isAtLeastXI22() && conn->xi2MouseEvents());
+#else
+ return mouseButtonsPressed;
+#endif
+ }
+ return true;
+}
+
+static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR)
{
- return (mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM
+ return ((doCheckUnGrabAncestor(conn)
+ && mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
+ || (mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_INFERIOR)
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL
- || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL;
+ || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
}
-static bool ignoreEnterEvent(quint8 mode, quint8 detail)
+static bool ignoreEnterEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR)
{
- return ((mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM
+ return ((doCheckUnGrabAncestor(conn)
+ && mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
|| (mode != XCB_NOTIFY_MODE_NORMAL && mode != XCB_NOTIFY_MODE_UNGRAB)
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
@@ -2258,9 +2300,7 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in
const QPoint global = QPoint(root_x, root_y);
- if (ignoreEnterEvent(mode, detail)
- || (connection()->buttons() != Qt::NoButton
- && QGuiApplicationPrivate::lastCursorPosition != global))
+ if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow())
return;
const QPoint local(event_x, event_y);
@@ -2272,11 +2312,7 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
{
connection()->setTime(timestamp);
- const QPoint global(root_x, root_y);
-
- if (ignoreLeaveEvent(mode, detail)
- || (connection()->buttons() != Qt::NoButton
- && QGuiApplicationPrivate::lastCursorPosition != global))
+ if (ignoreLeaveEvent(mode, detail, connection()) || connection()->mousePressWindow())
return;
EnterEventChecker checker;
@@ -2299,6 +2335,11 @@ void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, i
{
QPoint local(event_x, event_y);
QPoint global(root_x, root_y);
+
+ // "mousePressWindow" can be NULL i.e. if a window will be grabbed or umnapped, so set it again here
+ if (connection()->buttons() != Qt::NoButton && connection()->mousePressWindow() == Q_NULLPTR)
+ connection()->setMousePressWindow(this);
+
handleMouseEvent(timestamp, local, global, modifiers, source);
}
@@ -2350,7 +2391,7 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource
conn->setButton(conn->translateMouseButton(i), XIMaskIsSet(buttonMask, i));
}
- const char *sourceName = nullptr;
+ const char *sourceName = 0;
if (lcQpaXInput().isDebugEnabled()) {
const QMetaObject *metaObject = qt_getEnumMetaObject(source);
const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(source)));