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");
24 case NSEventTypeLeftMouseDown:
25 case NSEventTypeLeftMouseUp:
26 case NSEventTypeRightMouseDown:
27 case NSEventTypeRightMouseUp:
28 case NSEventTypeMouseMoved:
29 case NSEventTypeLeftMouseDragged:
30 case NSEventTypeRightMouseDragged:
37@implementation NSWindow (FullScreenProperty)
41 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
42 [center addObserverForName:NSWindowDidEnterFullScreenNotification object:nil queue:nil
43 usingBlock:^(NSNotification *notification) {
44 objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
45 @(YES), OBJC_ASSOCIATION_RETAIN);
48 [center addObserverForName:NSWindowDidExitFullScreenNotification object:nil queue:nil
49 usingBlock:^(NSNotification *notification) {
50 objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
51 nil, OBJC_ASSOCIATION_RETAIN);
58 NSNumber *number = objc_getAssociatedObject(self, @selector(qt_fullScreen));
59 return [number boolValue];
65NSWindow<QNSWindowProtocol> *qnswindow_cast(NSWindow *window)
67 if ([window conformsToProtocol:@protocol(QNSWindowProtocol)])
68 return static_cast<QCocoaNSWindow *>(window);
74@implementation QNSWindow
75#define QNSWINDOW_PROTOCOL_IMPLMENTATION 1
77#undef QNSWINDOW_PROTOCOL_IMPLMENTATION
79+ (
void)applicationActivationChanged:(NSNotification*)notification
81 const id sender = self;
82 NSEnumerator<NSWindow*> *windowEnumerator =
nullptr;
83 NSApplication *application = [NSApplication sharedApplication];
87 NSMutableArray<NSWindow *> *windows = [[NSMutableArray<NSWindow *>
new] autorelease];
88 [application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
89 usingBlock:^(NSWindow *window, BOOL *) {
94 [windows addObject:window];
98 windowEnumerator = windows.reverseObjectEnumerator;
100 for (NSWindow *window in windowEnumerator) {
102 if (!(window.level == NSNormalWindowLevel || window.level == NSFloatingWindowLevel))
110 if (window.hidesOnDeactivate)
113 if ([window conformsToProtocol:@protocol(QNSWindowProtocol)]) {
114 if (QCocoaWindow *cocoaWindow =
static_cast<QCocoaNSWindow *>(window).platformWindow) {
115 window.level = notification.name == NSApplicationWillResignActiveNotification ?
116 NSNormalWindowLevel : cocoaWindow->windowLevel(cocoaWindow->window()->flags());
132 [window orderFront:sender];
138@implementation QNSPanel
139#define QNSWINDOW_PROTOCOL_IMPLMENTATION 1
141#undef QNSWINDOW_PROTOCOL_IMPLMENTATION
143- (BOOL)worksWhenModal
145 if (!m_platformWindow)
159 if (!NSApp.modalWindow)
166 Qt::WindowType type = m_platformWindow->window()->type();
167 if (type == Qt::Popup)
172 if (![NSApp.modalWindow conformsToProtocol:@protocol(QNSWindowProtocol)])
175 if (
auto *modalWindow =
static_cast<QCocoaNSWindow *>(NSApp.modalWindow).platformWindow) {
176 if (modalWindow->window()->isAncestorOf(m_platformWindow->window(), QWindow::IncludeTransients))
190 QPointer<QCocoaWindow> m_platformWindow;
194- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style
195 backing:(NSBackingStoreType)backingStoreType defer:(BOOL)defer screen:(NSScreen *)screen
196 platformWindow:(QCocoaWindow*)window
201 m_platformWindow = window;
203 m_isMinimizing =
false;
205 return [super initWithContentRect:contentRect styleMask:style backing:backingStoreType defer:defer screen:screen];
208- (QCocoaWindow *)platformWindow
210 return m_platformWindow;
213- (
void)setContentView:(NSView*)view
215 [super setContentView:view];
217 if (!qnsview_cast(self.contentView))
224 const QWindow *window = m_platformWindow->window();
225 qCDebug(lcQpaWindow) <<
"Reflecting" << window <<
"state to" << self;
227 m_platformWindow->propagateSizeHints();
228 m_platformWindow->setWindowFlags(window->flags());
229 m_platformWindow->setWindowTitle(window->title());
230 m_platformWindow->setWindowFilePath(window->filePath());
231 m_platformWindow->setWindowState(window->windowState());
232 m_platformWindow->setOpacity(window->opacity());
241 m_platformWindow->setGeometry(QHighDpi::toNativeWindowGeometry(window->geometry(), window));
244 m_platformWindow->setVisible(window->isVisible());
247- (NSString *)description
249 NSMutableString *description = [NSMutableString stringWithString:[super description]];
251#ifndef QT_NO_DEBUG_STREAM
252 QString contentViewDescription;
253 QDebug debug(&contentViewDescription);
254 debug.nospace() <<
"; contentView=" << qnsview_cast(self.contentView) <<
">";
256 NSRange lastCharacter = [description rangeOfComposedCharacterSequenceAtIndex:description.length - 1];
257 [description replaceCharactersInRange:lastCharacter withString:contentViewDescription.toNSString()];
263- (BOOL)canBecomeKeyWindow
265 if (!m_platformWindow)
268 if (m_platformWindow->shouldRefuseKeyWindowAndFirstResponder())
271 if ([self isKindOfClass:[QNSPanel
class]]) {
273 Qt::WindowType type = m_platformWindow->window()->type();
274 if (type == Qt::Tool || type == Qt::Dialog)
286- (BOOL)canBecomeMainWindow
290 if (!m_platformWindow || m_platformWindow->window()->transientParent())
293 return [super canBecomeMainWindow];
298 return m_platformWindow ? m_platformWindow->isOpaque() : [super isOpaque];
301- (NSColor *)backgroundColor
307 const QWindow *window = m_platformWindow ? m_platformWindow->window() :
nullptr;
308 if (!self.opaque && window) {
311 if (window->flags().testFlag(Qt::FramelessWindowHint)
312 || (window->flags() & Qt::WindowType_Mask) == Qt::Popup)
313 return [NSColor clearColor];
319 return [super backgroundColor];
322- (
void)sendEvent:(NSEvent*)theEvent
324 qCDebug(lcQpaEvents) <<
"Sending" << theEvent <<
"to" << self;
331 if (!m_platformWindow)
336 [[self retain] autorelease];
338 const char *eventType = object_getClassName(theEvent);
339 if (QWindowSystemInterface::handleNativeEvent(m_platformWindow->window(),
340 QByteArray::fromRawData(eventType, qstrlen(eventType)), theEvent,
nullptr)) {
344 const bool mouseEventInFrameStrut = [theEvent, self]{
345 if (isMouseEvent(theEvent)) {
346 const NSPoint loc = theEvent.locationInWindow;
347 const NSRect windowFrame = [self convertRectFromScreen:self.frame];
348 const NSRect contentFrame = self.contentView.frame;
349 if (NSMouseInRect(loc, windowFrame, NO) && !NSMouseInRect(loc, contentFrame, NO))
357 if (theEvent.type == NSEventTypeLeftMouseDown && mouseEventInFrameStrut)
358 QGuiApplicationPrivate::instance()->closeAllPopups();
360 [super sendEvent:theEvent];
362 if (!m_platformWindow)
369 if (isMouseEvent(theEvent) && QGuiApplicationPrivate::instance()->activePopupWindow()
370 && QGuiApplicationPrivate::instance()->isWindowBlocked(m_platformWindow->window(),
nullptr)) {
371 qCDebug(lcQpaWindow) <<
"Mouse event over modally blocked window" << m_platformWindow->window()
372 <<
"while popup is open - redirecting";
373 [qnsview_cast(m_platformWindow->view()) handleMouseEvent:theEvent];
375 if (m_platformWindow->frameStrutEventsEnabled() && mouseEventInFrameStrut)
376 [qnsview_cast(m_platformWindow->view()) handleFrameStrutMouseEvent:theEvent];
379- (
void)miniaturize:(id)sender
381 QScopedValueRollback miniaturizeTracker(m_isMinimizing,
true);
382 [super miniaturize:sender];
385- (NSButton *)standardWindowButton:(NSWindowButton)buttonType
387 NSButton *button = [super standardWindowButton:buttonType];
398 if (buttonType == NSWindowMiniaturizeButton && m_isMinimizing && !button.enabled)
399 return [NSWindow standardWindowButton:buttonType forStyleMask:self.styleMask];
404- (
void)closeAndRelease
406 qCDebug(lcQpaWindow) <<
"Closing and releasing" << self;
413 qCDebug(lcQpaWindow) <<
"Deallocating" << self;
static bool isMouseEvent(NSEvent *ev)