summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglcontext.cpp34
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglwindow.cpp29
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglwindow.h2
-rw-r--r--src/plugins/platforms/android/qandroidplatformvulkanwindow.h2
-rw-r--r--src/plugins/platforms/android/qandroidplatformwindow.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm22
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.mm17
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm19
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm4
-rw-r--r--src/plugins/platforms/cocoa/qnsview_mouse.mm2
-rw-r--r--src/plugins/platforms/cocoa/qnsview_tablet.mm3
-rw-r--r--src/plugins/platforms/cocoa/qnsview_touch.mm12
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm5
-rw-r--r--src/plugins/platforms/windows/qwindowssystemtrayicon.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp31
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp121
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp16
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp20
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h1
21 files changed, 195 insertions, 156 deletions
diff --git a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp
index faccf8b1173..337dd266fe8 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp
+++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp
@@ -22,17 +22,43 @@ QAndroidPlatformOpenGLContext::QAndroidPlatformOpenGLContext(const QSurfaceForma
void QAndroidPlatformOpenGLContext::swapBuffers(QPlatformSurface *surface)
{
- if (surface->surface()->surfaceClass() == QSurface::Window &&
- static_cast<QAndroidPlatformOpenGLWindow *>(surface)->checkNativeSurface(eglConfig())) {
- QEGLPlatformContext::makeCurrent(surface);
+ if (surface->surface()->surfaceClass() != QSurface::Window) {
+ QEGLPlatformContext::swapBuffers(surface);
+ return;
}
+ QAndroidPlatformOpenGLWindow *window = static_cast<QAndroidPlatformOpenGLWindow *>(surface);
+ // Since QEGLPlatformContext::makeCurrent() and QEGLPlatformContext::swapBuffers()
+ // will be using the eglSurface of the window, which wraps the Android Surface, we
+ // need to lock here to make sure we don't end up using a Surface already destroyed
+ // by Android
+ window->lockSurface();
+
+ if (window->checkNativeSurface(eglConfig())) {
+ // Call base class implementation directly since we are already locked
+ QEGLPlatformContext::makeCurrent(surface);
+ }
QEGLPlatformContext::swapBuffers(surface);
+
+ window->unlockSurface();
}
bool QAndroidPlatformOpenGLContext::makeCurrent(QPlatformSurface *surface)
{
- return QEGLPlatformContext::makeCurrent(surface);
+ if (surface->surface()->surfaceClass() != QSurface::Window)
+ return QEGLPlatformContext::makeCurrent(surface);
+
+ QAndroidPlatformOpenGLWindow *window = static_cast<QAndroidPlatformOpenGLWindow *>(surface);
+ window->lockSurface();
+ // Has the Surface been destroyed?
+ if (window->eglSurface(eglConfig()) == EGL_NO_SURFACE) {
+ qWarning("makeCurrent(): no EGLSurface, likely Surface destroyed by Android.");
+ window->unlockSurface();
+ return false;
+ }
+ const bool ok = QEGLPlatformContext::makeCurrent(surface);
+ window->unlockSurface();
+ return ok;
}
EGLSurface QAndroidPlatformOpenGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
index 8ab95cf8be4..31ca205ace2 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
@@ -32,7 +32,7 @@ QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow()
lockSurface();
if (m_nativeSurfaceId != -1)
QtAndroid::destroySurface(m_nativeSurfaceId);
- clearEgl();
+ clearSurface();
unlockSurface();
}
@@ -81,13 +81,13 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
repaint(QRegion(rect));
}
+// Called by QAndroidPlatformOpenGLContext::eglSurfaceForPlatformSurface(),
+// surface is already locked when calling this
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
{
if (QAndroidEventDispatcherStopper::stopped() || QGuiApplication::applicationState() == Qt::ApplicationSuspended)
return m_eglSurface;
- QMutexLocker lock(&m_surfaceMutex);
-
if (m_nativeSurfaceId == -1) {
AndroidDeadlockProtector protector;
if (!protector.acquire())
@@ -98,17 +98,16 @@ EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
m_surfaceWaitCondition.wait(&m_surfaceMutex);
}
- if (m_eglSurface == EGL_NO_SURFACE) {
- m_surfaceMutex.unlock();
+ if (m_eglSurface == EGL_NO_SURFACE)
checkNativeSurface(config);
- m_surfaceMutex.lock();
- }
+
return m_eglSurface;
}
bool QAndroidPlatformOpenGLWindow::checkNativeSurface(EGLConfig config)
{
- QMutexLocker lock(&m_surfaceMutex);
+ // Either no surface created, or the m_eglSurface already wraps the active Surface
+ // -> makeCurrent is NOT needed.
if (m_nativeSurfaceId == -1 || !m_androidSurfaceObject.isValid())
return false; // makeCurrent is NOT needed.
@@ -130,14 +129,14 @@ void QAndroidPlatformOpenGLWindow::applicationStateChanged(Qt::ApplicationState
QtAndroid::destroySurface(m_nativeSurfaceId);
m_nativeSurfaceId = -1;
}
- clearEgl();
+ clearSurface();
unlockSurface();
}
}
void QAndroidPlatformOpenGLWindow::createEgl(EGLConfig config)
{
- clearEgl();
+ clearSurface();
QJniEnvironment env;
m_nativeWindow = ANativeWindow_fromSurface(env.jniEnv(), m_androidSurfaceObject.object());
m_androidSurfaceObject = QJniObject();
@@ -158,7 +157,7 @@ QSurfaceFormat QAndroidPlatformOpenGLWindow::format() const
return m_format;
}
-void QAndroidPlatformOpenGLWindow::clearEgl()
+void QAndroidPlatformOpenGLWindow::clearSurface()
{
if (m_eglSurface != EGL_NO_SURFACE) {
eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@@ -168,7 +167,7 @@ void QAndroidPlatformOpenGLWindow::clearEgl()
if (m_nativeWindow) {
ANativeWindow_release(m_nativeWindow);
- m_nativeWindow = 0;
+ m_nativeWindow = nullptr;
}
}
@@ -180,11 +179,13 @@ void QAndroidPlatformOpenGLWindow::surfaceChanged(JNIEnv *jniEnv, jobject surfac
lockSurface();
m_androidSurfaceObject = surface;
- if (surface) // wait until we have a valid surface to draw into
+ if (m_androidSurfaceObject.isValid()) // wait until we have a valid surface to draw into
m_surfaceWaitCondition.wakeOne();
+ else
+ clearSurface();
unlockSurface();
- if (surface) {
+ if (m_androidSurfaceObject.isValid()) {
// repaint the window, when we have a valid surface
QRect availableGeometry = screen()->availableGeometry();
if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.h b/src/plugins/platforms/android/qandroidplatformopenglwindow.h
index 8c31368b654..9a4247824e1 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.h
@@ -35,7 +35,7 @@ public:
protected:
void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) override;
void createEgl(EGLConfig config);
- void clearEgl();
+ void clearSurface() override;
private:
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.h b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h
index 14d5b7fc0ef..4b750b7070b 100644
--- a/src/plugins/platforms/android/qandroidplatformvulkanwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h
@@ -34,10 +34,10 @@ public:
protected:
void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) override;
+ void clearSurface() override;
private:
void sendExpose();
- void clearSurface();
int m_nativeSurfaceId;
ANativeWindow *m_nativeWindow;
diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h
index 6fccc2e7fea..2d92bfa0b04 100644
--- a/src/plugins/platforms/android/qandroidplatformwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformwindow.h
@@ -57,6 +57,7 @@ public:
protected:
void setGeometry(const QRect &rect) override;
+ virtual void clearSurface() {}
protected:
Qt::WindowFlags m_windowFlags;
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 7c2a942ca94..ad0dd3fd691 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -88,6 +88,13 @@ void QCALayerBackingStore::beginPaint(const QRegion &region)
qCInfo(lcQpaBackingStore) << "Beginning paint of" << region << "into backingstore of" << m_requestedSize;
+ if (m_requestedSize.isEmpty()) {
+ // We can't create IOSurfaces with and empty size, so instead reset our back buffer
+ qCDebug(lcQpaBackingStore) << "Size is empty, throwing away back buffer";
+ m_buffers.back().reset(nullptr);
+ return;
+ }
+
ensureBackBuffer(); // Find an unused back buffer, or reserve space for a new one
const bool bufferWasRecreated = recreateBackBufferIfNeeded();
@@ -202,12 +209,19 @@ bool QCALayerBackingStore::recreateBackBufferIfNeeded()
QPaintDevice *QCALayerBackingStore::paintDevice()
{
- Q_ASSERT(m_buffers.back());
- return m_buffers.back()->asImage();
+ if (m_buffers.back()) {
+ return m_buffers.back()->asImage();
+ } else {
+ static QImage fallbackDevice;
+ return &fallbackDevice;
+ }
}
void QCALayerBackingStore::endPaint()
{
+ if (!m_buffers.back())
+ return;
+
qCInfo(lcQpaBackingStore) << "Paint ended. Back buffer valid region is now" << m_buffers.back()->validRegion();
m_buffers.back()->unlock();
@@ -278,7 +292,7 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
Q_UNUSED(offset);
if (!m_buffers.back()) {
- qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first";
+ qCWarning(lcQpaBackingStore) << "Flush requested with no back buffer. Ignoring.";
return;
}
@@ -405,7 +419,7 @@ QPlatformBackingStore::FlushResult QCALayerBackingStore::rhiFlush(QWindow *windo
bool translucentBackground)
{
if (!m_buffers.back()) {
- qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first";
+ qCWarning(lcQpaBackingStore) << "Flush requested with no back buffer. Ignoring.";
return FlushFailed;
}
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.h b/src/plugins/platforms/cocoa/qcocoadrag.h
index dedf8a7fd9c..30456a91bba 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.h
+++ b/src/plugins/platforms/cocoa/qcocoadrag.h
@@ -35,7 +35,8 @@ public:
* to meet NSView dragImage:at guarantees, we need to record the original
* event and view when handling an event in QNSView
*/
- void setLastMouseEvent(NSEvent *event, NSView *view);
+ void setLastInputEvent(NSEvent *event, NSView *view);
+ void viewDestroyed(NSView *view);
void setAcceptedAction(Qt::DropAction act);
void exitDragLoop();
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm
index a8c0392f8ba..269ead2632e 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.mm
+++ b/src/plugins/platforms/cocoa/qcocoadrag.mm
@@ -31,13 +31,24 @@ QCocoaDrag::~QCocoaDrag()
[m_lastEvent release];
}
-void QCocoaDrag::setLastMouseEvent(NSEvent *event, NSView *view)
+void QCocoaDrag::setLastInputEvent(NSEvent *event, NSView *view)
{
[m_lastEvent release];
m_lastEvent = [event copy];
m_lastView = view;
}
+void QCocoaDrag::viewDestroyed(NSView *view)
+{
+ if (view == m_lastView) {
+ if (m_lastEvent.window.contentView == view) {
+ [m_lastEvent release];
+ m_lastEvent = nil;
+ }
+ m_lastView = nil;
+ }
+}
+
QMimeData *QCocoaDrag::dragMimeData()
{
if (m_drag)
@@ -95,9 +106,11 @@ Qt::DropAction QCocoaDrag::defaultAction(Qt::DropActions possibleActions,
Qt::DropAction QCocoaDrag::drag(QDrag *o)
{
- m_drag = o;
m_executed_drop_action = Qt::IgnoreAction;
+ if (!m_lastEvent)
+ return m_executed_drop_action;
+ m_drag = o;
QMacPasteboard dragBoard(CFStringRef(NSPasteboardNameDrag), QUtiMimeConverter::HandlerScopeFlag::DnD);
m_drag->mimeData()->setData("application/x-qt-mime-type-name"_L1, QByteArray("dummy"));
dragBoard.setMimeData(m_drag->mimeData(), QMacPasteboard::LazyRequest);
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h
index 919f7c240bc..36546879ae4 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.h
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h
@@ -29,6 +29,7 @@ public:
void initialize() override;
bool makeCurrent(QPlatformSurface *surface) override;
+ void beginFrame() override;
void swapBuffers(QPlatformSurface *surface) override;
void doneCurrent() override;
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index a65311175ff..bfac716b633 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -332,6 +332,25 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
return true;
}
+void QCocoaGLContext::beginFrame()
+{
+ QMacAutoReleasePool pool;
+
+ Q_ASSERT(context() && context()->surface());
+ auto *surface = context()->surface()->surfaceHandle();
+ Q_ASSERT(surface);
+
+ qCDebug(lcQpaOpenGLContext) << "Beginning frame for" << this
+ << "in" << QThread::currentThread() << "for" << surface;
+
+ Q_ASSERT(surface->surface()->supportsOpenGL());
+
+ if (surface->surface()->surfaceClass() == QSurface::Window) {
+ if (m_needsUpdate.fetchAndStoreRelaxed(false))
+ update();
+ }
+}
+
/*!
Sets the drawable object of the NSOpenGLContext, which is the
frame buffer that is the target of OpenGL drawing operations.
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 42e3270afd1..91d614fa4e7 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -151,6 +151,10 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
[[NSNotificationCenter defaultCenter] removeObserver:self];
[m_mouseMoveHelper release];
+ // FIXME: Replace with __weak or someting equivalent
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ nativeDrag->viewDestroyed(self);
+
[super dealloc];
}
diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm
index 63b180111b4..34be561a230 100644
--- a/src/plugins/platforms/cocoa/qnsview_mouse.mm
+++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm
@@ -117,7 +117,7 @@ static const QPointingDevice *pointingDeviceFor(qint64 deviceID)
ulong timestamp = [theEvent timestamp] * 1000;
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- nativeDrag->setLastMouseEvent(theEvent, self);
+ nativeDrag->setLastInputEvent(theEvent, self);
const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(theEvent.modifierFlags);
auto button = cocoaButton2QtButton(theEvent);
diff --git a/src/plugins/platforms/cocoa/qnsview_tablet.mm b/src/plugins/platforms/cocoa/qnsview_tablet.mm
index 4c6e351b3f4..09553aee5f6 100644
--- a/src/plugins/platforms/cocoa/qnsview_tablet.mm
+++ b/src/plugins/platforms/cocoa/qnsview_tablet.mm
@@ -28,6 +28,9 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceMap, devicesInProximity)
ulong timestamp = [theEvent timestamp] * 1000;
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ nativeDrag->setLastInputEvent(theEvent, self);
+
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint: &windowPoint andScreenPoint: &screenPoint];
diff --git a/src/plugins/platforms/cocoa/qnsview_touch.mm b/src/plugins/platforms/cocoa/qnsview_touch.mm
index 6a147701fce..997edcbf36e 100644
--- a/src/plugins/platforms/cocoa/qnsview_touch.mm
+++ b/src/plugins/platforms/cocoa/qnsview_touch.mm
@@ -34,6 +34,10 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
return;
const NSTimeInterval timestamp = [event timestamp];
+
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ nativeDrag->setLastInputEvent(event, self);
+
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points << "from device" << Qt::hex << [event deviceID];
QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]), points);
@@ -45,6 +49,10 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
return;
const NSTimeInterval timestamp = [event timestamp];
+
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ nativeDrag->setLastInputEvent(event, self);
+
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points << "from device" << Qt::hex << [event deviceID];
QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]), points);
@@ -56,6 +64,10 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
return;
const NSTimeInterval timestamp = [event timestamp];
+
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ nativeDrag->setLastInputEvent(event, self);
+
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points << "from device" << Qt::hex << [event deviceID];
QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]), points);
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
index da6485a32dd..212c69938db 100644
--- a/src/plugins/platforms/cocoa/qnswindow.mm
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -14,6 +14,8 @@
#include <qpa/qwindowsysteminterface.h>
#include <qoperatingsystemversion.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
+
Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events");
static bool isMouseEvent(NSEvent *ev)
@@ -225,7 +227,8 @@ static bool isMouseEvent(NSEvent *ev)
// client geometry based on the QWindow's positionPolicy is a noop.
// Now that we have a NSWindow to read the frame from we re-apply
// the QWindow geometry, which will move the NSWindow if needed.
- m_platformWindow->setGeometry(window->geometry());
+ m_platformWindow->setGeometry(QHighDpi::toNativeWindowGeometry(window->geometry(), window));
+
m_platformWindow->setVisible(window->isVisible());
}
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
index b011bf0439d..bd9a960ed94 100644
--- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
+++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
@@ -17,6 +17,8 @@
#include <QtCore/qsettings.h>
#include <qpa/qwindowsysteminterface.h>
+#include <QtGui/private/qguiapplication_p.h>
+
#include <commctrl.h>
#include <shellapi.h>
#include <shlobj.h>
@@ -371,6 +373,10 @@ bool QWindowsSystemTrayIcon::winEvent(const MSG &message, long *result)
// since hi-res coordinates are delivered in this case (Windows issue).
// Default to primary screen with check to prevent a crash.
const QPoint globalPos = QPoint(GET_X_LPARAM(message.wParam), GET_Y_LPARAM(message.wParam));
+ // QTBUG-130832: QMenu relies on lastCursorPosition being up to date. When this code
+ // is called it still holds the last known mouse position inside a Qt window. Do a
+ // forced update of this position.
+ QGuiApplicationPrivate::lastCursorPosition = QCursor::pos().toPointF();
const auto &screenManager = QWindowsContext::instance()->screenManager();
const QPlatformScreen *screen = screenManager.screenAtDp(globalPos);
if (!screen)
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index c78e41bd3e0..e8506b011c0 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -2671,8 +2671,24 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState)
setFlag(WithinMaximize);
if (newState & Qt::WindowFullScreen)
setFlag(MaximizeToFullScreen);
- ShowWindow(m_data.hwnd,
- (newState & Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE);
+ if (m_data.flags & Qt::FramelessWindowHint) {
+ if (newState == Qt::WindowNoState) {
+ const QRect &rect = m_savedFrameGeometry;
+ MoveWindow(m_data.hwnd, rect.x(), rect.y(), rect.width(), rect.height(), true);
+ } else {
+ HMONITOR monitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO monitorInfo = {};
+ monitorInfo.cbSize = sizeof(MONITORINFO);
+ GetMonitorInfo(monitor, &monitorInfo);
+ const RECT &rect = monitorInfo.rcWork;
+ m_savedFrameGeometry = geometry();
+ MoveWindow(m_data.hwnd, rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top, true);
+ }
+ } else {
+ ShowWindow(m_data.hwnd,
+ (newState & Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE);
+ }
clearFlag(WithinMaximize);
clearFlag(MaximizeToFullScreen);
} else if (visible && (oldState & newState & Qt::WindowMinimized)) {
@@ -2832,15 +2848,16 @@ void QWindowsWindow::calculateFullFrameMargins()
const auto systemMargins = testFlag(DisableNonClientScaling)
? QWindowsGeometryHint::frameOnPrimaryScreen(window(), m_data.hwnd)
: frameMargins_sys();
+ const QMargins actualMargins = systemMargins + customMargins();
const int yDiff = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top);
- const bool typicalFrame = (systemMargins.left() == systemMargins.right())
- && (systemMargins.right() == systemMargins.bottom());
+ const bool typicalFrame = (actualMargins.left() == actualMargins.right())
+ && (actualMargins.right() == actualMargins.bottom());
const QMargins adjustedMargins = typicalFrame ?
- QMargins(systemMargins.left(), (yDiff - systemMargins.bottom()),
- systemMargins.right(), systemMargins.bottom())
- : systemMargins + customMargins();
+ QMargins(actualMargins.left(), (yDiff - actualMargins.bottom()),
+ actualMargins.right(), actualMargins.bottom())
+ : actualMargins;
setFullFrameMargins(adjustedMargins);
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 55c226d3e69..4f62a1880b8 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -682,96 +682,23 @@ static inline qreal fixed1616ToReal(xcb_input_fp1616_t val)
return qreal(val) / 0x10000;
}
-//implementation is ported from https://codereview.qt-project.org/c/qt/qtbase/+/231552/12/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp#558
-namespace {
-
-/*! \internal
-
- Qt listens for XIAllDevices to avoid losing mouse events. This function
- ensures that we don't process the same event twice: from a slave device and
- then again from a master device.
-
- In a normal use case (e.g. mouse press and release inside a window), we will
- drop events from master devices as duplicates. Other advantage of processing
- events from slave devices is that they don't share button state. All buttons
- on a master device share the state.
-
- Examples of special cases:
-
-\list
-
-\li During system move/resize, window manager (_NET_WM_MOVERESIZE) grabs the
- master pointer, in this case we process the matching release from the slave
- device. A master device event is not sent by the server, hence no duplicate
- event to drop. If we listened for XIAllMasterDevices instead, we would never
- see a release event in this case.
-
-\li If we dismiss a context menu by clicking somewhere outside a Qt application,
- we will process the mouse press from the master pointer as that is the
- device we are grabbing. We are not grabbing slave devices (grabbing on the
- slave device is buggy according to 19d289ab1b5bde3e136765e5432b5c7d004df3a4).
- And since the event occurs outside our window, the slave device event is
- not sent to us by the server, hence no duplicate event to drop.
-
-\endlist
-*/
-bool isDuplicateEvent(xcb_ge_event_t *event)
-{
- Q_ASSERT(event);
-
- struct qXIEvent {
- bool isValid = false;
- uint16_t sourceid;
- uint8_t evtype;
- uint32_t detail;
- int32_t root_x;
- int32_t root_y;
- };
- static qXIEvent lastSeenEvent;
-
- bool isDuplicate = false;
- auto *xiDeviceEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event);
- if (lastSeenEvent.isValid) {
- isDuplicate = lastSeenEvent.sourceid == xiDeviceEvent->sourceid &&
- lastSeenEvent.evtype == xiDeviceEvent->event_type &&
- lastSeenEvent.detail == xiDeviceEvent->detail &&
- lastSeenEvent.root_x == xiDeviceEvent->root_x &&
- lastSeenEvent.root_y == xiDeviceEvent->root_y;
- } else {
- lastSeenEvent.isValid = true;
- }
- lastSeenEvent.sourceid = xiDeviceEvent->sourceid;
- lastSeenEvent.evtype = xiDeviceEvent->event_type;
- lastSeenEvent.detail = xiDeviceEvent->detail;
- lastSeenEvent.root_x = xiDeviceEvent->root_x;
- lastSeenEvent.root_y = xiDeviceEvent->root_y;
-
- if (isDuplicate) {
- qCDebug(lcQpaXInputEvents, "Duplicate XI2 event %d", event->event_type);
- // This sanity check ensures that special cases like QTBUG-59277 keep working.
- lastSeenEvent.isValid = false; // An event can be a duplicate only once.
- }
-
- return isDuplicate;
-}
-
-} // namespace
-
void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
{
auto *xiEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event);
- if (m_xiSlavePointerIds.contains(xiEvent->deviceid)) {
- if (!(xiEvent->event_type == XCB_INPUT_BUTTON_PRESS
- || xiEvent->event_type == XCB_INPUT_BUTTON_RELEASE
- || xiEvent->event_type == XCB_INPUT_MOTION)) {
- if (!m_duringSystemMoveResize)
- return;
- if (xiEvent->event == XCB_NONE)
- return;
-
- if (xiEvent->event_type == XCB_INPUT_TOUCH_END)
- abortSystemMoveResize(xiEvent->event);
+ setTime(xiEvent->time);
+ if (m_xiSlavePointerIds.contains(xiEvent->deviceid) && xiEvent->event_type != XCB_INPUT_PROPERTY) {
+ if (!m_duringSystemMoveResize)
+ return;
+ if (xiEvent->event == XCB_NONE)
+ return;
+ if (xiEvent->event_type == XCB_INPUT_BUTTON_RELEASE
+ && xiEvent->detail == XCB_BUTTON_INDEX_1 ) {
+ abortSystemMoveResize(xiEvent->event);
+ } else if (xiEvent->event_type == XCB_INPUT_TOUCH_END) {
+ abortSystemMoveResize(xiEvent->event);
+ return;
+ } else {
return;
}
}
@@ -783,27 +710,11 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
switch (xiEvent->event_type) {
case XCB_INPUT_BUTTON_PRESS:
case XCB_INPUT_BUTTON_RELEASE:
- case XCB_INPUT_MOTION: {
- if (isDuplicateEvent(event))
- return;
- if (m_xiSlavePointerIds.contains(xiEvent->deviceid)) {
- if (m_duringSystemMoveResize) {
- if (xiEvent->event_type == XCB_INPUT_BUTTON_RELEASE
- && xiEvent->detail == XCB_BUTTON_INDEX_1 ) {
- abortSystemMoveResize(xiEvent->event);
- } else {
- return;
- }
- }
- }
- xiDeviceEvent = xiEvent;
- eventListener = windowEventListenerFromId(xiDeviceEvent->event);
- sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master
- break;
- }
+ case XCB_INPUT_MOTION:
case XCB_INPUT_TOUCH_BEGIN:
case XCB_INPUT_TOUCH_UPDATE:
- case XCB_INPUT_TOUCH_END: {
+ case XCB_INPUT_TOUCH_END:
+ {
xiDeviceEvent = xiEvent;
eventListener = windowEventListenerFromId(xiDeviceEvent->event);
sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 06f4b66edb2..9d1aa795e0a 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -657,12 +657,16 @@ void QXcbScreen::setMonitor(xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp
if (m_crtcs.size() == 1) {
auto crtc = Q_XCB_REPLY(xcb_randr_get_crtc_info,
xcb_connection(), m_crtcs[0], timestamp);
- m_singlescreen = (monitorGeometry == (QRect(crtc->x, crtc->y, crtc->width, crtc->height)));
- if (m_singlescreen) {
- if (crtc->mode) {
- updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
- if (mode() != crtc->mode)
- updateRefreshRate(crtc->mode);
+ if (crtc == XCB_NONE) {
+ qCDebug(lcQpaScreen, "Didn't get crtc info when m_crtcs.size() == 1");
+ } else {
+ m_singlescreen = (monitorGeometry == (QRect(crtc->x, crtc->y, crtc->width, crtc->height)));
+ if (m_singlescreen) {
+ if (crtc->mode) {
+ updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
+ if (mode() != crtc->mode)
+ updateRefreshRate(crtc->mode);
+ }
}
}
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 10181b58a4f..35f547cca99 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -1960,8 +1960,10 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x,
return;
}
- if (connection()->buttonState() == Qt::NoButton)
+ if (connection()->buttonState() == Qt::NoButton) {
connection()->setMousePressWindow(nullptr);
+ m_ignorePressedWindowOnMouseLeave = false;
+ }
handleMouseEvent(timestamp, local, global, modifiers, type, source);
}
@@ -1981,11 +1983,6 @@ static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
return true;
}
-static bool windowContainsGlobalPoint(QXcbWindow *window, int x, int y)
-{
- return window ? window->geometry().contains(window->mapFromGlobal(QPoint(x, y))) : false;
-}
-
static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn)
{
return ((doCheckUnGrabAncestor(conn)
@@ -2009,12 +2006,17 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in
{
connection()->setTime(timestamp);
- if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow())
+ if (ignoreEnterEvent(mode, detail, connection())
+ || (connection()->mousePressWindow() && !m_ignorePressedWindowOnMouseLeave)) {
return;
+ }
// Updates scroll valuators, as user might have done some scrolling outside our X client.
connection()->xi2UpdateScrollingDevices();
+ if (mode == XCB_NOTIFY_MODE_UNGRAB && connection()->queryMouseButtons() != Qt::NoButton)
+ m_ignorePressedWindowOnMouseLeave = true;
+
const QPoint global = QPoint(root_x, root_y);
const QPoint local(event_x, event_y);
QWindowSystemInterface::handleEnterEvent(window(), local, global);
@@ -2027,7 +2029,7 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
QXcbWindow *mousePressWindow = connection()->mousePressWindow();
if (ignoreLeaveEvent(mode, detail, connection())
- || (mousePressWindow && windowContainsGlobalPoint(mousePressWindow, root_x, root_y))) {
+ || (mousePressWindow && !m_ignorePressedWindowOnMouseLeave)) {
return;
}
@@ -2047,7 +2049,7 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global);
} else {
QWindowSystemInterface::handleLeaveEvent(window());
- if (!windowContainsGlobalPoint(this, root_x, root_y))
+ if (m_ignorePressedWindowOnMouseLeave)
connection()->setMousePressWindow(nullptr);
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 5d5d152e418..908e72722bd 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -230,6 +230,7 @@ protected:
bool m_alertState = false;
bool m_minimized = false;
bool m_trayIconWindow = false;
+ bool m_ignorePressedWindowOnMouseLeave = false;
xcb_window_t m_netWmUserTimeWindow = XCB_NONE;
QSurfaceFormat m_format;