5#if !defined(QNSWINDOW_PROTOCOL_IMPLMENTATION)
7#include <AppKit/AppKit.h>
15#include <qpa/qwindowsysteminterface.h>
17#include <QtGui/private/qhighdpiscaling_p.h>
19Q_STATIC_LOGGING_CATEGORY(lcQpaEvents,
"qt.qpa.events");
21@implementation NSWindow (FullScreenProperty)
25 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
26 [center addObserverForName:NSWindowDidEnterFullScreenNotification object:nil queue:nil
27 usingBlock:^(NSNotification *notification) {
28 objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
29 @(YES), OBJC_ASSOCIATION_RETAIN);
32 [center addObserverForName:NSWindowDidExitFullScreenNotification object:nil queue:nil
33 usingBlock:^(NSNotification *notification) {
34 objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
35 nil, OBJC_ASSOCIATION_RETAIN);
42 NSNumber *number = objc_getAssociatedObject(self, @selector(qt_fullScreen));
43 return [number boolValue];
49NSWindow<QNSWindowProtocol> *qnswindow_cast(NSWindow *window)
51 if ([window conformsToProtocol:@protocol(QNSWindowProtocol)])
52 return static_cast<QCocoaNSWindow *>(window);
58@implementation QNSWindow
59#define QNSWINDOW_PROTOCOL_IMPLMENTATION 1
61#undef QNSWINDOW_PROTOCOL_IMPLMENTATION
63+ (
void)applicationActivationChanged:(NSNotification*)notification
65 const id sender = self;
66 NSEnumerator<NSWindow*> *windowEnumerator =
nullptr;
67 NSApplication *application = [NSApplication sharedApplication];
71 NSMutableArray<NSWindow *> *windows = [[NSMutableArray<NSWindow *>
new] autorelease];
72 [application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
73 usingBlock:^(NSWindow *window, BOOL *) {
78 [windows addObject:window];
82 windowEnumerator = windows.reverseObjectEnumerator;
84 for (NSWindow *window in windowEnumerator) {
86 if (!(window.level == NSNormalWindowLevel || window.level == NSFloatingWindowLevel))
94 if (window.hidesOnDeactivate)
97 if ([window conformsToProtocol:@protocol(QNSWindowProtocol)]) {
98 if (QCocoaWindow *cocoaWindow =
static_cast<QCocoaNSWindow *>(window).platformWindow) {
99 window.level = notification.name == NSApplicationWillResignActiveNotification ?
100 NSNormalWindowLevel : cocoaWindow->windowLevel(cocoaWindow->window()->flags());
116 [window orderFront:sender];
122@implementation QNSPanel
123#define QNSWINDOW_PROTOCOL_IMPLMENTATION 1
125#undef QNSWINDOW_PROTOCOL_IMPLMENTATION
127- (BOOL)worksWhenModal
129 if (!m_platformWindow)
143 if (!NSApp.modalWindow)
150 Qt::WindowType type = m_platformWindow->window()->type();
151 if (type == Qt::Popup)
156 if (![NSApp.modalWindow conformsToProtocol:@protocol(QNSWindowProtocol)])
159 if (
auto *modalWindow =
static_cast<QCocoaNSWindow *>(NSApp.modalWindow).platformWindow) {
160 if (modalWindow->window()->isAncestorOf(m_platformWindow->window(), QWindow::IncludeTransients))
174 QPointer<QCocoaWindow> m_platformWindow;
178- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style
179 backing:(NSBackingStoreType)backingStoreType defer:(BOOL)defer screen:(NSScreen *)screen
180 platformWindow:(QCocoaWindow*)window
185 m_platformWindow = window;
187 m_isMinimizing =
false;
189 return [super initWithContentRect:contentRect styleMask:style backing:backingStoreType defer:defer screen:screen];
192- (QCocoaWindow *)platformWindow
194 return m_platformWindow;
197- (
void)setContentView:(NSView*)view
199 [super setContentView:view];
201 if (!qnsview_cast(self.contentView))
208 const QWindow *window = m_platformWindow->window();
209 qCDebug(lcQpaWindow) <<
"Reflecting" << window <<
"state to" << self;
211 m_platformWindow->propagateSizeHints();
212 m_platformWindow->setWindowFlags(window->flags());
213 m_platformWindow->setWindowTitle(window->title());
214 m_platformWindow->setWindowFilePath(window->filePath());
215 m_platformWindow->setWindowState(window->windowState());
216 m_platformWindow->setOpacity(window->opacity());
225 m_platformWindow->setGeometry(QHighDpi::toNativeWindowGeometry(window->geometry(), window));
228 m_platformWindow->setVisible(window->isVisible());
231- (
void)setStyleMask:(NSWindowStyleMask)styleMask
237 [[self.windowController retain] autorelease];
239 [super setStyleMask:styleMask];
242- (NSString *)description
244 NSMutableString *description = [NSMutableString stringWithString:[super description]];
246#ifndef QT_NO_DEBUG_STREAM
247 QString contentViewDescription;
248 QDebug debug(&contentViewDescription);
249 debug.nospace() <<
"; contentView=" << qnsview_cast(self.contentView) <<
">";
251 NSRange lastCharacter = [description rangeOfComposedCharacterSequenceAtIndex:description.length - 1];
252 [description replaceCharactersInRange:lastCharacter withString:contentViewDescription.toNSString()];
258- (BOOL)canBecomeKeyWindow
260 if (!m_platformWindow)
263 if (m_platformWindow->shouldRefuseKeyWindowAndFirstResponder())
266 if ([self isKindOfClass:[QNSPanel
class]]) {
268 Qt::WindowType type = m_platformWindow->window()->type();
269 if (type == Qt::Tool || type == Qt::Dialog)
281- (BOOL)canBecomeMainWindow
285 if (!m_platformWindow || m_platformWindow->window()->transientParent())
288 return [super canBecomeMainWindow];
293 return m_platformWindow ? m_platformWindow->isOpaque() : [super isOpaque];
296- (NSColor *)backgroundColor
302 const QWindow *window = m_platformWindow ? m_platformWindow->window() :
nullptr;
303 if (!self.opaque && window) {
306 if (window->flags().testFlag(Qt::FramelessWindowHint)
307 || (window->flags() & Qt::WindowType_Mask) == Qt::Popup)
308 return [NSColor clearColor];
314 return [super backgroundColor];
317- (
void)sendEvent:(NSEvent*)theEvent
319 qCDebug(lcQpaEvents) <<
"Sending" << theEvent <<
"to" << self;
326 if (!m_platformWindow)
331 [[self retain] autorelease];
333 const char *eventType = object_getClassName(theEvent);
334 if (QWindowSystemInterface::handleNativeEvent(m_platformWindow->window(),
335 QByteArray::fromRawData(eventType, qstrlen(eventType)), theEvent,
nullptr)) {
339 const bool mouseEventInFrameStrut = [theEvent, self]{
340 if (qt_mac_isMouseEvent(theEvent)) {
341 const NSPoint loc = theEvent.locationInWindow;
342 const NSRect windowFrame = [self convertRectFromScreen:self.frame];
343 const NSRect contentFrame = self.contentView.frame;
344 if (NSMouseInRect(loc, windowFrame, NO) && !NSMouseInRect(loc, contentFrame, NO))
352 if (theEvent.type == NSEventTypeLeftMouseDown && mouseEventInFrameStrut)
353 QGuiApplicationPrivate::instance()->closeAllPopups();
355 [super sendEvent:theEvent];
357 if (!m_platformWindow)
364 if (qt_mac_isMouseEvent(theEvent) && QGuiApplicationPrivate::instance()->activePopupWindow()
365 && QGuiApplicationPrivate::instance()->isWindowBlocked(m_platformWindow->window(),
nullptr)) {
366 qCDebug(lcQpaWindow) <<
"Mouse event over modally blocked window" << m_platformWindow->window()
367 <<
"while popup is open - redirecting";
368 [qnsview_cast(m_platformWindow->view()) handleMouseEvent:theEvent];
370 if (m_platformWindow->frameStrutEventsEnabled() && mouseEventInFrameStrut)
371 [qnsview_cast(m_platformWindow->view()) handleFrameStrutMouseEvent:theEvent];
374- (
void)miniaturize:(id)sender
376 QScopedValueRollback miniaturizeTracker(m_isMinimizing,
true);
377 [super miniaturize:sender];
380- (NSButton *)standardWindowButton:(NSWindowButton)buttonType
382 NSButton *button = [super standardWindowButton:buttonType];
393 if (buttonType == NSWindowMiniaturizeButton && m_isMinimizing && !button.enabled)
394 return [NSWindow standardWindowButton:buttonType forStyleMask:self.styleMask];
399- (
void)closeAndRelease
401 qCDebug(lcQpaWindow) <<
"Closing and releasing" << self;
408 qCDebug(lcQpaWindow) <<
"Deallocating" << self;