summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2017-02-17 20:10:34 +0100
committerLiang Qi <liang.qi@qt.io>2017-02-17 20:10:34 +0100
commitbc4cd465dd5df82e13f3c7709166ee11289d219f (patch)
treed6323aaed6383e589fbefb6057648c22bb187c76 /src/plugins
parent43daefb0962794b2df256cae1098e889b9b36f12 (diff)
parent07745d7bfbf6c8d83e0243150d8ce934675dea87 (diff)
Merge remote-tracking branch 'origin/5.9' into dev
Conflicts: qmake/Makefile.unix Change-Id: Ia18e391198222eef34ffa2df6f683e052058d032
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm3
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h17
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm371
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h2
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm23
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.h1
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.mm17
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp4
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h7
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp9
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.h3
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp1
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h1
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp33
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp3
18 files changed, 308 insertions, 197 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index a7cc19b3bf..9e688f4d1b 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -255,7 +255,8 @@ void QCocoaGLContext::setActiveWindow(QWindow *window)
QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
cocoaWindow->setCurrentContext(this);
- [(QNSView *) cocoaWindow->view() setQCocoaGLContext:this];
+ Q_ASSERT(!cocoaWindow->isForeignWindow());
+ [qnsview_cast(cocoaWindow->view()) setQCocoaGLContext:this];
}
void QCocoaGLContext::updateSurfaceFormat()
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index e177a24e73..8e47974d12 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -581,8 +581,8 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
// The calls above block, and also swallow any mouse release event,
// so we need to clear any mouse button that triggered the menu popup.
- if ([view isKindOfClass:[QNSView class]])
- [(QNSView *)view resetMouseButtons];
+ if (!cocoaWindow->isForeignWindow())
+ [qnsview_cast(view) resetMouseButtons];
}
void QCocoaMenu::dismiss()
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index bb015c2419..f60597fe42 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -217,7 +217,7 @@ public:
bool windowShouldClose();
bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const;
- void setSynchedWindowStateFromWindow();
+ void reportCurrentWindowState(bool unconditionally = false);
NSInteger windowLevel(Qt::WindowFlags flags);
NSUInteger windowStyleMask(Qt::WindowFlags flags);
@@ -284,10 +284,15 @@ protected:
QCocoaNSWindow *createNSWindow(bool shouldBeChildNSWindow, bool shouldBePanel);
QRect nativeWindowGeometry() const;
- void syncWindowState(Qt::WindowState newState);
void reinsertChildWindow(QCocoaWindow *child);
void removeChildWindow(QCocoaWindow *child);
+ Qt::WindowState windowState() const;
+ void applyWindowState(Qt::WindowState newState);
+ void toggleMaximized();
+ void toggleFullScreen();
+ bool isTransitioningToFullScreen() const;
+
// private:
public: // for QNSView
friend class QCocoaBackingStore;
@@ -304,8 +309,7 @@ public: // for QNSView
bool m_viewIsToBeEmbedded; // true if the m_view is intended to be embedded in a "foreign" NSView hiearchy
Qt::WindowFlags m_windowFlags;
- bool m_effectivelyMaximized;
- Qt::WindowState m_synchedWindowState;
+ Qt::WindowState m_lastReportedWindowState;
Qt::WindowModality m_windowModality;
QPointer<QWindow> m_enterLeaveTargetWindow;
bool m_windowUnderMouse;
@@ -339,11 +343,6 @@ public: // for QNSView
int m_topContentBorderThickness;
int m_bottomContentBorderThickness;
- // used by showFullScreen in fake mode
- QRect m_normalGeometry;
- Qt::WindowFlags m_oldWindowFlags;
- NSApplicationPresentationOptions m_presentationOptions;
-
struct BorderRange {
BorderRange(quintptr i, int u, int l) : identifier(i), upper(u), lower(l) { }
quintptr identifier;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 114efc3e92..918f376446 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -87,6 +87,36 @@ static void qt_closePopups()
}
}
+@interface NSWindow (FullScreenProperty)
+@property(readonly) BOOL qt_fullScreen;
+@end
+
+@implementation NSWindow (FullScreenProperty)
+
++ (void)load
+{
+ NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+ [center addObserverForName:NSWindowDidEnterFullScreenNotification object:nil queue:nil
+ usingBlock:^(NSNotification *notification) {
+ objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
+ [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_RETAIN);
+ }
+ ];
+ [center addObserverForName:NSWindowDidExitFullScreenNotification object:nil queue:nil
+ usingBlock:^(NSNotification *notification) {
+ objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
+ nil, OBJC_ASSOCIATION_RETAIN);
+ }
+ ];
+}
+
+- (BOOL)qt_fullScreen
+{
+ NSNumber *number = objc_getAssociatedObject(self, @selector(qt_fullScreen));
+ return [number boolValue];
+}
+@end
+
@implementation QNSWindowHelper
@synthesize window = _window;
@@ -409,8 +439,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_nsWindow(0)
, m_viewIsEmbedded(false)
, m_viewIsToBeEmbedded(false)
- , m_effectivelyMaximized(false)
- , m_synchedWindowState(Qt::WindowActive)
+ , m_lastReportedWindowState(Qt::WindowNoState)
, m_windowModality(Qt::NonModal)
, m_windowUnderMouse(false)
, m_inConstructor(true)
@@ -435,7 +464,6 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_drawContentBorderGradient(false)
, m_topContentBorderThickness(0)
, m_bottomContentBorderThickness(0)
- , m_normalGeometry(QRect(0,0,-1,-1))
, m_hasWindowFilePath(false)
{
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::QCocoaWindow" << window();
@@ -728,7 +756,7 @@ void QCocoaWindow::setVisible(bool visible)
// setWindowState might have been called while the window was hidden and
// will not change the NSWindow state in that case. Sync up here:
- syncWindowState(window()->windowState());
+ applyWindowState(window()->windowState());
if (window()->windowState() != Qt::WindowMinimized) {
if ((window()->modality() == Qt::WindowModal
@@ -930,7 +958,8 @@ void QCocoaWindow::setWindowZoomButton(Qt::WindowFlags flags)
// in line with the platform style guidelines.
bool fixedSizeNoZoom = (windowMinimumSize().isValid() && windowMaximumSize().isValid()
&& windowMinimumSize() == windowMaximumSize());
- bool customizeNoZoom = ((flags & Qt::CustomizeWindowHint) && !(flags & Qt::WindowMaximizeButtonHint));
+ bool customizeNoZoom = ((flags & Qt::CustomizeWindowHint)
+ && !(flags & (Qt::WindowMaximizeButtonHint | Qt::WindowFullscreenButtonHint)));
[[m_nsWindow standardWindowButton:NSWindowZoomButton] setEnabled:!(fixedSizeNoZoom || customizeNoZoom)];
}
@@ -965,13 +994,16 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
setWindowZoomButton(flags);
}
+ if (m_nsWindow)
+ m_nsWindow.ignoresMouseEvents = flags & Qt::WindowTransparentForInput;
+
m_windowFlags = flags;
}
void QCocoaWindow::setWindowState(Qt::WindowState state)
{
if (window()->isVisible())
- syncWindowState(state); // Window state set for hidden windows take effect when show() is called.
+ applyWindowState(state); // Window state set for hidden windows take effect when show() is called
}
void QCocoaWindow::setWindowTitle(const QString &title)
@@ -1247,6 +1279,9 @@ void QCocoaWindow::windowDidMove()
return;
[qnsview_cast(m_view) updateGeometry];
+
+ // Moving a window might bring it out of maximized state
+ reportCurrentWindowState();
}
void QCocoaWindow::windowDidResize()
@@ -1259,6 +1294,9 @@ void QCocoaWindow::windowDidResize()
clipChildWindows();
[qnsview_cast(m_view) updateGeometry];
+
+ if (!m_view.inLiveResize)
+ reportCurrentWindowState();
}
void QCocoaWindow::viewDidChangeFrame()
@@ -1280,10 +1318,7 @@ void QCocoaWindow::viewDidChangeGlobalFrame()
void QCocoaWindow::windowDidEndLiveResize()
{
- if (m_synchedWindowState == Qt::WindowMaximized && ![m_nsWindow isZoomed]) {
- m_effectivelyMaximized = false;
- [qnsview_cast(m_view) notifyWindowStateChanged:Qt::WindowNoState];
- }
+ reportCurrentWindowState();
}
void QCocoaWindow::windowDidBecomeKey()
@@ -1320,22 +1355,37 @@ void QCocoaWindow::windowDidResignKey()
void QCocoaWindow::windowDidMiniaturize()
{
- [qnsview_cast(m_view) notifyWindowStateChanged:Qt::WindowMinimized];
+ reportCurrentWindowState();
}
void QCocoaWindow::windowDidDeminiaturize()
{
- [qnsview_cast(m_view) notifyWindowStateChanged:Qt::WindowNoState];
+ reportCurrentWindowState();
}
void QCocoaWindow::windowDidEnterFullScreen()
{
- [qnsview_cast(m_view) notifyWindowStateChanged:Qt::WindowFullScreen];
+ Q_ASSERT_X(m_nsWindow.qt_fullScreen, "QCocoaWindow",
+ "FullScreen category processes window notifications first");
+
+ reportCurrentWindowState();
}
void QCocoaWindow::windowDidExitFullScreen()
{
- [qnsview_cast(m_view) notifyWindowStateChanged:Qt::WindowNoState];
+ Q_ASSERT_X(!m_nsWindow.qt_fullScreen, "QCocoaWindow",
+ "FullScreen category processes window notifications first");
+
+ Qt::WindowState requestedState = window()->windowState();
+
+ // Deliver update of QWindow state
+ reportCurrentWindowState();
+
+ if (requestedState != windowState() && requestedState != Qt::WindowFullScreen) {
+ // We were only going out of full screen as an intermediate step before
+ // progressing into the final step, so re-sync the desired state.
+ applyWindowState(requestedState);
+ }
}
void QCocoaWindow::windowDidOrderOffScreen()
@@ -1399,12 +1449,6 @@ bool QCocoaWindow::windowShouldClose()
// --------------------------------------------------------------------------
-void QCocoaWindow::setSynchedWindowStateFromWindow()
-{
- if (QWindow *w = window())
- m_synchedWindowState = w->windowState();
-}
-
bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const
{
if (type == Qt::Widget)
@@ -1579,15 +1623,8 @@ void QCocoaWindow::recreateWindowIfNeeded()
}
// Set properties after the window has been made a child NSWindow
- m_nsWindow.styleMask = NSBorderlessWindowMask;
- m_nsWindow.hasShadow = NO;
- m_nsWindow.level = NSNormalWindowLevel;
- NSWindowCollectionBehavior collectionBehavior =
- NSWindowCollectionBehaviorManaged | NSWindowCollectionBehaviorIgnoresCycle
- | NSWindowCollectionBehaviorFullScreenAuxiliary;
- m_nsWindow.animationBehavior = NSWindowAnimationBehaviorNone;
- m_nsWindow.collectionBehavior = collectionBehavior;
setCocoaGeometry(windowGeometry());
+ setWindowFlags(window()->flags());
} else {
// Child windows have no NSWindow, link the NSViews instead.
if ([m_view superview])
@@ -1604,9 +1641,6 @@ void QCocoaWindow::recreateWindowIfNeeded()
[m_view setHidden:!window()->isVisible()];
}
- m_nsWindow.ignoresMouseEvents =
- (window()->flags() & Qt::WindowTransparentForInput) == Qt::WindowTransparentForInput;
-
const qreal opacity = qt_window_private(window())->opacity;
if (!qFuzzyCompare(opacity, qreal(1.0)))
setOpacity(opacity);
@@ -1674,62 +1708,49 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBeChildNSWindow, bool sh
Qt::WindowType type = window()->type();
Qt::WindowFlags flags = window()->flags();
- NSUInteger styleMask;
- if (shouldBeChildNSWindow) {
- styleMask = NSBorderlessWindowMask;
- } else {
- styleMask = windowStyleMask(flags);
- }
- QCocoaNSWindow *createdWindow = 0;
-
- // Use NSPanel for popup-type windows. (Popup, Tool, ToolTip, SplashScreen)
- // and dialogs
- if (shouldBePanel) {
- QNSPanel *panel = [[QNSPanel alloc] initWithContentRect:frame screen:cocoaScreen->nativeScreen()
- styleMask: styleMask qPlatformWindow:this];
-
- if ((type & Qt::Popup) == Qt::Popup)
- [panel setHasShadow:YES];
-
- // Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set.
- QVariant showWithoutActivating = QPlatformWindow::window()->property("_q_macAlwaysShowToolWindow");
- bool shouldHideOnDeactivate = ((type & Qt::Tool) == Qt::Tool) &&
- !(showWithoutActivating.isValid() && showWithoutActivating.toBool());
- [panel setHidesOnDeactivate: shouldHideOnDeactivate];
+ // Create NSWindow
+ Class windowClass = shouldBePanel ? [QNSPanel class] : [QNSWindow class];
+ NSUInteger styleMask = shouldBeChildNSWindow ? NSBorderlessWindowMask : windowStyleMask(flags);
+ QCocoaNSWindow *window = [[windowClass alloc] initWithContentRect:frame
+ screen:cocoaScreen->nativeScreen() styleMask:styleMask qPlatformWindow:this];
- // Make popup windows show on the same desktop as the parent full-screen window.
- [panel setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
- if ((type & Qt::Popup) == Qt::Popup)
- [panel setAnimationBehavior:NSWindowAnimationBehaviorUtilityWindow];
+ window.restorable = NO;
+ window.level = shouldBeChildNSWindow ? NSNormalWindowLevel : windowLevel(flags);
- createdWindow = panel;
- } else {
- createdWindow = [[QNSWindow alloc] initWithContentRect:frame screen:cocoaScreen->nativeScreen()
- styleMask: styleMask qPlatformWindow:this];
+ if (!isOpaque()) {
+ window.backgroundColor = [NSColor clearColor];
+ window.opaque = NO;
}
- if ([createdWindow respondsToSelector:@selector(setRestorable:)])
- [createdWindow setRestorable: NO];
+ Q_ASSERT(!(shouldBePanel && shouldBeChildNSWindow));
- NSInteger level = windowLevel(flags);
- [createdWindow setLevel:level];
+ if (shouldBePanel) {
+ // Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set
+ window.hidesOnDeactivate = ((type & Qt::Tool) == Qt::Tool) &&
+ !qt_mac_resolveOption(false, QPlatformWindow::window(), "_q_macAlwaysShowToolWindow", "");
- // OpenGL surfaces can be ordered either above(default) or below the NSWindow.
- // When ordering below the window must be tranclucent and have a clear background color.
- static GLint openglSourfaceOrder = qt_mac_resolveOption(1, "QT_MAC_OPENGL_SURFACE_ORDER");
+ // Make popup windows show on the same desktop as the parent full-screen window
+ window.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary;
- bool isTranslucent = window()->format().alphaBufferSize() > 0
- || (surface()->supportsOpenGL() && openglSourfaceOrder == -1);
- if (isTranslucent) {
- [createdWindow setBackgroundColor:[NSColor clearColor]];
- [createdWindow setOpaque:NO];
+ if ((type & Qt::Popup) == Qt::Popup) {
+ window.hasShadow = YES;
+ window.animationBehavior = NSWindowAnimationBehaviorUtilityWindow;
+ }
+ } else if (shouldBeChildNSWindow) {
+ window.collectionBehavior =
+ NSWindowCollectionBehaviorManaged
+ | NSWindowCollectionBehaviorIgnoresCycle
+ | NSWindowCollectionBehaviorFullScreenAuxiliary;
+ window.hasShadow = NO;
+ window.animationBehavior = NSWindowAnimationBehaviorNone;
}
- m_windowModality = window()->modality();
+ // Persist modality so we can detect changes later on
+ m_windowModality = QPlatformWindow::window()->modality();
- applyContentBorderThickness(createdWindow);
+ applyContentBorderThickness(window);
- return createdWindow;
+ return window;
}
void QCocoaWindow::removeMonitor()
@@ -1753,85 +1774,155 @@ QRect QCocoaWindow::nativeWindowGeometry() const
return qRect;
}
-// Syncs the NSWindow minimize/maximize/fullscreen state with the current QWindow state
-void QCocoaWindow::syncWindowState(Qt::WindowState newState)
+/*!
+ Applies the given state to the NSWindow, going in/out of minimize/zoomed/fullscreen
+
+ When this is called from QWindow::setWindowState(), the QWindow state has not been
+ updated yet, so window()->windowState() will reflect the previous state that was
+ reported to QtGui.
+*/
+void QCocoaWindow::applyWindowState(Qt::WindowState newState)
{
+ const Qt::WindowState currentState = windowState();
+ if (newState == currentState)
+ return;
+
if (!m_nsWindow)
return;
- // if content view width or height is 0 then the window animations will crash so
- // do nothing except set the new state
- NSRect contentRect = m_view.frame;
- if (contentRect.size.width <= 0 || contentRect.size.height <= 0) {
+
+ const NSSize contentSize = m_view.frame.size;
+ if (contentSize.width <= 0 || contentSize.height <= 0) {
+ // If content view width or height is 0 then the window animations will crash so
+ // do nothing. We report the current state back to reflect the failed operation.
qWarning("invalid window content view size, check your window geometry");
- m_synchedWindowState = newState;
+ reportCurrentWindowState(true);
return;
}
- Qt::WindowState predictedState = newState;
- if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized)) {
- const int styleMask = [m_nsWindow styleMask];
- const bool usePerform = styleMask & NSResizableWindowMask;
- [m_nsWindow setStyleMask:styleMask | NSResizableWindowMask];
- if (usePerform)
- [m_nsWindow performZoom : m_nsWindow]; // toggles
- else
- [m_nsWindow zoom : m_nsWindow]; // toggles
- [m_nsWindow setStyleMask:styleMask];
+ if (m_nsWindow.styleMask & NSUtilityWindowMask) {
+ // Utility panels cannot be fullscreen
+ qWarning() << window()->type() << "windows can not be made full screen";
+ reportCurrentWindowState(true);
+ return;
}
- if ((m_synchedWindowState & Qt::WindowMinimized) != (newState & Qt::WindowMinimized)) {
- if (newState & Qt::WindowMinimized) {
- if ([m_nsWindow styleMask] & NSMiniaturizableWindowMask)
- [m_nsWindow performMiniaturize : m_nsWindow];
- else
- [m_nsWindow miniaturize : m_nsWindow];
- } else {
- [m_nsWindow deminiaturize : m_nsWindow];
- }
+ const id sender = m_nsWindow;
+
+ // First we need to exit states that can't transition directly to other states
+ switch (currentState) {
+ case Qt::WindowMinimized:
+ [m_nsWindow deminiaturize:sender];
+ Q_ASSERT_X(windowState() != Qt::WindowMinimized, "QCocoaWindow",
+ "[NSWindow deminiaturize:] is synchronous");
+ break;
+ case Qt::WindowFullScreen: {
+ toggleFullScreen();
+ // Exiting fullscreen is not synchronous, so we need to wait for the
+ // NSWindowDidExitFullScreenNotification before continuing to apply
+ // the new state.
+ return;
}
-
- const bool effMax = m_effectivelyMaximized;
- if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized) || (m_effectivelyMaximized && newState == Qt::WindowNoState)) {
- if ((m_synchedWindowState & Qt::WindowFullScreen) == (newState & Qt::WindowFullScreen)) {
- [m_nsWindow zoom : m_nsWindow]; // toggles
- m_effectivelyMaximized = !effMax;
- } else if (!(newState & Qt::WindowMaximized)) {
- // it would be nice to change the target geometry that toggleFullScreen will animate toward
- // but there is no known way, so the maximized state is not possible at this time
- predictedState = static_cast<Qt::WindowState>(static_cast<int>(newState) | Qt::WindowMaximized);
- m_effectivelyMaximized = true;
- }
+ default:
+ Q_FALLTHROUGH();
}
- if ((m_synchedWindowState & Qt::WindowFullScreen) != (newState & Qt::WindowFullScreen)) {
- if (window()->flags() & Qt::WindowFullscreenButtonHint) {
- if (m_effectivelyMaximized && m_synchedWindowState == Qt::WindowFullScreen)
- predictedState = Qt::WindowMaximized;
- [m_nsWindow toggleFullScreen : m_nsWindow];
- } else {
- if (newState & Qt::WindowFullScreen) {
- QScreen *screen = window()->screen();
- if (screen) {
- if (m_normalGeometry.width() < 0) {
- m_oldWindowFlags = m_windowFlags;
- window()->setFlags(window()->flags() | Qt::FramelessWindowHint);
- m_normalGeometry = nativeWindowGeometry();
- setGeometry(screen->geometry());
- m_presentationOptions = [NSApp presentationOptions];
- [NSApp setPresentationOptions : m_presentationOptions | NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock];
- }
- }
- } else {
- window()->setFlags(m_oldWindowFlags);
- setGeometry(m_normalGeometry);
- m_normalGeometry.setRect(0, 0, -1, -1);
- [NSApp setPresentationOptions : m_presentationOptions];
- }
+ // Then we apply the new state if needed
+ if (newState == windowState())
+ return;
+
+ switch (newState) {
+ case Qt::WindowFullScreen:
+ toggleFullScreen();
+ break;
+ case Qt::WindowMaximized:
+ toggleMaximized();
+ break;
+ case Qt::WindowMinimized:
+ [m_nsWindow miniaturize:sender];
+ break;
+ case Qt::WindowNoState:
+ switch (windowState()) {
+ case Qt::WindowMaximized:
+ toggleMaximized();
+ default:
+ Q_FALLTHROUGH();
}
+ break;
+ default:
+ Q_UNREACHABLE();
}
+}
+
+void QCocoaWindow::toggleMaximized()
+{
+ // The NSWindow needs to be resizable, otherwise the window will
+ // not be possible to zoom back to non-zoomed state.
+ const bool wasResizable = m_nsWindow.styleMask & NSResizableWindowMask;
+ m_nsWindow.styleMask |= NSResizableWindowMask;
+
+ const id sender = m_nsWindow;
+ [m_nsWindow zoom:sender];
+
+ if (!wasResizable)
+ m_nsWindow.styleMask &= ~NSResizableWindowMask;
+}
+
+void QCocoaWindow::toggleFullScreen()
+{
+ // The NSWindow needs to be resizable, otherwise we'll end up with
+ // the normal window geometry, centered in the middle of the screen
+ // on a black background.
+ const bool wasResizable = m_nsWindow.styleMask & NSResizableWindowMask;
+ m_nsWindow.styleMask |= NSResizableWindowMask;
+
+ // It also needs to have the correct collection behavior for the
+ // toggleFullScreen call to have an effect.
+ const bool wasFullScreenEnabled = m_nsWindow.collectionBehavior & NSWindowCollectionBehaviorFullScreenPrimary;
+ m_nsWindow.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
+
+ const id sender = m_nsWindow;
+ [m_nsWindow toggleFullScreen:sender];
+
+ if (!wasResizable)
+ m_nsWindow.styleMask &= ~NSResizableWindowMask;
+ if (!wasFullScreenEnabled)
+ m_nsWindow.collectionBehavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
+}
+
+bool QCocoaWindow::isTransitioningToFullScreen() const
+{
+ NSWindow *window = m_view.window;
+ return window.styleMask & NSFullScreenWindowMask && !window.qt_fullScreen;
+}
+
+Qt::WindowState QCocoaWindow::windowState() const
+{
+ // FIXME: Support compound states (Qt::WindowStates)
+
+ NSWindow *window = m_view.window;
+ if (window.miniaturized)
+ return Qt::WindowMinimized;
+ if (window.qt_fullScreen)
+ return Qt::WindowFullScreen;
+ if ((window.zoomed && !isTransitioningToFullScreen())
+ || (m_lastReportedWindowState == Qt::WindowMaximized && isTransitioningToFullScreen()))
+ return Qt::WindowMaximized;
+
+ // Note: We do not report Qt::WindowActive, even if isActive()
+ // is true, as QtGui does not expect this window state to be set.
+
+ return Qt::WindowNoState;
+}
+
+void QCocoaWindow::reportCurrentWindowState(bool unconditionally)
+{
+ Qt::WindowState currentState = windowState();
+ if (!unconditionally && currentState == m_lastReportedWindowState)
+ return;
- // New state is now the current synched state
- m_synchedWindowState = predictedState;
+ QWindowSystemInterface::handleWindowStateChanged<QWindowSystemInterface::SynchronousDelivery>(
+ window(), currentState, m_lastReportedWindowState);
+ m_lastReportedWindowState = currentState;
}
bool QCocoaWindow::setWindowModified(bool modified)
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index 84be7eb797..75a508370f 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -100,8 +100,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
- (void)drawRect:(NSRect)dirtyRect;
- (void)drawBackingStoreUsingCoreGraphics:(NSRect)dirtyRect;
- (void)updateGeometry;
-- (void)notifyWindowStateChanged:(Qt::WindowState)newState;
-- (void)notifyWindowWillZoom:(BOOL)willZoom;
- (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification;
- (void)viewDidHide;
- (void)viewDidUnhide;
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 7ce407f7d0..fbf4f99f2e 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -339,21 +339,6 @@ static bool _q_dontOverrideCtrlLMB = false;
}
}
-- (void)notifyWindowStateChanged:(Qt::WindowState)newState
-{
- // If the window was maximized, then fullscreen, then tried to go directly to "normal" state,
- // this notification will say that it is "normal", but it will still look maximized, and
- // if you called performZoom it would actually take it back to "normal".
- // So we should say that it is maximized because it actually is.
- if (newState == Qt::WindowNoState && m_platformWindow->m_effectivelyMaximized)
- newState = Qt::WindowMaximized;
- QWindowSystemInterface::handleWindowStateChanged(m_platformWindow->window(), newState);
- // We want to read the window state back from the window,
- // but the event we just sent may be asynchronous.
- QWindowSystemInterface::flushWindowSystemEvents();
- m_platformWindow->setSynchedWindowStateFromWindow();
-}
-
- (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification
{
Q_UNUSED(textInputContextKeyboardSelectionDidChangeNotification)
@@ -363,14 +348,6 @@ static bool _q_dontOverrideCtrlLMB = false;
}
}
-- (void)notifyWindowWillZoom:(BOOL)willZoom
-{
- Qt::WindowState newState = willZoom ? Qt::WindowMaximized : Qt::WindowNoState;
- if (!willZoom)
- m_platformWindow->m_effectivelyMaximized = false;
- [self notifyWindowStateChanged:newState];
-}
-
- (void)viewDidHide
{
m_platformWindow->obscureWindow();
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h
index a465b249c5..d2078b5786 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.h
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h
@@ -52,7 +52,6 @@
- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow;
- (BOOL)windowShouldClose:(NSNotification *)notification;
-- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame;
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu;
- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard;
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
index 2d5afa9375..ce74aa9973 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
@@ -41,6 +41,7 @@
#include "qcocoahelpers.h"
#include <QDebug>
+#include <qpa/qplatformscreen.h>
#include <qpa/qwindowsysteminterface.h>
@implementation QNSWindowDelegate
@@ -62,13 +63,19 @@
return YES;
}
-
-- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame
+/*!
+ Overridden to ensure that the zoomed state always results in a maximized
+ window, which would otherwise not be the case for borderless windows.
+*/
+- (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)newFrame
{
Q_UNUSED(newFrame);
- if (m_cocoaWindow && !m_cocoaWindow->isForeignWindow())
- [qnsview_cast(m_cocoaWindow->view()) notifyWindowWillZoom:![window isZoomed]];
- return YES;
+
+ // We explicitly go through the QScreen API here instead of just using
+ // window.screen.visibleFrame directly, as that ensures we have the same
+ // behavior for both use-cases/APIs.
+ Q_ASSERT(window == m_cocoaWindow->nativeWindow());
+ return m_cocoaWindow->screen()->availableGeometry().toCGRect();
}
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp
index 8a059ba973..1abc430da6 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp
@@ -122,13 +122,13 @@ EGLNativeWindowType QEglFSEmulatorIntegration::createNativeWindow(QPlatformWindo
{
Q_UNUSED(size);
Q_UNUSED(format);
- static QAtomicInt uniqueWindowId(1);
QEglFSEmulatorScreen *screen = static_cast<QEglFSEmulatorScreen *>(platformWindow->screen());
if (screen && setDisplay) {
// Let the emulator know which screen the window surface is attached to
setDisplay(screen->id());
}
- return EGLNativeWindowType(qintptr(uniqueWindowId.fetchAndAddRelaxed(1)));
+ static QBasicAtomicInt uniqueWindowId = Q_BASIC_ATOMIC_INITIALIZER(0);
+ return EGLNativeWindowType(qintptr(1 + uniqueWindowId.fetchAndAddRelaxed(1)));
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index 27632de688..a5c05bf1a3 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -56,6 +56,10 @@
# define WM_GESTURE 0x0119
#endif
+#ifndef WM_DPICHANGED
+# define WM_DPICHANGED 0x02E0
+#endif
+
QT_BEGIN_NAMESPACE
namespace QtWindows
@@ -96,6 +100,7 @@ enum WindowsEventType // Simplify event types
FocusInEvent = WindowEventFlag + 17,
FocusOutEvent = WindowEventFlag + 18,
WhatsThisEvent = WindowEventFlag + 19,
+ DpiChangedEvent = WindowEventFlag + 21,
MouseEvent = MouseEventFlag + 1,
MouseWheelEvent = MouseEventFlag + 2,
CursorEvent = MouseEventFlag + 3,
@@ -266,6 +271,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
#endif
case WM_GESTURE:
return QtWindows::GestureEvent;
+ case WM_DPICHANGED:
+ return QtWindows::DpiChangedEvent;
default:
break;
}
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index fefc848d01..5745fc6d19 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -1088,6 +1088,15 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return true;
#endif
} break;
+ case QtWindows::DpiChangedEvent: {
+ platformWindow->setFlag(QWindowsWindow::WithinDpiChanged);
+ const RECT *prcNewWindow = reinterpret_cast<RECT *>(lParam);
+ SetWindowPos(hwnd, NULL, prcNewWindow->left, prcNewWindow->top,
+ prcNewWindow->right - prcNewWindow->left,
+ prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE);
+ platformWindow->clearFlag(QWindowsWindow::WithinDpiChanged);
+ return true;
+ }
#if !defined(QT_NO_SESSIONMANAGER)
case QtWindows::QueryEndSessionApplicationEvent: {
QWindowsSessionManager *sessionManager = platformSessionManager();
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h
index 23d2fd0d09..dfaa428520 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.h
+++ b/src/plugins/platforms/windows/qwindowsglcontext.h
@@ -48,6 +48,7 @@
#include <vector>
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_OPENGL
class QDebug;
@@ -227,7 +228,7 @@ private:
GLenum (APIENTRY * m_getGraphicsResetStatus)();
bool m_lost;
};
-
+#endif
QT_END_NAMESPACE
#endif // QWINDOWSGLCONTEXT_H
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index bd598630ba..24fb12d27a 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -82,6 +82,7 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
if (GetMonitorInfo(hMonitor, &info) == FALSE)
return false;
+ data->hMonitor = hMonitor;
data->geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
data->availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1));
data->name = QString::fromWCharArray(info.szDevice);
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index 00722e2fa4..9a8997326b 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -69,6 +69,7 @@ struct QWindowsScreenData
QString name;
Qt::ScreenOrientation orientation = Qt::LandscapeOrientation;
qreal refreshRateHz = 60;
+ HMONITOR hMonitor = nullptr;
};
class QWindowsScreen : public QPlatformScreen
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 0b6318ce9f..121fdaeabd 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -43,7 +43,11 @@
#include "qwindowsscreen.h"
#include "qwindowsintegration.h"
#include "qwindowsnativeinterface.h"
-#include "qwindowsglcontext.h"
+#if QT_CONFIG(dynamicgl)
+# include "qwindowsglcontext.h"
+#else
+# include "qwindowsopenglcontext.h"
+#endif
#ifdef QT_NO_CURSOR
# include "qwindowscursor.h"
#endif
@@ -1546,10 +1550,16 @@ void QWindowsWindow::handleGeometryChange()
&& !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) {
fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true);
}
- if (previousGeometry.topLeft() != m_data.geometry.topLeft()) {
- QPlatformScreen *newScreen = screenForGeometry(m_data.geometry);
- if (newScreen != screen())
- QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen());
+ if (!parent() && previousGeometry.topLeft() != m_data.geometry.topLeft()) {
+ HMONITOR hMonitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTONULL);
+ QPlatformScreen *currentScreen = screen();
+ const auto screens = QWindowsContext::instance()->screenManager().screens();
+ auto newScreenIt = std::find_if(screens.begin(), screens.end(), [&](QWindowsScreen *s) {
+ return s->data().hMonitor == hMonitor
+ && s->data().flags & QWindowsScreenData::VirtualDesktop;
+ });
+ if (newScreenIt != screens.end() && *newScreenIt != currentScreen)
+ QWindowSystemInterface::handleWindowScreenChanged(window(), (*newScreenIt)->screen());
}
if (testFlag(SynchronousGeometryChangeEvent))
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
@@ -1629,7 +1639,8 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
if (message == WM_ERASEBKGND) // Backing store - ignored.
return true;
// Ignore invalid update bounding rectangles
- if (!GetUpdateRect(m_data.hwnd, 0, FALSE))
+ RECT updateRect;
+ if (!GetUpdateRect(m_data.hwnd, &updateRect, FALSE))
return false;
PAINTSTRUCT ps;
@@ -1653,7 +1664,7 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
// we still need to send isExposed=true, for compatibility.
// Our tests depend on it.
fireExpose(QRegion(qrectFromRECT(ps.rcPaint)), true);
- if (!QWindowsContext::instance()->asyncExpose())
+ if (qSizeOfRect(updateRect) == m_data.geometry.size() && !QWindowsContext::instance()->asyncExpose())
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
EndPaint(hwnd, &ps);
@@ -2121,8 +2132,12 @@ void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
{
- const QWindowsGeometryHint hint(window(), m_data.customMargins);
- hint.applyToMinMaxInfo(m_data.hwnd, mmi);
+ // We don't apply the min/max size hint as we change the dpi, because we did not adjust the
+ // QScreen of the window yet so we don't have the min/max with the right ratio
+ if (!testFlag(QWindowsWindow::WithinDpiChanged)) {
+ const QWindowsGeometryHint hint(window(), m_data.customMargins);
+ hint.applyToMinMaxInfo(m_data.hwnd, mmi);
+ }
if ((testFlag(WithinMaximize) || (window()->windowState() == Qt::WindowMinimized))
&& (m_data.flags & Qt::FramelessWindowHint)) {
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index bc4f6216ba..227b79a207 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -205,7 +205,8 @@ public:
MaximizeToFullScreen = 0x80000,
InputMethodDisabled = 0x100000,
Compositing = 0x200000,
- HasBorderInFullScreen = 0x400000
+ HasBorderInFullScreen = 0x400000,
+ WithinDpiChanged = 0x800000,
};
QWindowsWindow(QWindow *window, const QWindowsWindowData &data);
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 3444b21654..8c5f8cae08 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -605,7 +605,8 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeXRender();
#if defined(XCB_USE_XINPUT2)
- initializeXInput2();
+ if (!qEnvironmentVariableIsSet("QT_XCB_NO_XI2"))
+ initializeXInput2();
#endif
initializeXShape();
initializeXKB();
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index acdcc996b7..f70c7138b3 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -226,6 +226,9 @@ void QXcbConnection::xi2SetupDevices()
isTablet = true;
tabletData.pointerType = QTabletEvent::Pen;
dbgType = QLatin1String("pen");
+ } else if (name.contains("uc-logic") && isTablet) {
+ tabletData.pointerType = QTabletEvent::Pen;
+ dbgType = QLatin1String("pen");
} else {
isTablet = false;
}