macOS: Rewrite window state handling
Instead of relying on specific notifications to change the window state we now evaluate the state based on the current window state. This allows us to get rid of windowShouldZoom in the window delegate, making window state handling work for foreign windows as well, and also allows us to re-evaluate the state in more places, such as when moving a window, which may bring it out of maximized state. The full screen state is tracked by a helper category that doesn't just rely on the styleFlag, but also on the full screen notifications. This is needed as macOS will complain if you try to go in or out of fullscreen while a transition is in effect. The differentiation between performFoo: and foo: has been removed, as the latter works in both cases and doesn't rely on the button being visible/enabled. These changes fixes many observed quirks in the window state handling that also resulted in making it hard to write tests that relied on the fullscreen/maximized operations always working. Change-Id: I0538c42d9223a56f20ec9156f4939288e0750552 Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io> Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
925a3c6529
commit
ef32f16fc2
@ -217,7 +217,7 @@ public:
|
|||||||
bool windowShouldClose();
|
bool windowShouldClose();
|
||||||
bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const;
|
bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const;
|
||||||
|
|
||||||
void handleWindowStateChanged(Qt::WindowState);
|
void reportCurrentWindowState(bool unconditionally = false);
|
||||||
|
|
||||||
NSInteger windowLevel(Qt::WindowFlags flags);
|
NSInteger windowLevel(Qt::WindowFlags flags);
|
||||||
NSUInteger windowStyleMask(Qt::WindowFlags flags);
|
NSUInteger windowStyleMask(Qt::WindowFlags flags);
|
||||||
@ -284,10 +284,15 @@ protected:
|
|||||||
QCocoaNSWindow *createNSWindow(bool shouldBeChildNSWindow, bool shouldBePanel);
|
QCocoaNSWindow *createNSWindow(bool shouldBeChildNSWindow, bool shouldBePanel);
|
||||||
|
|
||||||
QRect nativeWindowGeometry() const;
|
QRect nativeWindowGeometry() const;
|
||||||
void syncWindowState(Qt::WindowState newState);
|
|
||||||
void reinsertChildWindow(QCocoaWindow *child);
|
void reinsertChildWindow(QCocoaWindow *child);
|
||||||
void removeChildWindow(QCocoaWindow *child);
|
void removeChildWindow(QCocoaWindow *child);
|
||||||
|
|
||||||
|
Qt::WindowState windowState() const;
|
||||||
|
void applyWindowState(Qt::WindowState newState);
|
||||||
|
void toggleMaximized();
|
||||||
|
void toggleFullScreen();
|
||||||
|
bool isTransitioningToFullScreen() const;
|
||||||
|
|
||||||
// private:
|
// private:
|
||||||
public: // for QNSView
|
public: // for QNSView
|
||||||
friend class QCocoaBackingStore;
|
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
|
bool m_viewIsToBeEmbedded; // true if the m_view is intended to be embedded in a "foreign" NSView hiearchy
|
||||||
|
|
||||||
Qt::WindowFlags m_windowFlags;
|
Qt::WindowFlags m_windowFlags;
|
||||||
bool m_effectivelyMaximized;
|
Qt::WindowState m_lastReportedWindowState;
|
||||||
Qt::WindowState m_synchedWindowState;
|
|
||||||
Qt::WindowModality m_windowModality;
|
Qt::WindowModality m_windowModality;
|
||||||
QPointer<QWindow> m_enterLeaveTargetWindow;
|
QPointer<QWindow> m_enterLeaveTargetWindow;
|
||||||
bool m_windowUnderMouse;
|
bool m_windowUnderMouse;
|
||||||
@ -339,11 +343,6 @@ public: // for QNSView
|
|||||||
int m_topContentBorderThickness;
|
int m_topContentBorderThickness;
|
||||||
int m_bottomContentBorderThickness;
|
int m_bottomContentBorderThickness;
|
||||||
|
|
||||||
// used by showFullScreen in fake mode
|
|
||||||
QRect m_normalGeometry;
|
|
||||||
Qt::WindowFlags m_oldWindowFlags;
|
|
||||||
NSApplicationPresentationOptions m_presentationOptions;
|
|
||||||
|
|
||||||
struct BorderRange {
|
struct BorderRange {
|
||||||
BorderRange(quintptr i, int u, int l) : identifier(i), upper(u), lower(l) { }
|
BorderRange(quintptr i, int u, int l) : identifier(i), upper(u), lower(l) { }
|
||||||
quintptr identifier;
|
quintptr identifier;
|
||||||
|
@ -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
|
@implementation QNSWindowHelper
|
||||||
|
|
||||||
@synthesize window = _window;
|
@synthesize window = _window;
|
||||||
@ -409,8 +439,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
|
|||||||
, m_nsWindow(0)
|
, m_nsWindow(0)
|
||||||
, m_viewIsEmbedded(false)
|
, m_viewIsEmbedded(false)
|
||||||
, m_viewIsToBeEmbedded(false)
|
, m_viewIsToBeEmbedded(false)
|
||||||
, m_effectivelyMaximized(false)
|
, m_lastReportedWindowState(Qt::WindowNoState)
|
||||||
, m_synchedWindowState(Qt::WindowActive)
|
|
||||||
, m_windowModality(Qt::NonModal)
|
, m_windowModality(Qt::NonModal)
|
||||||
, m_windowUnderMouse(false)
|
, m_windowUnderMouse(false)
|
||||||
, m_inConstructor(true)
|
, m_inConstructor(true)
|
||||||
@ -435,7 +464,6 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
|
|||||||
, m_drawContentBorderGradient(false)
|
, m_drawContentBorderGradient(false)
|
||||||
, m_topContentBorderThickness(0)
|
, m_topContentBorderThickness(0)
|
||||||
, m_bottomContentBorderThickness(0)
|
, m_bottomContentBorderThickness(0)
|
||||||
, m_normalGeometry(QRect(0,0,-1,-1))
|
|
||||||
, m_hasWindowFilePath(false)
|
, m_hasWindowFilePath(false)
|
||||||
{
|
{
|
||||||
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::QCocoaWindow" << window();
|
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
|
// setWindowState might have been called while the window was hidden and
|
||||||
// will not change the NSWindow state in that case. Sync up here:
|
// 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()->windowState() != Qt::WindowMinimized) {
|
||||||
if ((window()->modality() == Qt::WindowModal
|
if ((window()->modality() == Qt::WindowModal
|
||||||
@ -972,7 +1000,7 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
|
|||||||
void QCocoaWindow::setWindowState(Qt::WindowState state)
|
void QCocoaWindow::setWindowState(Qt::WindowState state)
|
||||||
{
|
{
|
||||||
if (window()->isVisible())
|
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)
|
void QCocoaWindow::setWindowTitle(const QString &title)
|
||||||
@ -1248,6 +1276,9 @@ void QCocoaWindow::windowDidMove()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
[qnsview_cast(m_view) updateGeometry];
|
[qnsview_cast(m_view) updateGeometry];
|
||||||
|
|
||||||
|
// Moving a window might bring it out of maximized state
|
||||||
|
reportCurrentWindowState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QCocoaWindow::windowDidResize()
|
void QCocoaWindow::windowDidResize()
|
||||||
@ -1260,6 +1291,9 @@ void QCocoaWindow::windowDidResize()
|
|||||||
|
|
||||||
clipChildWindows();
|
clipChildWindows();
|
||||||
[qnsview_cast(m_view) updateGeometry];
|
[qnsview_cast(m_view) updateGeometry];
|
||||||
|
|
||||||
|
if (!m_view.inLiveResize)
|
||||||
|
reportCurrentWindowState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QCocoaWindow::viewDidChangeFrame()
|
void QCocoaWindow::viewDidChangeFrame()
|
||||||
@ -1281,10 +1315,7 @@ void QCocoaWindow::viewDidChangeGlobalFrame()
|
|||||||
|
|
||||||
void QCocoaWindow::windowDidEndLiveResize()
|
void QCocoaWindow::windowDidEndLiveResize()
|
||||||
{
|
{
|
||||||
if (m_synchedWindowState == Qt::WindowMaximized && ![m_nsWindow isZoomed]) {
|
reportCurrentWindowState();
|
||||||
m_effectivelyMaximized = false;
|
|
||||||
handleWindowStateChanged(Qt::WindowNoState);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QCocoaWindow::windowDidBecomeKey()
|
void QCocoaWindow::windowDidBecomeKey()
|
||||||
@ -1321,22 +1352,37 @@ void QCocoaWindow::windowDidResignKey()
|
|||||||
|
|
||||||
void QCocoaWindow::windowDidMiniaturize()
|
void QCocoaWindow::windowDidMiniaturize()
|
||||||
{
|
{
|
||||||
handleWindowStateChanged(Qt::WindowMinimized);
|
reportCurrentWindowState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QCocoaWindow::windowDidDeminiaturize()
|
void QCocoaWindow::windowDidDeminiaturize()
|
||||||
{
|
{
|
||||||
handleWindowStateChanged(Qt::WindowNoState);
|
reportCurrentWindowState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QCocoaWindow::windowDidEnterFullScreen()
|
void QCocoaWindow::windowDidEnterFullScreen()
|
||||||
{
|
{
|
||||||
handleWindowStateChanged(Qt::WindowFullScreen);
|
Q_ASSERT_X(m_nsWindow.qt_fullScreen, "QCocoaWindow",
|
||||||
|
"FullScreen category processes window notifications first");
|
||||||
|
|
||||||
|
reportCurrentWindowState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QCocoaWindow::windowDidExitFullScreen()
|
void QCocoaWindow::windowDidExitFullScreen()
|
||||||
{
|
{
|
||||||
handleWindowStateChanged(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()
|
void QCocoaWindow::windowDidOrderOffScreen()
|
||||||
@ -1748,99 +1794,155 @@ QRect QCocoaWindow::nativeWindowGeometry() const
|
|||||||
return qRect;
|
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)
|
if (!m_nsWindow)
|
||||||
return;
|
return;
|
||||||
// if content view width or height is 0 then the window animations will crash so
|
|
||||||
// do nothing except set the new state
|
const NSSize contentSize = m_view.frame.size;
|
||||||
NSRect contentRect = m_view.frame;
|
if (contentSize.width <= 0 || contentSize.height <= 0) {
|
||||||
if (contentRect.size.width <= 0 || contentRect.size.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");
|
qWarning("invalid window content view size, check your window geometry");
|
||||||
m_synchedWindowState = newState;
|
reportCurrentWindowState(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::WindowState predictedState = newState;
|
if (m_nsWindow.styleMask & NSUtilityWindowMask) {
|
||||||
if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized)) {
|
// Utility panels cannot be fullscreen
|
||||||
const int styleMask = [m_nsWindow styleMask];
|
qWarning() << window()->type() << "windows can not be made full screen";
|
||||||
const bool usePerform = styleMask & NSResizableWindowMask;
|
reportCurrentWindowState(true);
|
||||||
[m_nsWindow setStyleMask:styleMask | NSResizableWindowMask];
|
return;
|
||||||
if (usePerform)
|
|
||||||
[m_nsWindow performZoom : m_nsWindow]; // toggles
|
|
||||||
else
|
|
||||||
[m_nsWindow zoom : m_nsWindow]; // toggles
|
|
||||||
[m_nsWindow setStyleMask:styleMask];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_synchedWindowState & Qt::WindowMinimized) != (newState & Qt::WindowMinimized)) {
|
const id sender = m_nsWindow;
|
||||||
if (newState & Qt::WindowMinimized) {
|
|
||||||
if ([m_nsWindow styleMask] & NSMiniaturizableWindowMask)
|
// First we need to exit states that can't transition directly to other states
|
||||||
[m_nsWindow performMiniaturize : m_nsWindow];
|
switch (currentState) {
|
||||||
else
|
case Qt::WindowMinimized:
|
||||||
[m_nsWindow miniaturize : m_nsWindow];
|
[m_nsWindow deminiaturize:sender];
|
||||||
} else {
|
Q_ASSERT_X(windowState() != Qt::WindowMinimized, "QCocoaWindow",
|
||||||
[m_nsWindow deminiaturize : m_nsWindow];
|
"[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;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// New state is now the current synched state
|
|
||||||
m_synchedWindowState = predictedState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QCocoaWindow::handleWindowStateChanged(Qt::WindowState newState)
|
void QCocoaWindow::toggleMaximized()
|
||||||
{
|
{
|
||||||
// If the window was maximized, then fullscreen, then tried to go directly to "normal" state,
|
// The NSWindow needs to be resizable, otherwise the window will
|
||||||
// this notification will say that it is "normal", but it will still look maximized, and
|
// not be possible to zoom back to non-zoomed state.
|
||||||
// if you called performZoom it would actually take it back to "normal".
|
const bool wasResizable = m_nsWindow.styleMask & NSResizableWindowMask;
|
||||||
// So we should say that it is maximized because it actually is.
|
m_nsWindow.styleMask |= NSResizableWindowMask;
|
||||||
if (newState == Qt::WindowNoState && m_effectivelyMaximized)
|
|
||||||
newState = Qt::WindowMaximized;
|
|
||||||
|
|
||||||
QWindowSystemInterface::handleWindowStateChanged<QWindowSystemInterface::SynchronousDelivery>(window(), newState);
|
const id sender = m_nsWindow;
|
||||||
|
[m_nsWindow zoom:sender];
|
||||||
|
|
||||||
m_synchedWindowState = window()->windowState();
|
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;
|
||||||
|
|
||||||
|
QWindowSystemInterface::handleWindowStateChanged<QWindowSystemInterface::SynchronousDelivery>(
|
||||||
|
window(), currentState, m_lastReportedWindowState);
|
||||||
|
m_lastReportedWindowState = currentState;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QCocoaWindow::setWindowModified(bool modified)
|
bool QCocoaWindow::setWindowModified(bool modified)
|
||||||
|
@ -100,7 +100,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
|
|||||||
- (void)drawRect:(NSRect)dirtyRect;
|
- (void)drawRect:(NSRect)dirtyRect;
|
||||||
- (void)drawBackingStoreUsingCoreGraphics:(NSRect)dirtyRect;
|
- (void)drawBackingStoreUsingCoreGraphics:(NSRect)dirtyRect;
|
||||||
- (void)updateGeometry;
|
- (void)updateGeometry;
|
||||||
- (void)notifyWindowWillZoom:(BOOL)willZoom;
|
|
||||||
- (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification;
|
- (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification;
|
||||||
- (void)viewDidHide;
|
- (void)viewDidHide;
|
||||||
- (void)viewDidUnhide;
|
- (void)viewDidUnhide;
|
||||||
|
@ -348,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;
|
|
||||||
m_platformWindow->handleWindowStateChanged(newState);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)viewDidHide
|
- (void)viewDidHide
|
||||||
{
|
{
|
||||||
m_platformWindow->obscureWindow();
|
m_platformWindow->obscureWindow();
|
||||||
|
@ -52,7 +52,6 @@
|
|||||||
- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow;
|
- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow;
|
||||||
|
|
||||||
- (BOOL)windowShouldClose:(NSNotification *)notification;
|
- (BOOL)windowShouldClose:(NSNotification *)notification;
|
||||||
- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame;
|
|
||||||
|
|
||||||
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu;
|
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu;
|
||||||
- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard;
|
- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard;
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "qcocoahelpers.h"
|
#include "qcocoahelpers.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <qpa/qplatformscreen.h>
|
||||||
#include <qpa/qwindowsysteminterface.h>
|
#include <qpa/qwindowsysteminterface.h>
|
||||||
|
|
||||||
@implementation QNSWindowDelegate
|
@implementation QNSWindowDelegate
|
||||||
@ -62,13 +63,19 @@
|
|||||||
|
|
||||||
return YES;
|
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);
|
Q_UNUSED(newFrame);
|
||||||
if (m_cocoaWindow && !m_cocoaWindow->isForeignWindow())
|
|
||||||
[qnsview_cast(m_cocoaWindow->view()) notifyWindowWillZoom:![window isZoomed]];
|
// We explicitly go through the QScreen API here instead of just using
|
||||||
return YES;
|
// 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
|
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu
|
||||||
|
Loading…
Reference in New Issue
Block a user