diff --git a/5.15.9/qtbase/src/plugins/platforms/cocoa/qnsview.mm b/5.15.9/qtbase/src/plugins/platforms/cocoa/qnsview.mm new file mode 100644 index 0000000..05fe39b --- /dev/null +++ b/5.15.9/qtbase/src/plugins/platforms/cocoa/qnsview.mm @@ -0,0 +1,391 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** $QT_END_LICENSE$ +** +** +** +** +** +** +** +** +** +** +** +** +** +** +** +** +** +** +** +****************************************************************************/ + +#include + +#include "qnsview.h" +#include "qcocoawindow.h" +#include "qcocoahelpers.h" +#include "qcocoascreen.h" +#include "qmultitouch_mac_p.h" +#include "qcocoadrag.h" +#include "qcocoainputcontext.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qcocoabackingstore.h" +#ifndef QT_NO_OPENGL +#include "qcocoaglcontext.h" +#endif +#include "qcocoaintegration.h" + +// Private interface +@interface QNSView () +- (BOOL)isTransparentForUserInput; +@property (assign) NSView* previousSuperview; +@property (assign) NSWindow* previousWindow; +@end + +@interface QNSView (Drawing) +- (void)initDrawing; +@end + +@interface QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) : NSObject +- (instancetype)initWithView:(QNSView *)theView; +- (void)mouseMoved:(NSEvent *)theEvent; +- (void)mouseEntered:(NSEvent *)theEvent; +- (void)mouseExited:(NSEvent *)theEvent; +- (void)cursorUpdate:(NSEvent *)theEvent; +@end + +QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper); + +@interface QNSView (Mouse) +- (void)initMouse; +- (NSPoint)screenMousePoint:(NSEvent *)theEvent; +- (void)mouseMovedImpl:(NSEvent *)theEvent; +- (void)mouseEnteredImpl:(NSEvent *)theEvent; +- (void)mouseExitedImpl:(NSEvent *)theEvent; +@end + +@interface QNSView (Touch) +@end + +@interface QNSView (Tablet) +- (bool)handleTabletEvent:(NSEvent *)theEvent; +@end + +@interface QNSView (Gestures) +@end + +@interface QNSView (Dragging) +-(void)registerDragTypes; +@end + +@interface QNSView (Keys) +@end + +@interface QNSView (ComplexText) +- (void)textInputContextKeyboardSelectionDidChangeNotification:(NSNotification *)textInputContextKeyboardSelectionDidChangeNotification; +@end + +@implementation QNSView { + QPointer m_platformWindow; + Qt::MouseButtons m_buttons; + Qt::MouseButtons m_acceptedMouseDowns; + Qt::MouseButtons m_frameStrutButtons; + QString m_composingText; + QPointer m_composingFocusObject; + bool m_sendKeyEvent; + bool m_dontOverrideCtrlLMB; + bool m_sendUpAsRightButton; + Qt::KeyboardModifiers m_currentWheelModifiers; + NSString *m_inputSource; + QNSViewMouseMoveHelper *m_mouseMoveHelper; + bool m_resendKeyEvent; + bool m_scrolling; + bool m_updatingDrag; + NSEvent *m_currentlyInterpretedKeyEvent; + QSet m_acceptedKeyDowns; +} + +- (instancetype)initWithCocoaWindow:(QCocoaWindow *)platformWindow +{ + if ((self = [super initWithFrame:NSZeroRect])) { + m_platformWindow = platformWindow; + m_sendKeyEvent = false; + m_inputSource = nil; + m_resendKeyEvent = false; + m_updatingDrag = false; + m_currentlyInterpretedKeyEvent = nil; + + self.focusRingType = NSFocusRingTypeNone; + + self.previousSuperview = nil; + self.previousWindow = nil; + + [self initDrawing]; + [self initMouse]; + [self registerDragTypes]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(textInputContextKeyboardSelectionDidChangeNotification:) + name:NSTextInputContextKeyboardSelectionDidChangeNotification + object:nil]; + } + return self; +} + +- (void)dealloc +{ + qCDebug(lcQpaWindow) << "Deallocating" << self; + + [m_inputSource release]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [m_mouseMoveHelper release]; + + [super dealloc]; +} + +- (NSString *)description +{ + NSMutableString *description = [NSMutableString stringWithString:[super description]]; + +#ifndef QT_NO_DEBUG_STREAM + QString platformWindowDescription; + QDebug debug(&platformWindowDescription); + debug.nospace() << "; " << m_platformWindow << ">"; + + NSRange lastCharacter = [description rangeOfComposedCharacterSequenceAtIndex:description.length - 1]; + [description replaceCharactersInRange:lastCharacter withString:platformWindowDescription.toNSString()]; +#endif + + return description; +} + +// ----------------------------- Re-parenting --------------------------------- + +- (void)removeFromSuperview +{ + QMacAutoReleasePool pool; + [super removeFromSuperview]; +} + +- (void)viewWillMoveToSuperview:(NSView *)newSuperview +{ + Q_ASSERT(!self.previousSuperview); + self.previousSuperview = self.superview; + + if (newSuperview == self.superview) + qCDebug(lcQpaWindow) << "Re-ordering" << self << "inside" << self.superview; + else + qCDebug(lcQpaWindow) << "Re-parenting" << self << "from" << self.superview << "to" << newSuperview; +} + +- (void)viewDidMoveToSuperview +{ + auto cleanup = qScopeGuard([&] { self.previousSuperview = nil; }); + + if (self.superview == self.previousSuperview) { + qCDebug(lcQpaWindow) << "Done re-ordering" << self << "new index:" + << [self.superview.subviews indexOfObject:self]; + return; + } + + qCDebug(lcQpaWindow) << "Done re-parenting" << self << "into" << self.superview; + + // Note: at this point the view's window property hasn't been updated to match the window + // of the new superview. We have to wait for viewDidMoveToWindow for that to be reflected. + + if (!m_platformWindow) + return; + + if (!m_platformWindow->isEmbedded()) + return; + + if ([self superview]) { + QWindowSystemInterface::handleGeometryChange(m_platformWindow->window(), m_platformWindow->geometry()); + [self setNeedsDisplay:YES]; + QWindowSystemInterface::flushWindowSystemEvents(); + } +} + +- (void)viewWillMoveToWindow:(NSWindow *)newWindow +{ + Q_ASSERT(!self.previousWindow); + self.previousWindow = self.window; + + // This callback is documented to be called also when a view is just moved between + // subviews in the same NSWindow, so we're not necessarily moving between NSWindows. + if (newWindow == self.window) + return; + + qCDebug(lcQpaWindow) << "Moving" << self << "from" << self.window << "to" << newWindow; + + // Note: at this point the superview has already been updated, so we know which view inside + // the new window the view will be a child of. +} + +- (void)viewDidMoveToWindow +{ + auto cleanup = qScopeGuard([&] { self.previousWindow = nil; }); + + // This callback is documented to be called also when a view is just moved between + // subviews in the same NSWindow, so we're not necessarily moving between NSWindows. + if (self.window == self.previousWindow) + return; + + qCDebug(lcQpaWindow) << "Done moving" << self << "to" << self.window; +} + +// ---------------------------------------------------------------------------- + +- (QWindow *)topLevelWindow +{ + if (!m_platformWindow) + return nullptr; + + QWindow *focusWindow = m_platformWindow->window(); + + // For widgets we need to do a bit of trickery as the window + // to activate is the window of the top-level widget. + if (qstrcmp(focusWindow->metaObject()->className(), "QWidgetWindow") == 0) { + while (focusWindow->parent()) { + focusWindow = focusWindow->parent(); + } + } + + return focusWindow; +} + +- (void)viewDidHide +{ + if (!m_platformWindow->isExposed()) + return; + + m_platformWindow->handleExposeEvent(QRegion()); + + // Note: setNeedsDisplay is automatically called for + // viewDidUnhide so no reason to override it here. +} + +- (BOOL)isTransparentForUserInput +{ + return m_platformWindow->window() && + m_platformWindow->window()->flags() & Qt::WindowTransparentForInput; +} + +- (BOOL)becomeFirstResponder +{ + if (!m_platformWindow) + return NO; + if ([self isTransparentForUserInput]) + return NO; + if (!m_platformWindow->windowIsPopupType()) + QWindowSystemInterface::handleWindowActivated([self topLevelWindow]); + return YES; +} + +- (BOOL)acceptsFirstResponder +{ + if (!m_platformWindow) + return NO; + if (m_platformWindow->shouldRefuseKeyWindowAndFirstResponder()) + return NO; + if ([self isTransparentForUserInput]) + return NO; + if ((m_platformWindow->window()->flags() & Qt::ToolTip) == Qt::ToolTip) + return NO; + return YES; +} + +- (NSView *)hitTest:(NSPoint)aPoint +{ + NSView *candidate = [super hitTest:aPoint]; + if (candidate == self) { + if ([self isTransparentForUserInput]) + return nil; + } + return candidate; +} + +- (void)convertFromScreen:(NSPoint)mouseLocation toWindowPoint:(QPointF *)qtWindowPoint andScreenPoint:(QPointF *)qtScreenPoint +{ + // Calculate the mouse position in the QWindow and Qt screen coordinate system, + // starting from coordinates in the NSWindow coordinate system. + // + // This involves translating according to the window location on screen, + // as well as inverting the y coordinate due to the origin change. + // + // Coordinate system overview, outer to innermost: + // + // Name Origin + // + // OS X screen bottom-left + // Qt screen top-left + // NSWindow bottom-left + // NSView/QWindow top-left + // + // NSView and QWindow are equal coordinate systems: the QWindow covers the + // entire NSView, and we've set the NSView's isFlipped property to true. + + NSWindow *window = [self window]; + NSPoint nsWindowPoint; + NSRect windowRect = [window convertRectFromScreen:NSMakeRect(mouseLocation.x, mouseLocation.y, 1, 1)]; + nsWindowPoint = windowRect.origin; // NSWindow coordinates + NSPoint nsViewPoint = [self convertPoint: nsWindowPoint fromView: nil]; // NSView/QWindow coordinates + *qtWindowPoint = QPointF(nsViewPoint.x, nsViewPoint.y); // NSView/QWindow coordinates + *qtScreenPoint = QCocoaScreen::mapFromNative(mouseLocation); +} + +@end + +#include "qnsview_drawing.mm" +#include "qnsview_mouse.mm" +#include "qnsview_touch.mm" +#include "qnsview_gestures.mm" +#include "qnsview_tablet.mm" +#include "qnsview_dragging.mm" +#include "qnsview_keys.mm" +#include "qnsview_complextext.mm" +#include "qnsview_menus.mm" +#ifndef QT_NO_ACCESSIBILITY +#include "qnsview_accessibility.mm" +#endif + +// ----------------------------------------------------- + +@implementation QNSView (QtExtras) + +- (QCocoaWindow*)platformWindow +{ + return m_platformWindow.data();; +} + +@end