Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qcocoawindow.mm
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <AppKit/AppKit.h>
5#include <QuartzCore/QuartzCore.h>
6
7#include "qcocoawindow.h"
8#include "qcocoaintegration.h"
9#include "qcocoascreen.h"
10#include "qnswindowdelegate.h"
12#ifndef QT_NO_OPENGL
13#include "qcocoaglcontext.h"
14#endif
15#include "qcocoahelpers.h"
17#include "qnsview.h"
18#include "qnswindow.h"
19#include <QtCore/qfileinfo.h>
20#include <QtCore/private/qcore_mac_p.h>
21#include <qwindow.h>
22#include <private/qwindow_p.h>
23#include <qpa/qwindowsysteminterface.h>
24#include <qpa/qplatformscreen.h>
25#include <QtGui/private/qcoregraphics_p.h>
26#include <QtGui/private/qhighdpiscaling_p.h>
27
28#include <QDebug>
29
30#include <vector>
31
33
34enum {
37};
38
39Q_LOGGING_CATEGORY(lcCocoaNotifications, "qt.qpa.cocoa.notifications");
40
42{
43 static const QLatin1StringView notificationHandlerPrefix(Q_NOTIFICATION_PREFIX);
44
45 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
46
47 const QMetaObject *metaObject = QMetaType(qRegisterMetaType<QCocoaWindow*>()).metaObject();
49
50 for (int i = 0; i < metaObject->methodCount(); ++i) {
51 QMetaMethod method = metaObject->method(i);
52 const QString methodTag = QString::fromLatin1(method.tag());
53 if (!methodTag.startsWith(notificationHandlerPrefix))
54 continue;
55
56 const QString notificationName = methodTag.mid(notificationHandlerPrefix.size());
57 [center addObserverForName:notificationName.toNSString() object:nil queue:nil
58 usingBlock:^(NSNotification *notification) {
59
61 if ([notification.object isKindOfClass:[NSWindow class]]) {
62 NSWindow *nsWindow = notification.object;
64 if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()))
65 if (cocoaWindow->nativeWindow() == nsWindow)
66 cocoaWindows += cocoaWindow;
67 }
68 } else if ([notification.object isKindOfClass:[NSView class]]) {
69 if (QNSView *qnsView = qnsview_cast(notification.object))
70 cocoaWindows += qnsView.platformWindow;
71 } else {
72 qCWarning(lcCocoaNotifications) << "Unhandled notification"
73 << notification.name << "for" << notification.object;
74 return;
75 }
76
77 if (lcCocoaNotifications().isDebugEnabled() && !cocoaWindows.isEmpty()) {
78 QVector<QCocoaWindow *> debugWindows;
79 for (QCocoaWindow *cocoaWindow : cocoaWindows)
80 debugWindows += cocoaWindow;
81 qCDebug(lcCocoaNotifications) << "Forwarding" << qPrintable(notificationName) <<
82 "to" << debugWindows;
83 }
84
85 // FIXME: Could be a foreign window, look up by iterating top level QWindows
86
87 for (QCocoaWindow *cocoaWindow : cocoaWindows) {
88 if (!method.invoke(cocoaWindow, Qt::DirectConnection)) {
89 qCWarning(lcQpaWindow) << "Failed to invoke NSNotification callback for"
90 << notification.name << "on" << cocoaWindow;
91 }
92 }
93 }];
94 }
95}
97
98const int QCocoaWindow::NoAlertRequest = -1;
100
102{
103 qCDebug(lcQpaWindow) << "QCocoaWindow::QCocoaWindow" << window();
104
105 if (nativeHandle) {
106 m_view = reinterpret_cast<NSView *>(nativeHandle);
107 [m_view retain];
108 }
109}
110
112{
113 qCDebug(lcQpaWindow) << "QCocoaWindow::initialize" << window();
114
116
117 if (!m_view)
118 m_view = [[QNSView alloc] initWithCocoaWindow:this];
119
120 if (!isForeignWindow()) {
121 // Compute the initial geometry based on the geometry set on the
122 // QWindow. This geometry has already been reflected to the
123 // QPlatformWindow in the constructor, so to ensure that the
124 // resulting setGeometry call does not think the geometry has
125 // already been applied, we reset the QPlatformWindow's view
126 // of the geometry first.
131
133
134 } else {
135 // Pick up essential foreign window state
136 QPlatformWindow::setGeometry(QRectF::fromCGRect(m_view.frame).toRect());
137 }
138
140
141 m_initialized = true;
142}
143
144const NSNotificationName QCocoaWindowWillReleaseQNSViewNotification = @"QCocoaWindowWillReleaseQNSViewNotification";
145
147{
148 qCDebug(lcQpaWindow) << "QCocoaWindow::~QCocoaWindow" << window();
149
151 [m_nsWindow makeFirstResponder:nil];
152 [m_nsWindow setContentView:nil];
153 if ([m_view superview])
154 [m_view removeFromSuperview];
155
156 // Make sure to disconnect observer in all case if view is valid
157 // to avoid notifications received when deleting when using Qt::AA_NativeWindows attribute
158 if (!isForeignWindow())
159 [[NSNotificationCenter defaultCenter] removeObserver:m_view];
160
161#if QT_CONFIG(vulkan)
162 if (QCocoaIntegration *cocoaIntegration = QCocoaIntegration::instance()) {
163 auto vulcanInstance = cocoaIntegration->getCocoaVulkanInstance();
164 if (vulcanInstance)
165 vulcanInstance->destroySurface(m_vulkanSurface);
166 }
167#endif
168
169 // Must send notification before calling release, as doing it from
170 // [QNSView dealloc] would mean that any weak references to the view
171 // would already return nil.
172 [NSNotificationCenter.defaultCenter
174 object:m_view];
175
176 [m_view release];
179}
180
182{
183 return window()->requestedFormat();
184}
185
187{
188 qCDebug(lcQpaWindow) << "QCocoaWindow::setGeometry" << window() << rectIn;
189
190 QBoolBlocker inSetGeometry(m_inSetGeometry, true);
191
192 QRect rect = rectIn;
193 // This means it is a call from QWindow::setFramePosition() and
194 // the coordinates include the frame (size is still the contents rectangle).
195 if (qt_window_private(const_cast<QWindow *>(window()))->positionPolicy
197 const QMargins margins = frameMargins();
198 rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top()));
199 }
200 if (geometry() == rect)
201 return;
202
204}
205
207{
208 return ![m_view isKindOfClass:[QNSView class]];
209}
210
212{
213 // QWindows that are embedded in a NSView hierarchy may be considered
214 // top-level from Qt's point of view but are not from Cocoa's point
215 // of view. Embedded QWindows get global (screen) geometry.
216 if (isEmbedded()) {
217 NSPoint windowPoint = [m_view convertPoint:NSMakePoint(0, 0) toView:nil];
218 NSRect screenRect = [[m_view window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
219 NSPoint screenPoint = screenRect.origin;
221 QSize size = QRectF::fromCGRect(NSRectToCGRect([m_view bounds])).toRect().size();
222 return QRect(position, size);
223 }
224
226}
227
237{
238 if (!isContentView())
239 return QRect();
240
241 // We only persist the normal the geometry when going into
242 // fullscreen and maximized states. For all other cases we
243 // can just report the geometry as is.
244
246 return geometry();
247
248 return m_normalGeometry;
249}
250
252{
253 if (!isContentView())
254 return;
255
257 return;
258
260}
261
263{
264 qCDebug(lcQpaWindow) << "QCocoaWindow::setCocoaGeometry" << window() << rect;
266
268
269 if (isEmbedded()) {
270 if (!isForeignWindow()) {
271 [m_view setFrame:NSMakeRect(0, 0, rect.width(), rect.height())];
272 }
273 return;
274 }
275
276 if (isContentView()) {
277 NSRect bounds = QCocoaScreen::mapToNative(rect);
278 [m_view.window setFrame:[m_view.window frameRectForContentRect:bounds] display:YES animate:NO];
279 } else {
280 [m_view setFrame:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
281 }
282
283 // will call QPlatformWindow::setGeometry(rect) during resize confirmation (see qnsview.mm)
284}
285
287{
288 switch (NSApp.currentEvent.type) {
289 case NSEventTypeLeftMouseDown:
290 case NSEventTypeRightMouseDown:
291 case NSEventTypeOtherMouseDown:
292 case NSEventTypeMouseMoved:
293 case NSEventTypeLeftMouseDragged:
294 case NSEventTypeRightMouseDragged:
295 case NSEventTypeOtherMouseDragged:
296 // The documentation only describes starting a system move
297 // based on mouse down events, but move events also work.
298 [m_view.window performWindowDragWithEvent:NSApp.currentEvent];
299 return true;
300 default:
301 return false;
302 }
303}
304
305void QCocoaWindow::setVisible(bool visible)
306{
307 qCDebug(lcQpaWindow) << "QCocoaWindow::setVisible" << window() << visible;
308
310
312 QCocoaWindow *parentCocoaWindow = nullptr;
313 if (window()->transientParent())
314 parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle());
315
316 auto eventDispatcher = [] {
317 return static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(qApp->eventDispatcher()));
318 };
319
320 if (visible) {
321 // We need to recreate if the modality has changed as the style mask will need updating
323
324 // We didn't send geometry changes during creation, as that would have confused
325 // Qt, which expects a show-event to be sent before any resize events. But now
326 // that the window is made visible, we know that the show-event has been sent
327 // so we can send the geometry change. FIXME: Get rid of this workaround.
329
330 if (parentCocoaWindow) {
331 // The parent window might have moved while this window was hidden,
332 // update the window geometry if there is a parent.
334
335 if (window()->type() == Qt::Popup) {
336 // QTBUG-30266: a window should not be resizable while a transient popup is open
337 // Since this isn't a native popup, the window manager doesn't close the popup when you click outside
338 NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
339 NSUInteger parentStyleMask = nativeParentWindow.styleMask;
340 if ((m_resizableTransientParent = (parentStyleMask & NSWindowStyleMaskResizable))
341 && !(nativeParentWindow.styleMask & NSWindowStyleMaskFullScreen))
342 nativeParentWindow.styleMask &= ~NSWindowStyleMaskResizable;
343 }
344
345 }
346
347 // Make the NSView visible first, before showing the NSWindow (in case of top level windows)
348 m_view.hidden = NO;
349
350 if (isContentView()) {
352
353 // setWindowState might have been called while the window was hidden and
354 // will not change the NSWindow state in that case. Sync up here:
355 applyWindowState(window()->windowStates());
356
358 if (parentCocoaWindow && (window()->modality() == Qt::WindowModal || window()->type() == Qt::Sheet)) {
359 // Show the window as a sheet
360 NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
361 if (!nativeParentWindow.attachedSheet)
362 [nativeParentWindow beginSheet:m_view.window completionHandler:nil];
363 else
364 [nativeParentWindow beginCriticalSheet:m_view.window completionHandler:nil];
365 } else if (window()->modality() == Qt::ApplicationModal) {
366 // Show the window as application modal
367 eventDispatcher()->beginModalSession(window());
368 } else if (m_view.window.canBecomeKeyWindow) {
369 bool shouldBecomeKeyNow = !NSApp.modalWindow
370 || m_view.window.worksWhenModal
371 || !NSApp.modalWindow.visible;
372
373 // Panels with becomesKeyOnlyIfNeeded set should not activate until a view
374 // with needsPanelToBecomeKey, for example a line edit, is clicked.
375 if ([m_view.window isKindOfClass:[NSPanel class]])
376 shouldBecomeKeyNow &= !(static_cast<NSPanel*>(m_view.window).becomesKeyOnlyIfNeeded);
377
378 if (shouldBecomeKeyNow)
379 [m_view.window makeKeyAndOrderFront:nil];
380 else
381 [m_view.window orderFront:nil];
382 } else {
383 [m_view.window orderFront:nil];
384 }
385 }
386 }
387 } else {
388 // Window not visible, hide it
389 if (isContentView()) {
390 if (eventDispatcher()->hasModalSession()) {
391 eventDispatcher()->endModalSession(window());
392 } else {
393 if ([m_view.window isSheet]) {
394 Q_ASSERT_X(parentCocoaWindow, "QCocoaWindow", "Window modal dialog has no transient parent.");
395 [parentCocoaWindow->nativeWindow() endSheet:m_view.window];
396 }
397 }
398
399 // Note: We do not guard the order out by checking NSWindow.visible, as AppKit will
400 // in some cases, such as when hiding the application, order out and make a window
401 // invisible, but keep it in a list of "hidden windows", that it then restores again
402 // when the application is unhidden. We need to call orderOut explicitly, to bring
403 // the window out of this "hidden list".
404 [m_view.window orderOut:nil];
405
406 if (m_view.window == [NSApp keyWindow] && !eventDispatcher()->hasModalSession()) {
407 // Probably because we call runModalSession: outside [NSApp run] in QCocoaEventDispatcher
408 // (e.g., when show()-ing a modal QDialog instead of exec()-ing it), it can happen that
409 // the current NSWindow is still key after being ordered out. Then, after checking we
410 // don't have any other modal session left, it's safe to make the main window key again.
411 NSWindow *mainWindow = [NSApp mainWindow];
412 if (mainWindow && [mainWindow canBecomeKeyWindow])
413 [mainWindow makeKeyWindow];
414 }
415 }
416
417 m_view.hidden = YES;
418
419 if (parentCocoaWindow && window()->type() == Qt::Popup) {
420 NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
422 && !(nativeParentWindow.styleMask & NSWindowStyleMaskFullScreen))
423 // A window should not be resizable while a transient popup is open
424 nativeParentWindow.styleMask |= NSWindowStyleMaskResizable;
425 }
426 }
427}
428
430{
432
433 NSInteger windowLevel = NSNormalWindowLevel;
434
435 if (type == Qt::Tool)
436 windowLevel = NSFloatingWindowLevel;
437 else if ((type & Qt::Popup) == Qt::Popup)
438 windowLevel = NSPopUpMenuWindowLevel;
439
440 // StayOnTop window should appear above Tool windows.
442 windowLevel = NSModalPanelWindowLevel;
443 // Tooltips should appear above StayOnTop windows.
444 if (type == Qt::ToolTip)
445 windowLevel = NSScreenSaverWindowLevel;
446
447 auto *transientParent = window()->transientParent();
448 if (transientParent && transientParent->handle()) {
449 // We try to keep windows in at least the same window level as
450 // their transient parent. Unfortunately this only works when the
451 // window is created. If the window level changes after that, as
452 // a result of a call to setWindowFlags, or by changing the level
453 // of the native window, we will not pick this up, and the window
454 // will be left behind (or in a different window level than) its
455 // parent. We could KVO-observe the window level of our transient
456 // parent, but that requires us to know when the parent goes away
457 // so that we can unregister the observation before the parent is
458 // dealloced, something we can't do for generic NSWindows. Another
459 // way would be to override [NSWindow setLevel:] and notify child
460 // windows about the change, but that doesn't work for foreign
461 // windows, which can still be transient parents via fromWinId().
462 // One area where this problem is apparent is when AppKit tweaks
463 // the window level of modal windows during application activation
464 // and deactivation. Since we don't pick up on these window level
465 // changes in a generic way, we need to add logic explicitly to
466 // re-evaluate the window level after AppKit has done its tweaks.
467
468 auto *transientCocoaWindow = static_cast<QCocoaWindow *>(transientParent->handle());
469 auto *nsWindow = transientCocoaWindow->nativeWindow();
470
471 // We only upgrade the window level for "special" windows, to work
472 // around Qt Designer parenting the designer windows to the widget
473 // palette window (QTBUG-31779). This should be fixed in designer.
474 if (type != Qt::Window)
475 windowLevel = qMax(windowLevel, nsWindow.level);
476 }
477
478 return windowLevel;
479}
480
482{
483 const Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
484
485 // Determine initial style mask based on whether the window should
486 // have a frame and title or not. The NSWindowStyleMaskBorderless
487 // and NSWindowStyleMaskTitled styles are mutually exclusive, with
488 // values of 0 and 1 correspondingly.
489 NSUInteger styleMask = [&]{
490 // Honor explicit requests for borderless windows
492 return NSWindowStyleMaskBorderless;
493
494 // Popup windows should always be borderless
496 return NSWindowStyleMaskBorderless;
497
499 // CustomizeWindowHint turns off the default window title hints,
500 // so the choice is then up to the user via Qt::WindowTitleHint.
502 ? NSWindowStyleMaskTitled
503 : NSWindowStyleMaskBorderless;
504 } else {
505 // Otherwise, default to using titled windows
506 return NSWindowStyleMaskTitled;
507 }
508 }();
509
510 // We determine which buttons to show in updateTitleBarButtons,
511 // so we can enable all the relevant style masks here to ensure
512 // that behaviors that don't involve the title bar buttons are
513 // working (for example minimizing frameless windows, or resizing
514 // windows that don't have zoom or fullscreen titlebar buttons).
515 styleMask |= NSWindowStyleMaskClosable
516 | NSWindowStyleMaskMiniaturizable;
517
518 if (type != Qt::Popup) // We only care about popups exactly.
519 styleMask |= NSWindowStyleMaskResizable;
520
521 if (type == Qt::Tool)
522 styleMask |= NSWindowStyleMaskUtilityWindow;
523
524 // FIXME: Remove use of deprecated style mask
526 styleMask |= NSWindowStyleMaskTexturedBackground;
527
528 // Don't wipe existing states
529 if (m_view.window.styleMask & NSWindowStyleMaskFullScreen)
530 styleMask |= NSWindowStyleMaskFullScreen;
531 if (m_view.window.styleMask & NSWindowStyleMaskFullSizeContentView)
532 styleMask |= NSWindowStyleMaskFullSizeContentView;
533
534 return styleMask;
535}
536
538{
541}
542
543void QCocoaWindow::updateTitleBarButtons(Qt::WindowFlags windowFlags)
544{
545 if (!isContentView())
546 return;
547
548 static constexpr std::pair<NSWindowButton, Qt::WindowFlags> buttons[] = {
549 { NSWindowCloseButton, Qt::WindowCloseButtonHint },
550 { NSWindowMiniaturizeButton, Qt::WindowMinimizeButtonHint},
552 };
553
554 bool hideButtons = true;
555 for (const auto &[button, buttonHint] : buttons) {
556 // Set up Qt defaults based on window type
557 bool enabled = true;
558 if (button == NSWindowMiniaturizeButton)
559 enabled = window()->type() != Qt::Dialog;
560
561 // Let users override via CustomizeWindowHint
562 if (windowFlags & Qt::CustomizeWindowHint)
563 enabled = windowFlags & buttonHint;
564
565 // Then do some final sanitizations
566
567 if (button == NSWindowZoomButton && isFixedSize())
568 enabled = false;
569
570 // Mimic what macOS natively does for parent windows of modal
571 // sheets, which is to disable the close button, but leave the
572 // other buttons as they were.
573 if (button == NSWindowCloseButton && enabled
574 && QWindowPrivate::get(window())->blockedByModalWindow) {
575 enabled = false;
576 // If we end up having no enabled buttons, our workaround
577 // should not be a reason for hiding all of them.
578 hideButtons = false;
579 }
580
581 [m_view.window standardWindowButton:button].enabled = enabled;
582 hideButtons &= !enabled;
583 }
584
585 // Hide buttons in case we disabled all of them
586 for (const auto &[button, buttonHint] : buttons)
587 [m_view.window standardWindowButton:button].hidden = hideButtons;
588}
589
591{
592 // Updating the window flags may affect the window's theme frame, which
593 // in the process retains and then autoreleases the NSWindow. To make
594 // sure this doesn't leave lingering releases when there is no pool in
595 // place (e.g. during main(), before exec), we add one locally here.
597
598 if (!isContentView())
599 return;
600
601 // While setting style mask we can have handleGeometryChange calls on a content
602 // view with null geometry, reporting an invalid coordinates as a result.
603 m_inSetStyleMask = true;
604 m_view.window.styleMask = windowStyleMask(flags);
605 m_inSetStyleMask = false;
606
608 if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) {
609 NSWindowCollectionBehavior behavior = m_view.window.collectionBehavior;
610 const bool enableFullScreen = m_view.window.qt_fullScreen
613 if (enableFullScreen) {
614 behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
615 behavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary;
616 } else {
617 behavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
618 behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
619 }
620 m_view.window.collectionBehavior = behavior;
621 }
622
623 // Set styleMask and collectionBehavior before applying window level, as
624 // the window level change will trigger verification of the two properties.
625 m_view.window.level = this->windowLevel(flags);
626
627 m_view.window.hasShadow = !(flags & Qt::NoDropShadowWindowHint);
628
631
633
634 // Make window ignore mouse events if WindowTransparentForInput is set.
635 // Note that ignoresMouseEvents has a special initial state where events
636 // are ignored (passed through) based on window transparency, and that
637 // setting the property to false does not return us to that state. Instead,
638 // this makes the window capture all mouse events. Take care to only
639 // set the property if needed. FIXME: recreate window if needed or find
640 // some other way to implement WindowTransparentForInput.
641 bool ignoreMouse = flags & Qt::WindowTransparentForInput;
642 if (m_view.window.ignoresMouseEvents != ignoreMouse)
643 m_view.window.ignoresMouseEvents = ignoreMouse;
644}
645
646// ----------------------- Window state -----------------------
647
656{
657 if (window()->isVisible())
658 applyWindowState(state); // Window state set for hidden windows take effect when show() is called
659}
660
661void QCocoaWindow::applyWindowState(Qt::WindowStates requestedState)
662{
663 if (!isContentView())
664 return;
665
668
669 if (newState == currentState)
670 return;
671
672 qCDebug(lcQpaWindow) << "Applying" << newState << "to" << window() << "in" << currentState;
673
674 const NSSize contentSize = m_view.frame.size;
675 if (contentSize.width <= 0 || contentSize.height <= 0) {
676 // If content view width or height is 0 then the window animations will crash so
677 // do nothing. We report the current state back to reflect the failed operation.
678 qWarning("invalid window content view size, check your window geometry");
680 return;
681 }
682
683 const NSWindow *nsWindow = m_view.window;
684
685 if (nsWindow.styleMask & NSWindowStyleMaskUtilityWindow
687 qWarning() << window()->type() << "windows cannot be made" << newState;
689 return;
690 }
691
692 const id sender = nsWindow;
693
694 // First we need to exit states that can't transition directly to other states
695 switch (currentState) {
697 [nsWindow deminiaturize:sender];
698 // Deminiaturizing is not synchronous, so we need to wait for the
699 // NSWindowDidMiniaturizeNotification before continuing to apply
700 // the new state.
701 return;
704 // Exiting fullscreen is not synchronous, so we need to wait for the
705 // NSWindowDidExitFullScreenNotification before continuing to apply
706 // the new state.
707 return;
708 }
709 default:;
710 }
711
712 // Then we apply the new state if needed
713 if (newState == windowState())
714 return;
715
716 switch (newState) {
719 break;
722 break;
724 [nsWindow miniaturize:sender];
725 break;
729 break;
730 default:
731 Q_UNREACHABLE();
732 }
733}
734
735Qt::WindowStates QCocoaWindow::windowState() const
736{
737 Qt::WindowStates states = Qt::WindowNoState;
738 NSWindow *window = m_view.window;
739
740 if (window.miniaturized)
742
743 // Full screen and maximized are mutually exclusive, as macOS
744 // will report a full screen window as zoomed.
745 if (window.qt_fullScreen) {
747 } else if ((window.zoomed && !isTransitioningToFullScreen())
750 }
751
752 // Note: We do not report Qt::WindowActive, even if isActive()
753 // is true, as QtGui does not expect this window state to be set.
754
755 return states;
756}
757
759{
760 const NSWindow *window = m_view.window;
761
762 // The NSWindow needs to be resizable, otherwise the window will
763 // not be possible to zoom back to non-zoomed state.
764 const bool wasResizable = window.styleMask & NSWindowStyleMaskResizable;
765 window.styleMask |= NSWindowStyleMaskResizable;
766
767 const id sender = window;
768 [window zoom:sender];
769
770 if (!wasResizable)
771 window.styleMask &= ~NSWindowStyleMaskResizable;
772}
773
775{
777}
778
780{
781 const NSWindow *window = m_view.window;
782
783 // The window needs to have the correct collection behavior for the
784 // toggleFullScreen call to have an effect. The collection behavior
785 // will be reset in windowDidEnterFullScreen/windowDidLeaveFullScreen.
786 window.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
787
788 const id sender = window;
790}
791
792void QCocoaWindow::windowWillEnterFullScreen()
793{
794 if (!isContentView())
795 return;
796
798
799 // The NSWindow needs to be resizable, otherwise we'll end up with
800 // the normal window geometry, centered in the middle of the screen
801 // on a black background. The styleMask will be reset below.
802 m_view.window.styleMask |= NSWindowStyleMaskResizable;
803}
804
806{
807 NSWindow *window = m_view.window;
808 return window.styleMask & NSWindowStyleMaskFullScreen && !window.qt_fullScreen;
809}
810
811void QCocoaWindow::windowDidEnterFullScreen()
812{
813 if (!isContentView())
814 return;
815
816 Q_ASSERT_X(m_view.window.qt_fullScreen, "QCocoaWindow",
817 "FullScreen category processes window notifications first");
818
819 // Reset to original styleMask
821
823}
824
825void QCocoaWindow::windowWillExitFullScreen()
826{
827 if (!isContentView())
828 return;
829
830 // The NSWindow needs to be resizable, otherwise we'll end up with
831 // a weird zoom animation. The styleMask will be reset below.
832 m_view.window.styleMask |= NSWindowStyleMaskResizable;
833}
834
835void QCocoaWindow::windowDidExitFullScreen()
836{
837 if (!isContentView())
838 return;
839
840 Q_ASSERT_X(!m_view.window.qt_fullScreen, "QCocoaWindow",
841 "FullScreen category processes window notifications first");
842
843 // Reset to original styleMask
845
846 Qt::WindowState requestedState = window()->windowState();
847
848 // Deliver update of QWindow state
850
851 if (requestedState != windowState() && requestedState != Qt::WindowFullScreen) {
852 // We were only going out of full screen as an intermediate step before
853 // progressing into the final step, so re-sync the desired state.
854 applyWindowState(requestedState);
855 }
856}
857
858void QCocoaWindow::windowDidMiniaturize()
859{
860 if (!isContentView())
861 return;
862
864}
865
866void QCocoaWindow::windowDidDeminiaturize()
867{
868 if (!isContentView())
869 return;
870
871 Qt::WindowState requestedState = window()->windowState();
872
874
875 if (requestedState != windowState() && requestedState != Qt::WindowMinimized) {
876 // We were only going out of minimized as an intermediate step before
877 // progressing into the final step, so re-sync the desired state.
878 applyWindowState(requestedState);
879 }
880}
881
883{
884 Qt::WindowStates currentState = windowState();
885 if (!(flags & HandleUnconditionally) && currentState == m_lastReportedWindowState)
886 return;
887
888 qCDebug(lcQpaWindow) << "QCocoaWindow::handleWindowStateChanged" <<
889 m_lastReportedWindowState << "-->" << currentState;
890
891 QWindowSystemInterface::handleWindowStateChanged<QWindowSystemInterface::SynchronousDelivery>(
892 window(), currentState, m_lastReportedWindowState);
893 m_lastReportedWindowState = currentState;
894}
895
896// ------------------------------------------------------------
897
899{
900 if (!isContentView())
901 return;
902
904 m_view.window.title = title.toNSString();
905
906 if (title.isEmpty() && !window()->filePath().isEmpty()) {
907 // Clearing the title should restore the default filename
908 setWindowFilePath(window()->filePath());
909 }
910}
911
913{
914 if (!isContentView())
915 return;
916
918
919 if (window()->title().isNull())
920 [m_view.window setTitleWithRepresentedFilename:filePath.toNSString()];
921 else
922 m_view.window.representedFilename = filePath.toNSString();
923
924 // Changing the file path may affect icon visibility
926}
927
929{
930 if (!isContentView())
931 return;
932
933 NSButton *iconButton = [m_view.window standardWindowButton:NSWindowDocumentIconButton];
934 if (!iconButton) {
935 // Window icons are only supported on macOS in combination with a document filePath
936 return;
937 }
938
940
941 if (icon.isNull()) {
942 iconButton.image = [NSWorkspace.sharedWorkspace iconForFile:m_view.window.representedFilename];
943 } else {
944 // Fall back to a size that looks good on the highest resolution screen available
945 auto fallbackSize = iconButton.frame.size.height * qGuiApp->devicePixelRatio();
946 iconButton.image = [NSImage imageFromQIcon:icon withSize:fallbackSize];
947 }
948}
949
951{
953 m_alertRequest = [NSApp requestUserAttention:NSCriticalRequest];
954 } else if (m_alertRequest != NoAlertRequest && !enabled) {
955 [NSApp cancelUserAttentionRequest:m_alertRequest];
957 }
958}
959
961{
963}
964
966{
967 qCDebug(lcQpaWindow) << "QCocoaWindow::raise" << window();
968
969 // ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm)
970 if (isContentView()) {
971 if (m_view.window.visible) {
972 {
973 // Clean up auto-released temp objects from orderFront immediately.
974 // Failure to do so has been observed to cause leaks also beyond any outer
975 // autorelease pool (for example around a complete QWindow
976 // construct-show-raise-hide-delete cycle), counter to expected autoreleasepool
977 // behavior.
979 [m_view.window orderFront:m_view.window];
980 }
981 static bool raiseProcess = qt_mac_resolveOption(true, "QT_MAC_SET_RAISE_PROCESS");
982 if (raiseProcess)
983 [NSApp activateIgnoringOtherApps:YES];
984 }
985 } else {
986 [m_view.superview addSubview:m_view positioned:NSWindowAbove relativeTo:nil];
987 }
988}
989
991{
992 qCDebug(lcQpaWindow) << "QCocoaWindow::lower" << window();
993
994 if (isContentView()) {
995 if (m_view.window.visible)
996 [m_view.window orderBack:m_view.window];
997 } else {
998 [m_view.superview addSubview:m_view positioned:NSWindowBelow relativeTo:nil];
999 }
1000}
1001
1003{
1004 return !m_exposedRect.isEmpty();
1005}
1006
1008{
1009 // Child QWindows are not embedded
1010 if (window()->parent())
1011 return false;
1012
1013 // Top-level QWindows with non-Qt NSWindows are embedded
1014 if (m_view.window)
1015 return !([m_view.window isKindOfClass:[QNSWindow class]] ||
1016 [m_view.window isKindOfClass:[QNSPanel class]]);
1017
1018 // The window has no QWindow parent but also no NSWindow,
1019 // conservatively reuturn false.
1020 return false;
1021}
1022
1024{
1025 // OpenGL surfaces can be ordered either above(default) or below the NSWindow.
1026 // When ordering below the window must be tranclucent.
1027 static GLint openglSourfaceOrder = qt_mac_resolveOption(1, "QT_MAC_OPENGL_SURFACE_ORDER");
1028
1029 bool translucent = window()->format().alphaBufferSize() > 0
1030 || window()->opacity() < 1
1031 || !window()->mask().isEmpty()
1032 || (surface()->supportsOpenGL() && openglSourfaceOrder == -1);
1033 return !translucent;
1034}
1035
1037{
1039 if (!isContentView())
1040 return;
1041
1042 qCDebug(lcQpaWindow) << "QCocoaWindow::propagateSizeHints" << window()
1043 << "min:" << windowMinimumSize() << "max:" << windowMaximumSize()
1044 << "increment:" << windowSizeIncrement()
1045 << "base:" << windowBaseSize();
1046
1047 const NSWindow *window = m_view.window;
1048
1049 // Set the minimum content size.
1050 QSize minimumSize = windowMinimumSize();
1051 if (!minimumSize.isValid()) // minimumSize is (-1, -1) when not set. Make that (0, 0) for Cocoa.
1052 minimumSize = QSize(0, 0);
1053 window.contentMinSize = NSSizeFromCGSize(minimumSize.toCGSize());
1054
1055 // Set the maximum content size.
1056 window.contentMaxSize = NSSizeFromCGSize(windowMaximumSize().toCGSize());
1057
1058 // The window may end up with a fixed size; in this case the zoom button should be disabled.
1060
1061 // sizeIncrement is observed to take values of (-1, -1) and (0, 0) for windows that should be
1062 // resizable and that have no specific size increment set. Cocoa expects (1.0, 1.0) in this case.
1063 QSize sizeIncrement = windowSizeIncrement();
1064 if (sizeIncrement.isEmpty())
1065 sizeIncrement = QSize(1, 1);
1066 window.resizeIncrements = NSSizeFromCGSize(sizeIncrement.toCGSize());
1067
1068 QRect rect = geometry();
1069 QSize baseSize = windowBaseSize();
1070 if (!baseSize.isNull() && baseSize.isValid())
1071 [window setFrame:NSMakeRect(rect.x(), rect.y(), baseSize.width(), baseSize.height()) display:YES];
1072}
1073
1075{
1076 qCDebug(lcQpaWindow) << "QCocoaWindow::setOpacity" << level;
1077 if (!isContentView())
1078 return;
1079
1080 m_view.window.alphaValue = level;
1081}
1082
1084{
1085 qCDebug(lcQpaWindow) << "QCocoaWindow::setMask" << window() << region;
1086
1087 if (!region.isEmpty()) {
1088 QCFType<CGMutablePathRef> maskPath = CGPathCreateMutable();
1089 for (const QRect &r : region)
1090 CGPathAddRect(maskPath, nullptr, r.toCGRect());
1091 CAShapeLayer *maskLayer = [CAShapeLayer layer];
1092 maskLayer.path = maskPath;
1093 m_view.layer.mask = maskLayer;
1094 } else {
1095 m_view.layer.mask = nil;
1096 }
1097}
1098
1100{
1101 return false; // FIXME (QTBUG-106597)
1102}
1103
1105{
1106 return false; // FIXME (QTBUG-106597)
1107}
1108
1110{
1111 return WId(m_view);
1112}
1113
1115{
1116 qCDebug(lcQpaWindow) << "QCocoaWindow::setParent" << window() << (parentWindow ? parentWindow->window() : 0);
1117
1118 // Recreate in case we need to get rid of a NSWindow, or create one
1120
1122}
1123
1124NSView *QCocoaWindow::view() const
1125{
1126 return m_view;
1127}
1128
1130{
1131 return m_view.window;
1132}
1133
1135{
1136 // Release any previously created NSWindow.
1137 [m_nsWindow closeAndRelease];
1138 m_nsWindow = 0;
1139}
1140
1141// ----------------------- NSView notifications -----------------------
1142
1143void QCocoaWindow::viewDidChangeFrame()
1144{
1145 // Note: When the view is the content view, it would seem redundant
1146 // to deliver geometry changes both from windowDidResize and this
1147 // callback, but in some cases such as when macOS native tabbed
1148 // windows are enabled we may end up with the wrong geometry in
1149 // the initial windowDidResize callback when a new tab is created.
1151}
1152
1160void QCocoaWindow::viewDidChangeGlobalFrame()
1161{
1162 [m_view setNeedsDisplay:YES];
1163}
1164
1165// ----------------------- NSWindow notifications -----------------------
1166
1167// Note: The following notifications are delivered to every QCocoaWindow
1168// that is a child of the NSWindow that triggered the notification. Each
1169// callback should make sure to filter out notifications if they do not
1170// apply to that QCocoaWindow, e.g. if the window is not a content view.
1171
1172void QCocoaWindow::windowDidMove()
1173{
1174 if (!isContentView())
1175 return;
1176
1178
1179 // Moving a window might bring it out of maximized state
1181}
1182
1183void QCocoaWindow::windowDidResize()
1184{
1185 if (!isContentView())
1186 return;
1187
1189
1190 if (!m_view.inLiveResize)
1192}
1193
1194void QCocoaWindow::windowDidEndLiveResize()
1195{
1196 if (!isContentView())
1197 return;
1198
1200}
1201
1202void QCocoaWindow::windowDidBecomeKey()
1203{
1204 if (!isContentView())
1205 return;
1206
1207 if (isForeignWindow())
1208 return;
1209
1210 QNSView *firstResponderView = qt_objc_cast<QNSView *>(m_view.window.firstResponder);
1211 if (!firstResponderView)
1212 return;
1213
1214 const QCocoaWindow *focusCocoaWindow = firstResponderView.platformWindow;
1215 if (focusCocoaWindow->windowIsPopupType())
1216 return;
1217
1218 // See also [QNSView becomeFirstResponder]
1219 QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(
1220 focusCocoaWindow->window(), Qt::ActiveWindowFocusReason);
1221}
1222
1223void QCocoaWindow::windowDidResignKey()
1224{
1225 if (!isContentView())
1226 return;
1227
1228 if (isForeignWindow())
1229 return;
1230
1231 // Make sure popups are closed before we deliver activation changes, which are
1232 // otherwise ignored by QApplication.
1234
1235 // The current key window will be non-nil if another window became key. If that
1236 // window is a Qt window, we delay the window activation event until the didBecomeKey
1237 // notification is delivered to the active window, to ensure an atomic update.
1238 NSWindow *newKeyWindow = [NSApp keyWindow];
1239 if (newKeyWindow && newKeyWindow != m_view.window
1240 && [newKeyWindow conformsToProtocol:@protocol(QNSWindowProtocol)]) {
1241 return;
1242 }
1243
1244 // Lost key window, go ahead and set the active window to zero
1245 if (!windowIsPopupType()) {
1246 QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(
1248 }
1249}
1250
1251void QCocoaWindow::windowDidOrderOnScreen()
1252{
1253 // The current mouse window needs to get a leave event when a popup window opens.
1254 // For modal dialogs, QGuiApplicationPrivate::showModalWindow takes care of this.
1255 if (QWindowPrivate::get(window())->isPopup()) {
1256 QWindowSystemInterface::handleLeaveEvent<QWindowSystemInterface::SynchronousDelivery>
1258 }
1259
1260 [m_view setNeedsDisplay:YES];
1261}
1262
1263void QCocoaWindow::windowDidOrderOffScreen()
1264{
1266 // We are closing a window, so the window that is now under the mouse
1267 // might need to get an Enter event if it isn't already the mouse window.
1268 if (window()->type() & Qt::Window) {
1269 const QPointF screenPoint = QCocoaScreen::mapFromNative([NSEvent mouseLocation]);
1270 if (QWindow *windowUnderMouse = QGuiApplication::topLevelAt(screenPoint.toPoint())) {
1271 if (windowUnderMouse != QGuiApplicationPrivate::instance()->currentMouseWindow) {
1272 const auto windowPoint = windowUnderMouse->mapFromGlobal(screenPoint);
1273 // asynchronous delivery on purpose
1274 QWindowSystemInterface::handleEnterEvent<QWindowSystemInterface::AsynchronousDelivery>
1275 (windowUnderMouse, windowPoint, screenPoint);
1276 }
1277 }
1278 }
1279}
1280
1281void QCocoaWindow::windowDidChangeOcclusionState()
1282{
1283 bool visible = m_view.window.occlusionState & NSWindowOcclusionStateVisible;
1284 qCDebug(lcQpaWindow) << "QCocoaWindow::windowDidChangeOcclusionState" << window() << "is now" << (visible ? "visible" : "occluded");
1285 if (visible)
1286 [m_view setNeedsDisplay:YES];
1287 else
1289}
1290
1291void QCocoaWindow::windowDidChangeScreen()
1292{
1293 if (!window())
1294 return;
1295
1296 // Note: When a window is resized to 0x0 Cocoa will report the window's screen as nil
1297 NSScreen *nsScreen = m_view.window.screen;
1298
1299 qCDebug(lcQpaWindow) << window() << "did change" << nsScreen;
1300 QCocoaScreen::updateScreens();
1301
1302 auto *previousScreen = static_cast<QCocoaScreen*>(screen());
1303 auto *currentScreen = QCocoaScreen::get(nsScreen);
1304
1305 qCDebug(lcQpaWindow) << "Screen changed for" << window() << "from" << previousScreen << "to" << currentScreen;
1306
1307 // Note: The previous screen may be the same as the current screen, either because
1308 // a) the screen was just reconfigured, which still results in AppKit sending an
1309 // NSWindowDidChangeScreenNotification, b) because the previous screen was removed,
1310 // and we ended up calling QWindow::setScreen to move the window, which doesn't
1311 // actually move the window to the new screen, or c) because we've delivered the
1312 // screen change to the top level window, which will make all the child windows
1313 // of that window report the new screen when requested via QWindow::screen().
1314 // We still need to deliver the screen change in all these cases, as the
1315 // device-pixel ratio may have changed, and needs to be delivered to all
1316 // windows, both top level and child windows.
1317
1318 QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(
1319 window(), currentScreen ? currentScreen->screen() : nullptr);
1320
1321 if (currentScreen && hasPendingUpdateRequest()) {
1322 // Restart display-link on new screen. We need to do this unconditionally,
1323 // since we can't rely on the previousScreen reflecting whether or not the
1324 // window actually moved from one screen to another, or just stayed on the
1325 // same screen.
1326 currentScreen->requestUpdate();
1327 }
1328}
1329
1330// ----------------------- NSWindowDelegate callbacks -----------------------
1331
1333{
1334 qCDebug(lcQpaWindow) << "QCocoaWindow::windowShouldClose" << window();
1335
1336 // This callback should technically only determine if the window
1337 // should (be allowed to) close, but since our QPA API to determine
1338 // that also involves actually closing the window we do both at the
1339 // same time, instead of doing the latter in windowWillClose.
1340
1341 // If the window is closed, we will release and deallocate the NSWindow.
1342 // But frames higher up in the stack might still expect the window to
1343 // be alive, since the windowShouldClose: callback is technically only
1344 // supposed to answer YES or NO. To ensure the window is still alive
1345 // we put an autorelease in the closest pool (typically the runloop).
1346 [[m_view.window retain] autorelease];
1347
1348 return QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(window());
1349}
1350
1351// ----------------------------- QPA forwarding -----------------------------
1352
1354{
1355 // Prevent geometry change during initialization, as that will result
1356 // in a resize event, and Qt expects those to come after the show event.
1357 // FIXME: Remove once we've clarified the Qt behavior for this.
1358 if (!m_initialized)
1359 return;
1360
1361 // It can happen that the current NSWindow is nil (if we are changing styleMask
1362 // from/to borderless, and the content view is being re-parented), which results
1363 // in invalid coordinates.
1364 if (m_inSetStyleMask && !m_view.window)
1365 return;
1366
1367 QRect newGeometry;
1368 if (isContentView() && !isEmbedded()) {
1369 // Content views are positioned at (0, 0) in the window, so we resolve via the window
1370 CGRect contentRect = [m_view.window contentRectForFrameRect:m_view.window.frame];
1371
1372 // The result above is in native screen coordinates, so remap to the Qt coordinate system
1373 newGeometry = QCocoaScreen::mapFromNative(contentRect).toRect();
1374 } else {
1375 // QNSView has isFlipped set, so no need to remap the geometry
1376 newGeometry = QRectF::fromCGRect(m_view.frame).toRect();
1377 }
1378
1379 qCDebug(lcQpaWindow) << "QCocoaWindow::handleGeometryChange" << window()
1380 << "current" << geometry() << "new" << newGeometry;
1381
1383
1384 // Guard against processing window system events during QWindow::setGeometry
1385 // calls, which Qt and Qt applications do not expect.
1386 if (!m_inSetGeometry)
1388}
1389
1391{
1392 // Ideally we'd implement isExposed() in terms of these properties,
1393 // plus the occlusionState of the NSWindow, and let the expose event
1394 // pull the exposed state out when needed. However, when the window
1395 // is first shown we receive a drawRect call where the occlusionState
1396 // of the window is still hidden, but we still want to prepare the
1397 // window for display by issuing an expose event to Qt. To work around
1398 // this we don't use the occlusionState directly, but instead base
1399 // the exposed state on the region we get in, which in the case of
1400 // a window being obscured is an empty region, and in the case of
1401 // a drawRect call is a non-null region, even if occlusionState
1402 // is still hidden. This ensures the window is prepared for display.
1403 if (m_view.window.visible && m_view.window.screen
1404 && !geometry().size().isEmpty() && !region.isEmpty()
1405 && !m_view.hiddenOrHasHiddenAncestor) {
1406 m_exposedRect = region.boundingRect();
1407 } else {
1408 m_exposedRect = QRect();
1409 }
1410
1411 qCDebug(lcQpaDrawing) << "QCocoaWindow::handleExposeEvent" << window() << region << "isExposed" << isExposed();
1412 QWindowSystemInterface::handleExposeEvent<QWindowSystemInterface::SynchronousDelivery>(window(), region);
1413}
1414
1415// --------------------------------------------------------------------------
1416
1418{
1419 if (type == Qt::Widget)
1420 type = window()->type();
1421 if (type == Qt::Tool)
1422 return false; // Qt::Tool has the Popup bit set but isn't, at least on Mac.
1423
1424 return ((type & Qt::Popup) == Qt::Popup);
1425}
1426
1437{
1438 return m_view.window.contentView == m_view;
1439}
1440
1448{
1450
1451 if (isForeignWindow()) {
1452 // A foreign window is created as such, and can never move between being
1453 // foreign and not, so we don't need to get rid of any existing NSWindows,
1454 // nor create new ones, as a foreign window is a single simple NSView.
1455 qCDebug(lcQpaWindow) << "Skipping NSWindow management for foreign window" << this;
1456 return;
1457 }
1458
1459 QPlatformWindow *parentWindow = QPlatformWindow::parent();
1460
1461 const bool isEmbeddedView = isEmbedded();
1462 RecreationReasons recreateReason = RecreationNotNeeded;
1463
1464 QCocoaWindow *oldParentCocoaWindow = nullptr;
1465 if (QNSView *qnsView = qnsview_cast(m_view.superview))
1466 oldParentCocoaWindow = qnsView.platformWindow;
1467
1468 if (parentWindow != oldParentCocoaWindow)
1469 recreateReason |= ParentChanged;
1470
1471 if (!m_view.window)
1472 recreateReason |= MissingWindow;
1473
1474 // If the modality has changed the style mask will need updating
1475 if (m_windowModality != window()->modality())
1476 recreateReason |= WindowModalityChanged;
1477
1478 Qt::WindowType type = window()->type();
1479
1480 const bool shouldBeContentView = !parentWindow
1481 && !((type & Qt::SubWindow) == Qt::SubWindow)
1482 && !isEmbeddedView;
1483 if (isContentView() != shouldBeContentView)
1484 recreateReason |= ContentViewChanged;
1485
1486 const bool isPanel = isContentView() && [m_view.window isKindOfClass:[QNSPanel class]];
1487 const bool shouldBePanel = shouldBeContentView &&
1488 ((type & Qt::Popup) == Qt::Popup || (type & Qt::Dialog) == Qt::Dialog);
1489
1490 if (isPanel != shouldBePanel)
1491 recreateReason |= PanelChanged;
1492
1493 qCDebug(lcQpaWindow) << "QCocoaWindow::recreateWindowIfNeeded" << window() << recreateReason;
1494
1495 if (recreateReason == RecreationNotNeeded)
1496 return;
1497
1498 QCocoaWindow *parentCocoaWindow = static_cast<QCocoaWindow *>(parentWindow);
1499
1500 // Remove current window (if any)
1501 if ((isContentView() && !shouldBeContentView) || (recreateReason & PanelChanged)) {
1502 if (m_nsWindow) {
1503 qCDebug(lcQpaWindow) << "Getting rid of existing window" << m_nsWindow;
1504 [m_nsWindow closeAndRelease];
1505 if (isContentView() && !isEmbeddedView) {
1506 // We explicitly disassociate m_view from the window's contentView,
1507 // as AppKit does not automatically do this in response to removing
1508 // the view from the NSThemeFrame subview list, so we might end up
1509 // with a NSWindow contentView pointing to a deallocated NSView.
1510 m_view.window.contentView = nil;
1511 }
1512 m_nsWindow = nil;
1513 }
1514 }
1515
1516 if (shouldBeContentView && !m_nsWindow) {
1517 // Move view to new NSWindow if needed
1518 if (auto *newWindow = createNSWindow(shouldBePanel)) {
1519 qCDebug(lcQpaWindow) << "Ensuring that" << m_view << "is content view for" << newWindow;
1520 [m_view setPostsFrameChangedNotifications:NO];
1521 [newWindow setContentView:m_view];
1522 [m_view setPostsFrameChangedNotifications:YES];
1523
1524 m_nsWindow = newWindow;
1525 Q_ASSERT(m_view.window == m_nsWindow);
1526 }
1527 }
1528
1529 if (parentCocoaWindow) {
1530 // Child windows have no NSWindow, re-parent to superview instead
1531 [parentCocoaWindow->m_view addSubview:m_view];
1532 }
1533}
1534
1536{
1537 qCDebug(lcQpaDrawing) << "QCocoaWindow::requestUpdate" << window()
1538 << "using" << (updatesWithDisplayLink() ? "display-link" : "timer");
1539
1540 if (updatesWithDisplayLink()) {
1541 if (!static_cast<QCocoaScreen *>(screen())->requestUpdate()) {
1542 qCDebug(lcQpaDrawing) << "Falling back to timer-based update request";
1544 }
1545 } else {
1546 // Fall back to the un-throttled timer-based callback
1548 }
1549}
1550
1552{
1553 // Update via CVDisplayLink if Vsync is enabled
1554 return format().swapInterval() != 0;
1555}
1556
1558{
1559 qCDebug(lcQpaDrawing) << "Delivering update request to" << window();
1561}
1562
1564{
1566 [m_view.window makeFirstResponder:m_view];
1567 [m_view.window makeKeyWindow];
1568}
1569
1570/*
1571 Closes all popups, and removes observers and monitors.
1572*/
1574{
1576
1578}
1579
1581{
1583 [NSEvent removeMonitor:s_globalMouseMonitor];
1585 }
1587 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:s_applicationActivationObserver];
1589 }
1590}
1591
1593{
1594 // we open a popup window while we are not active. None of our existing event
1595 // handlers will get called if the user now clicks anywhere outside the application
1596 // or activates another window. Use a global event monitor to watch for mouse
1597 // presses, and close popups. We also want mouse tracking in the popup to work, so
1598 // also watch for MouseMoved.
1599 if (!s_globalMouseMonitor) {
1600 // we only get LeftMouseDown events when we also set LeftMouseUp.
1601 constexpr NSEventMask mouseButtonMask = NSEventTypeLeftMouseDown | NSEventTypeLeftMouseUp
1602 | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown
1603 | NSEventMaskMouseMoved;
1604 s_globalMouseMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:mouseButtonMask
1605 handler:^(NSEvent *e){
1608 return;
1609 }
1610 const auto eventType = cocoaEvent2QtMouseEvent(e);
1611 if (eventType == QEvent::MouseMove) {
1612 if (s_windowUnderMouse) {
1614 const auto button = cocoaButton2QtButton(e);
1615 const auto buttons = currentlyPressedMouseButtons();
1616 const auto globalPoint = QCocoaScreen::mapFromNative(NSEvent.mouseLocation);
1617 const auto localPoint = window->mapFromGlobal(globalPoint.toPoint());
1618 QWindowSystemInterface::handleMouseEvent(window, localPoint, globalPoint,
1619 buttons, button, eventType);
1620 }
1621 } else {
1623 }
1624 }];
1625 }
1626 // The activation observer also gets called when we become active because the user clicks
1627 // into the popup. This should not close the popup, so QCocoaApplicationDelegate's
1628 // applicationDidBecomeActive implementation removes this observer.
1630 s_applicationActivationObserver = [[[NSWorkspace sharedWorkspace] notificationCenter]
1631 addObserverForName:NSWorkspaceDidActivateApplicationNotification
1632 object:nil queue:nil
1633 usingBlock:^(NSNotification *){
1635 }];
1636 }
1637}
1638
1639QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
1640{
1642
1643 Qt::WindowType type = window()->type();
1644 Qt::WindowFlags flags = window()->flags();
1645
1646 QRect rect = geometry();
1647
1648 QScreen *targetScreen = nullptr;
1650 if (screen->geometry().contains(rect.topLeft())) {
1651 targetScreen = screen;
1652 break;
1653 }
1654 }
1655
1656 NSWindowStyleMask styleMask = windowStyleMask(flags);
1657
1658 if (!targetScreen) {
1659 qCWarning(lcQpaWindow) << "Window position" << rect << "outside any known screen, using primary screen";
1660 targetScreen = QGuiApplication::primaryScreen();
1661 // Unless the window is created as borderless AppKit won't find a position and
1662 // screen that's close to the requested invalid position, and will always place
1663 // the window on the primary screen.
1664 styleMask = NSWindowStyleMaskBorderless;
1665 }
1666
1667 rect.translate(-targetScreen->geometry().topLeft());
1668 auto *targetCocoaScreen = static_cast<QCocoaScreen *>(targetScreen->handle());
1669 NSRect contentRect = QCocoaScreen::mapToNative(rect, targetCocoaScreen);
1670
1671 if (targetScreen->primaryOrientation() == Qt::PortraitOrientation) {
1672 // The macOS window manager has a bug, where if a screen is rotated, it will not allow
1673 // a window to be created within the area of the screen that has a Y coordinate (I quadrant)
1674 // higher than the height of the screen in its non-rotated state (including a magic padding
1675 // of 24 points), unless the window is created with the NSWindowStyleMaskBorderless style mask.
1676 if (styleMask && (contentRect.origin.y + 24 > targetScreen->geometry().width())) {
1677 qCDebug(lcQpaWindow) << "Window positioned on portrait screen."
1678 << "Adjusting style mask during creation";
1679 styleMask = NSWindowStyleMaskBorderless;
1680 }
1681 }
1682
1683 // Create NSWindow
1684 Class windowClass = shouldBePanel ? [QNSPanel class] : [QNSWindow class];
1685 QCocoaNSWindow *nsWindow = [[windowClass alloc] initWithContentRect:contentRect
1686 // Mask will be updated in setWindowFlags if not the final mask
1687 styleMask:styleMask
1688 // Deferring window creation breaks OpenGL (the GL context is
1689 // set up before the window is shown and needs a proper window)
1690 backing:NSBackingStoreBuffered defer:NO
1691 screen:targetCocoaScreen->nativeScreen()
1692 platformWindow:this];
1693
1694 // The resulting screen can be different from the screen requested if
1695 // for example the application has been assigned to a specific display.
1696 auto resultingScreen = QCocoaScreen::get(nsWindow.screen);
1697
1698 // But may not always be resolved at this point, in which case we fall back
1699 // to the target screen. The real screen will be delivered as a screen change
1700 // when resolved as part of ordering the window on screen.
1701 if (!resultingScreen)
1702 resultingScreen = targetCocoaScreen;
1703
1704 if (resultingScreen->screen() != window()->screen()) {
1706 QWindowSystemInterface::SynchronousDelivery>(window(), resultingScreen->screen());
1707 }
1708
1709 static QSharedPointer<QNSWindowDelegate> sharedDelegate([[QNSWindowDelegate alloc] init],
1710 [](QNSWindowDelegate *delegate) { [delegate release]; });
1711 nsWindow.delegate = sharedDelegate.get();
1712
1713 // Prevent Cocoa from releasing the window on close. Qt
1714 // handles the close event asynchronously and we want to
1715 // make sure that NSWindow stays valid until the
1716 // QCocoaWindow is deleted by Qt.
1717 [nsWindow setReleasedWhenClosed:NO];
1718
1719 if (alwaysShowToolWindow()) {
1720 static dispatch_once_t onceToken;
1721 dispatch_once(&onceToken, ^{
1722 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
1723 [center addObserver:[QNSWindow class] selector:@selector(applicationActivationChanged:)
1724 name:NSApplicationWillResignActiveNotification object:nil];
1725 [center addObserver:[QNSWindow class] selector:@selector(applicationActivationChanged:)
1726 name:NSApplicationWillBecomeActiveNotification object:nil];
1727 });
1728 }
1729
1730 nsWindow.restorable = NO;
1731 nsWindow.level = windowLevel(flags);
1732 nsWindow.tabbingMode = NSWindowTabbingModeDisallowed;
1733
1734 if (shouldBePanel) {
1735 // Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set
1736 nsWindow.hidesOnDeactivate = ((type & Qt::Tool) == Qt::Tool) && !alwaysShowToolWindow();
1737
1738 // Make popup windows show on the same desktop as the parent full-screen window
1739 nsWindow.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary;
1740
1741 if ((type & Qt::Popup) == Qt::Popup) {
1742 nsWindow.hasShadow = YES;
1743 nsWindow.animationBehavior = NSWindowAnimationBehaviorUtilityWindow;
1746 }
1747 }
1748
1749 // Persist modality so we can detect changes later on
1751
1753
1754 if (QColorSpace colorSpace = format().colorSpace(); colorSpace.isValid()) {
1755 NSData *iccData = colorSpace.iccProfile().toNSData();
1756 nsWindow.colorSpace = [[[NSColorSpace alloc] initWithICCProfileData:iccData] autorelease];
1757 qCDebug(lcQpaDrawing) << "Set" << this << "color space to" << nsWindow.colorSpace;
1758 }
1759
1760 return nsWindow;
1761}
1762
1764{
1765 return qt_mac_resolveOption(false, window(), "_q_macAlwaysShowToolWindow", "");
1766}
1767
1769{
1770 if (!isContentView())
1771 return false;
1772
1773 m_view.window.documentEdited = modified;
1774 return true;
1775}
1776
1778{
1779 m_menubar = mb;
1780}
1781
1783{
1784 return m_menubar;
1785}
1786
1788{
1789 // Setting a cursor in a foreign view is not supported
1790 if (isForeignWindow())
1791 return;
1792
1793 qCInfo(lcQpaMouse) << "Setting" << this << "cursor to" << cursor;
1794
1796 if (cursor == view.cursor)
1797 return;
1798
1799 view.cursor = cursor;
1800
1801 // We're not using the the legacy cursor rects API to manage our
1802 // cursor, but calling this function also invalidates AppKit's
1803 // view of whether or not we need a cursorUpdate callback for
1804 // our tracking area.
1805 [m_view.window invalidateCursorRectsForView:m_view];
1806
1807 // We've informed AppKit that we need a cursorUpdate, but cursor
1808 // updates for tracking areas are deferred in some cases, such as
1809 // when the mouse is down, whereas we want a synchronous update.
1810 // To ensure an updated cursor we synthesize a cursor update event
1811 // now if the window is otherwise allowed to change the cursor.
1812 auto locationInWindow = m_view.window.mouseLocationOutsideOfEventStream;
1813 auto locationInSuperview = [m_view.superview convertPoint:locationInWindow fromView:nil];
1814 bool mouseIsOverView = [m_view hitTest:locationInSuperview] == m_view;
1815 auto utilityMask = NSWindowStyleMaskUtilityWindow | NSWindowStyleMaskTitled;
1816 bool isUtilityWindow = (m_view.window.styleMask & utilityMask) == utilityMask;
1817 if (mouseIsOverView && (m_view.window.keyWindow || isUtilityWindow)) {
1818 qCDebug(lcQpaMouse) << "Synthesizing cursor update";
1819 [m_view cursorUpdate:[NSEvent enterExitEventWithType:NSEventTypeCursorUpdate
1820 location:locationInWindow modifierFlags:0 timestamp:0
1821 windowNumber:m_view.window.windowNumber context:nil
1822 eventNumber:0 trackingNumber:0 userData:0]];
1823 }
1824}
1825
1827{
1828 m_registerTouchCount += enable ? 1 : -1;
1829 if (enable && m_registerTouchCount == 1)
1830 m_view.allowedTouchTypes |= NSTouchTypeMaskIndirect;
1831 else if (m_registerTouchCount == 0)
1832 m_view.allowedTouchTypes &= ~NSTouchTypeMaskIndirect;
1833}
1834
1835void QCocoaWindow::registerContentBorderArea(quintptr identifier, int upper, int lower)
1836{
1837 m_contentBorderAreas.insert(identifier, BorderRange(identifier, upper, lower));
1839}
1840
1842{
1845}
1846
1848{
1851}
1852
1854{
1855 if (!window && isContentView())
1856 window = m_view.window;
1857
1858 if (!window)
1859 return;
1860
1862 window.styleMask = window.styleMask & ~NSWindowStyleMaskTexturedBackground;
1863 [window.contentView.superview setNeedsDisplay:YES];
1864 window.titlebarAppearsTransparent = NO;
1865 return;
1866 }
1867
1868 // Find consecutive registered border areas, starting from the top.
1869 std::vector<BorderRange> ranges(m_contentBorderAreas.cbegin(), m_contentBorderAreas.cend());
1870 std::sort(ranges.begin(), ranges.end());
1871 int effectiveTopContentBorderThickness = 0;
1872 for (BorderRange range : ranges) {
1873 // Skip disiabled ranges (typically hidden tool bars)
1874 if (!m_enabledContentBorderAreas.value(range.identifier, false))
1875 continue;
1876
1877 // Is this sub-range adjacent to or overlapping the
1878 // existing total border area range? If so merge
1879 // it into the total range,
1880 if (range.upper <= (effectiveTopContentBorderThickness + 1))
1881 effectiveTopContentBorderThickness = qMax(effectiveTopContentBorderThickness, range.lower);
1882 else
1883 break;
1884 }
1885
1886 int effectiveBottomContentBorderThickness = 0;
1887
1888 [window setStyleMask:[window styleMask] | NSWindowStyleMaskTexturedBackground];
1889 window.titlebarAppearsTransparent = YES;
1890
1891 // Setting titlebarAppearsTransparent to YES means that the border thickness has to account
1892 // for the title bar height as well, otherwise sheets will not be presented at the correct
1893 // position, which should be (title bar height + top content border size).
1894 const NSRect frameRect = window.frame;
1895 const NSRect contentRect = [window contentRectForFrameRect:frameRect];
1896 const CGFloat titlebarHeight = frameRect.size.height - contentRect.size.height;
1897 effectiveTopContentBorderThickness += titlebarHeight;
1898
1899 [window setContentBorderThickness:effectiveTopContentBorderThickness forEdge:NSMaxYEdge];
1900 [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
1901
1902 [window setContentBorderThickness:effectiveBottomContentBorderThickness forEdge:NSMinYEdge];
1903 [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMinYEdge];
1904
1905 [[[window contentView] superview] setNeedsDisplay:YES];
1906}
1907
1909{
1911 return false;
1912
1913 // Determine if the given y position (relative to the content area) is inside the
1914 // unified toolbar area. Note that the value returned by contentBorderThicknessForEdge
1915 // includes the title bar height; subtract it.
1916 const int contentBorderThickness = [m_view.window contentBorderThicknessForEdge:NSMaxYEdge];
1917 const NSRect frameRect = m_view.window.frame;
1918 const NSRect contentRect = [m_view.window contentRectForFrameRect:frameRect];
1919 const CGFloat titlebarHeight = frameRect.size.height - contentRect.size.height;
1920 return 0 <= position && position < (contentBorderThickness - titlebarHeight);
1921}
1922
1924{
1925 // The documented way to observe the relationship between device-independent
1926 // and device pixels is to use one for the convertToBacking functions. Other
1927 // methods such as [NSWindow backingScaleFactor] might not give the correct
1928 // result, for example if setWantsBestResolutionOpenGLSurface is not set or
1929 // or ignored by the OpenGL driver.
1930 NSSize backingSize = [m_view convertSizeToBacking:NSMakeSize(1.0, 1.0)];
1931 return backingSize.height;
1932}
1933
1935{
1936 QWindow *targetWindow = window();
1937 for (QObject *child : targetWindow->children())
1938 if (QWindow *childWindow = qobject_cast<QWindow *>(child))
1939 if (QPlatformWindow *handle = childWindow->handle())
1940 if (handle->isExposed() && childWindow->geometry().contains(windowPoint))
1941 targetWindow = static_cast<QCocoaWindow*>(handle)->childWindowAt(windowPoint - childWindow->position());
1942
1943 return targetWindow;
1944}
1945
1947{
1948 // This function speaks up if there's any reason
1949 // to refuse key window or first responder state.
1950
1952 return true;
1953
1954 if (QWindowPrivate::get(window())->blockedByModalWindow)
1955 return true;
1956
1957 if (m_inSetVisible) {
1958 QVariant showWithoutActivating = window()->property("_q_showWithoutActivating");
1959 if (showWithoutActivating.isValid() && showWithoutActivating.toBool())
1960 return true;
1961 }
1962
1963 return false;
1964}
1965
1967{
1968 switch (event->type()) {
1972 break;
1973 default:
1974 break;
1975 }
1976
1978}
1979
1981{
1982 if (!m_view)
1983 return QPoint();
1984 const NSPoint origin = [m_view isFlipped] ? NSMakePoint(0, [m_view frame].size.height)
1985 : NSMakePoint(0, 0);
1986 const NSRect visibleRect = [m_view visibleRect];
1987
1988 return QPoint(visibleRect.origin.x, -visibleRect.origin.y + (origin.y - visibleRect.size.height));
1989}
1990
1992{
1993 if (!isContentView())
1994 return QMargins();
1995
1996 NSRect frameW = m_view.window.frame;
1997 NSRect frameC = [m_view.window contentRectForFrameRect:frameW];
1998
1999 return QMargins(frameW.origin.x - frameC.origin.x,
2000 (frameW.origin.y + frameW.size.height) - (frameC.origin.y + frameC.size.height),
2001 (frameW.origin.x + frameW.size.width) - (frameC.origin.x + frameC.size.width),
2002 frameC.origin.y - frameW.origin.y);
2003}
2004
2006{
2008}
2009
2010#ifndef QT_NO_DEBUG_STREAM
2012{
2013 QDebugStateSaver saver(debug);
2014 debug.nospace();
2015 debug << "QCocoaWindow(" << (const void *)window;
2016 if (window)
2017 debug << ", window=" << window->window();
2018 debug << ')';
2019 return debug;
2020}
2021#endif // !QT_NO_DEBUG_STREAM
2022
2024
2025#include "moc_qcocoawindow.cpp"
static QCocoaIntegration * instance()
static CGPoint mapToNative(const QPointF &pos, QCocoaScreen *screen=QCocoaScreen::primaryScreen())
static QCocoaScreen * get(NSScreen *nsScreen)
bool requestUpdate()
static QPointF mapFromNative(CGPoint pos, QCocoaScreen *screen=QCocoaScreen::primaryScreen())
void handleWindowStateChanged(HandleFlags flags=NoHandleFlags)
static void setupPopupMonitor()
void setContentBorderAreaEnabled(quintptr identifier, bool enable)
bool alwaysShowToolWindow() const
void setMenubar(QCocoaMenuBar *mb)
void toggleMaximized()
QWindow * childWindowAt(QPoint windowPoint)
void setAlertState(bool enabled) override
Reimplement this method to set whether the window demands attention (for example, by flashing the tas...
int m_registerTouchCount
Qt::WindowModality m_windowModality
void setWindowTitle(const QString &title) override
Reimplement to set the window title to title.
void setWindowCursor(NSCursor *cursor)
bool testContentBorderAreaPosition(int position) const
NSView * view() const
QRect normalGeometry() const override
the geometry of the window as it will appear when shown as a normal (not maximized or full screen) to...
bool updatesWithDisplayLink() const
bool m_inSetStyleMask
WId winId() const override
Reimplement in subclasses to return a handle to the native window.
bool isForeignWindow() const override
bool setMouseGrabEnabled(bool grab) override
QCocoaNSWindow * m_nsWindow
void propagateSizeHints() override
Reimplement to propagate the size hints of the QWindow.
void setOpacity(qreal level) override
Reimplement to be able to let Qt set the opacity level of a window.
QCocoaNSWindow * createNSWindow(bool shouldBePanel)
void requestActivateWindow() override
Reimplement to let Qt be able to request activation/focus for a window.
static id s_globalMouseMonitor
void setMask(const QRegion &region) override
Reimplement to be able to let Qt set the mask of a window.
QHash< quintptr, bool > m_enabledContentBorderAreas
QCocoaWindow(QWindow *tlw, WId nativeHandle=0)
void setFrameStrutEventsEnabled(bool enabled) override
Reimplement this method to set whether frame strut events should be sent to enabled.
void toggleFullScreen()
QCocoaMenuBar * menubar() const
void setWindowFilePath(const QString &filePath) override
Reimplement to set the window file path to filePath.
void setCocoaGeometry(const QRect &rect)
QRect geometry() const override
Returns the current geometry of a window.
NSInteger windowLevel(Qt::WindowFlags flags)
void setContentBorderEnabled(bool enable) override
bool isOpaque() const
void setParent(const QPlatformWindow *window) override
This function is called to enable native child window in QPA.
static void removePopupMonitor()
bool m_frameStrutEventsEnabled
bool setWindowModified(bool modified) override
Reimplement to be able to let Qt indicate that the window has been modified.
NSWindow * nativeWindow() const
void applyContentBorderThickness(NSWindow *window=nullptr)
void setWindowState(Qt::WindowStates state) override
Changes the state of the NSWindow, going in/out of minimize/zoomed/fullscreen.
bool windowShouldClose()
void registerTouch(bool enable)
void updateTitleBarButtons(Qt::WindowFlags flags)
QMargins frameMargins() const override
void setGeometry(const QRect &rect) override
This function is called by Qt whenever a window is moved or resized using the QWindow API.
void updateNormalGeometry()
bool isFixedSize() const
bool isAlertState() const override
Reimplement this method return whether the window is in an alert state.
bool isExposed() const override
Returns if this window is exposed in the windowing system.
void deliverUpdateRequest() override
Delivers an QEvent::UpdateRequest event to the window.
bool isEmbedded() const override
Returns true if the window is a child of a non-Qt window.
void setWindowFlags(Qt::WindowFlags flags) override
Requests setting the window flags of this surface to flags.
void lower() override
Reimplement to be able to let Qt lower windows to the bottom of the desktop.
bool shouldRefuseKeyWindowAndFirstResponder()
void requestUpdate() override
Requests an QEvent::UpdateRequest event.
static QPointer< QCocoaWindow > s_windowUnderMouse
static void closeAllPopups()
void setWindowIcon(const QIcon &icon) override
Reimplement to set the window icon to icon.
bool isContentView() const
Checks if the window is the content view of its immediate NSWindow.
NSInteger m_alertRequest
QRect m_normalGeometry
void recreateWindowIfNeeded()
Recreates (or removes) the NSWindow for this QWindow, if needed.
void handleGeometryChange()
bool m_drawContentBorderGradient
bool m_resizableTransientParent
NSUInteger windowStyleMask(Qt::WindowFlags flags)
QCocoaMenuBar * m_menubar
void setVisible(bool visible) override
Reimplemented in subclasses to show the surface if visible is true, and hide it if visible is false.
bool startSystemMove() override
Reimplement this method to start a system move operation if the system supports it and return true to...
static const int NoAlertRequest
QRect m_exposedRect
bool windowEvent(QEvent *event) override
Reimplement this method to be able to do any platform specific event handling.
void raise() override
Reimplement to be able to let Qt raise windows to the top of the desktop.
void windowWillZoom()
bool setKeyboardGrabEnabled(bool grab) override
bool windowIsPopupType(Qt::WindowType type=Qt::Widget) const
void registerContentBorderArea(quintptr identifier, int upper, int lower)
void setEmbeddedInForeignView()
void applyWindowState(Qt::WindowStates newState)
QPoint bottomLeftClippedByNSWindowOffset() const override
bool isTransitioningToFullScreen() const
QHash< quintptr, BorderRange > m_contentBorderAreas
Qt::WindowStates windowState() const
qreal devicePixelRatio() const override
Reimplement this function in subclass to return the device pixel ratio for the window.
void initialize() override
Called as part of QWindow::create(), after constructing the window.
Qt::WindowStates m_lastReportedWindowState
QSurfaceFormat format() const override
Returns the actual surface format of the window.
static id s_applicationActivationObserver
NSView * m_view
void handleExposeEvent(const QRegion &region)
The QColorSpace class provides a color space abstraction.
Definition qcolorspace.h:21
\inmodule QtCore
\inmodule QtCore
@ ExcludeSocketNotifiers
Definition qeventloop.h:28
@ ExcludeUserInputEvents
Definition qeventloop.h:27
\inmodule QtCore
Definition qcoreevent.h:45
@ WindowBlocked
Definition qcoreevent.h:141
@ WindowUnblocked
Definition qcoreevent.h:142
@ MouseMove
Definition qcoreevent.h:63
static QGuiApplicationPrivate * instance()
static QWindow * currentMouseWindow
static Qt::ApplicationState applicationState()
static QWindow * topLevelAt(const QPoint &pos)
Returns the top level window at the given position pos, if any.
static QWindowList allWindows()
Returns a list of all the windows in the application.
QScreen * primaryScreen
the primary (or default) screen of the application.
static QList< QScreen * > screens()
Returns a list of all the screens associated with the windowing system the application is connected t...
T value(const Key &key) const noexcept
Definition qhash.h:1044
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:20
bool isNull() const
Returns true if the icon is empty; otherwise returns false.
Definition qicon.cpp:973
constexpr qsizetype size() const noexcept
Definition qlist.h:74
\inmodule QtCore
Definition qmargins.h:23
constexpr int left() const noexcept
Returns the left margin.
Definition qmargins.h:110
constexpr int top() const noexcept
Returns the top margin.
Definition qmargins.h:113
\inmodule QtCore
Definition qmetaobject.h:18
\inmodule QtCore
Definition qmetatype.h:320
constexpr const QMetaObject * metaObject() const
Definition qmetatype.h:2633
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
\inmodule QtCore
Definition qobject.h:90
const QObjectList & children() const
Returns a list of child objects.
Definition qobject.h:171
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:311
QObject * sender() const
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; othe...
Definition qobject.cpp:2521
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4187
virtual QRect geometry() const =0
Reimplement in subclass to return the pixel geometry of the screen.
QSurface * surface() const
The QPlatformWindow class provides an abstraction for top-level windows.
QScopedPointer< QPlatformWindowPrivate > d_ptr
QWindow * window() const
Returns the window which belongs to the QPlatformWindow.
QPlatformScreen * screen() const override
Returns the platform screen handle corresponding to this platform window, or null if the window is no...
QSize windowMinimumSize() const
Returns the QWindow minimum size.
virtual bool windowEvent(QEvent *event)
Reimplement this method to be able to do any platform specific event handling.
QPlatformWindow * parent() const
Returns the parent platform window (or \nullptr if orphan).
virtual void setGeometry(const QRect &rect)
This function is called by Qt whenever a window is moved or resized using the QWindow API.
bool hasPendingUpdateRequest() const
Returns true if the window has a pending update request.
virtual QRect geometry() const
Returns the current geometry of a window.
virtual void deliverUpdateRequest()
Delivers an QEvent::UpdateRequest event to the window.
virtual void requestUpdate()
Requests an QEvent::UpdateRequest event.
QRect windowGeometry() const
Returns the QWindow geometry.
virtual bool close()
Reimplement to let the platform handle non-spontaneous window close.
QSize windowBaseSize() const
Returns the QWindow base size.
QSize windowMaximumSize() const
Returns the QWindow maximum size.
static QRect initialGeometry(const QWindow *w, const QRect &initialGeometry, int defaultWidth, int defaultHeight, const QScreen **resultingScreenReturn=nullptr)
Helper function to get initial geometry on windowing systems which do not do smart positioning and al...
QSize windowSizeIncrement() const
Returns the QWindow size increment.
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition qpoint.h:394
\inmodule QtCore\reentrant
Definition qpoint.h:23
\inmodule QtCore
Definition qpointer.h:18
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
Definition qrect.h:166
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:220
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:851
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
QRect boundingRect() const noexcept
Returns the bounding rectangle of this region.
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition qscreen.h:32
QRect geometry
the screen's geometry in pixels
Definition qscreen.h:45
Qt::ScreenOrientation primaryOrientation
the primary screen orientation
Definition qscreen.h:61
QPlatformScreen * handle() const
Get the platform screen handle.
Definition qscreen.cpp:83
\inmodule QtCore
T * get() const noexcept
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
constexpr bool isNull() const noexcept
Returns true if both the width and height is 0; otherwise returns false.
Definition qsize.h:120
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:123
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
Definition qsize.h:126
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
int alphaBufferSize() const
Get the size in bits of the alpha channel of the color buffer.
int swapInterval() const
Returns the swap interval.
bool supportsOpenGL() const
Returns true if the surface is OpenGL compatible and can be used in conjunction with QOpenGLContext; ...
Definition qsurface.cpp:70
bool isEmpty() const
\inmodule QtCore
Definition qvariant.h:64
bool isValid() const
Returns true if the storage type of this variant is not QMetaType::UnknownType; otherwise returns fal...
Definition qvariant.h:707
bool toBool() const
Returns the variant as a bool if the variant has userType() Bool.
static QWindowPrivate * get(QWindow *window)
Definition qwindow_p.h:94
static Qt::WindowState effectiveState(Qt::WindowStates)
Definition qwindow.cpp:1359
static bool flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags=QEventLoop::AllEvents)
Make Qt Gui process all events on the event queue immediately.
static void handleWindowScreenChanged(QWindow *window, QScreen *newScreen)
static bool handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons state, Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods=Qt::NoModifier, Qt::MouseEventSource source=Qt::MouseEventNotSynthesized)
static void handleGeometryChange(QWindow *window, const QRect &newRect)
\inmodule QtGui
Definition qwindow.h:63
Qt::WindowFlags flags
the window flags of the window
Definition qwindow.h:79
QSurfaceFormat format() const override
Returns the actual format of this window.
Definition qwindow.cpp:888
QSize size() const override
Returns the size of the window excluding any window frame.
Definition qwindow.h:210
QString title
the window's title in the windowing system
Definition qwindow.h:77
Qt::WindowModality modality
the modality of the window
Definition qwindow.h:78
qreal opacity
The opacity of the window in the windowing system.
Definition qwindow.h:96
QPushButton * button
[2]
QCursor cursor
double e
rect
[4]
else opt state
[0]
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
struct wl_display * display
Definition linuxdmabuf.h:41
QRegion toNativeLocalRegion(const QRegion &pointRegion, const QWindow *window)
Combined button and popup list for selecting options.
WindowState
Definition qnamespace.h:250
@ WindowFullScreen
Definition qnamespace.h:254
@ WindowNoState
Definition qnamespace.h:251
@ WindowMinimized
Definition qnamespace.h:252
@ WindowMaximized
Definition qnamespace.h:253
@ WindowModal
@ ApplicationModal
@ PortraitOrientation
Definition qnamespace.h:272
@ ApplicationActive
Definition qnamespace.h:265
@ DirectConnection
WindowType
Definition qnamespace.h:204
@ CustomizeWindowHint
Definition qnamespace.h:238
@ Widget
Definition qnamespace.h:205
@ FramelessWindowHint
Definition qnamespace.h:224
@ WindowDoesNotAcceptFocus
Definition qnamespace.h:235
@ ToolTip
Definition qnamespace.h:212
@ Popup
Definition qnamespace.h:210
@ WindowType_Mask
Definition qnamespace.h:219
@ Window
Definition qnamespace.h:206
@ WindowFullscreenButtonHint
Definition qnamespace.h:244
@ WindowStaysOnTopHint
Definition qnamespace.h:232
@ WindowMaximizeButtonHint
Definition qnamespace.h:228
@ WindowMinimizeButtonHint
Definition qnamespace.h:227
@ Dialog
Definition qnamespace.h:207
@ NoDropShadowWindowHint
Definition qnamespace.h:243
@ Sheet
Definition qnamespace.h:208
@ WindowTransparentForInput
Definition qnamespace.h:233
@ SubWindow
Definition qnamespace.h:215
@ Tool
Definition qnamespace.h:211
@ WindowTitleHint
Definition qnamespace.h:225
@ WindowCloseButtonHint
Definition qnamespace.h:240
@ ActiveWindowFocusReason
static void * context
float CGFloat
QNSView * qnsview_cast(NSView *view)
Returns the view cast to a QNSview if possible.
QEvent::Type cocoaEvent2QtMouseEvent(NSEvent *event)
Returns the QEvent::Type that corresponds to an NSEvent.type.
Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum)
Returns the Qt::Button that corresponds to an NSEvent.buttonNumber.
Qt::MouseButtons currentlyPressedMouseButtons()
Returns the Qt::MouseButtons that corresponds to an NSEvent.pressedMouseButtons.
unsigned long NSUInteger
#define Q_NOTIFICATION_PREFIX
long NSInteger
const NSNotificationName QCocoaWindowWillReleaseQNSViewNotification
static void qRegisterNotificationCallbacks()
QDebug operator<<(QDebug debug, const QCocoaWindow *window)
@ defaultWindowHeight
@ defaultWindowWidth
const NSNotificationName QCocoaWindowWillReleaseQNSViewNotification
Q_CONSTRUCTOR_FUNCTION(initializeStandardUserDefaults)
#define qApp
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
EGLOutputLayerEXT layer
#define qGuiApp
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCInfo(category,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLint location
typedef GLint(GL_APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC)(GLuint program
GLuint64 GLenum void * handle
GLenum GLuint GLint level
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint object
[3]
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLsizei range
GLenum type
GLbitfield flags
GLboolean enable
GLuint name
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
struct _cl_event * event
GLuint * states
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
#define qPrintable(string)
Definition qstring.h:1391
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
size_t quintptr
Definition qtypes.h:72
double qreal
Definition qtypes.h:92
Q_GUI_EXPORT QWindowPrivate * qt_window_private(QWindow *window)
Definition qwindow.cpp:2864
QWindow * qobject_cast< QWindow * >(QObject *o)
Definition qwindow.h:367
#define enabled
QWidget * win
Definition settings.cpp:6
QFileSelector selector
[1]
obj metaObject() -> className()
QObject::connect nullptr
QString title
[35]
sem release()
QQueue< int > queue
[0]
edit isVisible()
QLayoutItem * child
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QFrame frame
[0]
\inmodule QtCore