17#include <QtCore/qmath.h>
18#include <QtGui/qpointingdevice.h>
19#include <QtGui/private/qguiapplication_p.h>
20#include <QtGui/private/qwindow_p.h>
21#include <QtGui/private/qapplekeymapper_p.h>
22#include <qpa/qwindowsysteminterface_p.h>
30#if TARGET_OS_SIMULATOR == 1
43#if defined(Q_PROCESSOR_ARM)
44 #warning The timestamp work-around for x86_64 can (probably) be removed when building for ARM
46 return ulong(NSProcessInfo.processInfo.systemUptime * 1000);
73 [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillChangeStatusBarFrameNotification
74 object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *) {
75 for (QWindow *window : QGuiApplication::allWindows())
76 QWindowSystemInterface::handleSafeAreaMarginsChanged<QWindowSystemInterface::AsynchronousDelivery>(window);
86 return [CAEAGLLayer class];
88 return [
super layerClass];
93 if (self = [self initWithFrame:
window->geometry().toCGRect()]) {
98 action:@selector(handleScroll:)];
104 if (@available(ios 13.4, *)) {
110 [
self addGestureRecognizer:m_scrollGestureRecognizer];
112 if ([
self.layer isKindOfClass:CAMetalLayer.class]) {
114 if (
QColorSpace colorSpace =
window->format().colorSpace(); colorSpace.isValid()) {
117 CAMetalLayer *metalLayer =
static_cast<CAMetalLayer *
>(
self.layer);
118 metalLayer.colorspace = cgColorSpace;
119 qCDebug(lcQpaWindow) <<
"Set" <<
self <<
"color space to" << metalLayer.colorspace;
127- (instancetype)initWithFrame:(CGRect)frame
129 if ((self = [super initWithFrame:
frame])) {
131 if ([
self.layer isKindOfClass:[CAEAGLLayer class]]) {
133 CAEAGLLayer *eaglLayer =
static_cast<CAEAGLLayer *
>(
self.layer);
134 eaglLayer.opaque = TRUE;
135 eaglLayer.drawableProperties = @{
136 kEAGLDrawablePropertyRetainedBacking: @(YES),
137 kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
146 self.multipleTouchEnabled = YES;
152 for (
CGFloat diff = 0; diff < 0.1 || diff > 0.9; diff = fabs(hue - lastHue))
155 #define colorWithBrightness(br) \
156 [UIColor colorWithHue:hue saturation:0.5 brightness:br alpha:1.0].CGColor
159 self.layer.borderWidth = 1.0;
163 UIView *safeAreaOverlay = [[UIView alloc] initWithFrame:CGRectZero];
164 [safeAreaOverlay setBackgroundColor:[UIColor colorWithRed:0.3 green:0.7 blue:0.9 alpha:0.3]];
165 [
self addSubview:safeAreaOverlay];
167 safeAreaOverlay.translatesAutoresizingMaskIntoConstraints = NO;
168 [safeAreaOverlay.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor].active = YES;
169 [safeAreaOverlay.leftAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.leftAnchor].active = YES;
170 [safeAreaOverlay.rightAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.rightAnchor].active = YES;
171 [safeAreaOverlay.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor].active = YES;
180 [m_accessibleElements release];
181 [m_scrollGestureRecognizer release];
186- (NSString *)description
188 NSMutableString *description = [NSMutableString stringWithString:[
super description]];
190#ifndef QT_NO_DEBUG_STREAM
191 QString platformWindowDescription;
193 debug.nospace() <<
"; " <<
self.platformWindow <<
">";
194 NSRange lastCharacter = [description rangeOfComposedCharacterSequenceAtIndex:description.length - 1];
195 [description replaceCharactersInRange:lastCharacter withString:platformWindowDescription.toNSString()];
201- (
void)willMoveToWindow:(UIWindow *)newWindow
205 self.contentScaleFactor = newWindow && newWindow.screen ?
206 newWindow.screen.scale : [[UIScreen mainScreen] scale];
211- (
void)didAddSubview:(UIView *)subview
213 if ([subview isKindOfClass:[
QUIView class]])
214 self.clipsToBounds = YES;
217- (
void)willRemoveSubview:(UIView *)subview
224 self.clipsToBounds = NO;
227- (
void)setNeedsDisplay
229 [
super setNeedsDisplay];
233 [
self.layer setNeedsDisplay];
236- (
void)layoutSubviews
244 if (!CGAffineTransformIsIdentity(
self.transform))
245 qWarning() <<
self <<
"has a transform set. This is not supported.";
249 QRect currentGeometry = QRectF::fromCGRect(
self.frame).toRect();
250 qCDebug(lcQpaWindow) <<
self.platformWindow <<
"new geometry is" << currentGeometry;
253 if (currentGeometry.
size() != lastReportedGeometry.
size()) {
255 [
self setNeedsDisplay];
262- (
void)displayLayer:(CALayer *)layer
267 [
self sendUpdatedExposeEvent];
270- (
void)sendUpdatedExposeEvent
274 if (
self.platformWindow->isExposed()) {
275 QSize bounds = QRectF::fromCGRect(
self.layer.bounds).toRect().size();
283 qCDebug(lcQpaWindow) <<
self.platformWindow << region <<
"isExposed" <<
self.platformWindow->isExposed();
287- (
void)safeAreaInsetsDidChange
294- (BOOL)canBecomeFirstResponder
300- (BOOL)becomeFirstResponder
308 qImDebug() <<
"self:" <<
self <<
"first:" << [UIResponder currentFirstResponder];
310 if (![super becomeFirstResponder]) {
311 qImDebug() <<
self <<
"was not allowed to become first responder";
318 if (
qGuiApp->focusWindow() !=
self.platformWindow->window())
321 qImDebug() <<
self.platformWindow->window() <<
"already active, not sending window activation";
326- (BOOL)responderShouldTriggerWindowDeactivation:(UIResponder *)responder
330 if ([responder isKindOfClass:[
QUIView class]])
336 while ((responder = [responder nextResponder])) {
337 if ([responder isKindOfClass:[
QUIView class]])
345- (BOOL)resignFirstResponder
347 qImDebug() <<
"self:" <<
self <<
"first:" << [UIResponder currentFirstResponder];
349 if (![super resignFirstResponder])
355 if ([self responderShouldTriggerWindowDeactivation:newResponder])
361- (BOOL)isActiveWindow
367 if ([self isFirstResponder])
370 UIResponder *firstResponder = [UIResponder currentFirstResponder];
372 && [firstResponder nextResponder] ==
self)
380- (
void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
382 [
super traitCollectionDidChange: previousTraitCollection];
385 QPointingDevice::Capabilities touchCapabilities = touchDevice->
capabilities();
388 (
self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable));
390 touchDevice->setCapabilities(touchCapabilities);
393-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
397 return [
super pointInside:point withEvent:event];
400- (
void)handleTouches:(NSSet *)touches withEvent:(UIEvent *)event withState:(
QEventPoint::
State)state withTimestamp:(
ulong)timeStamp
405#if QT_CONFIG(tabletevent)
407 NSArray<UITouch *> *cTouches = [event coalescedTouchesForTouch:m_activePencilTouch];
409 for (UITouch *cTouch
in cTouches) {
410 QPointF localViewPosition = QPointF::fromCGPoint([cTouch preciseLocationInView:
self]);
412 QPointF globalScreenPosition =
self.platformWindow->mapToGlobal(localViewPositionI) +
413 (localViewPosition - localViewPositionI);
414 qreal pressure = cTouch.force / cTouch.maximumPossibleForce;
416 CGVector azimuth = [cTouch azimuthUnitVectorInView: self];
422 qCDebug(lcQpaTablet) <<
i <<
":" << timeStamp << localViewPosition << pressure <<
state <<
"azimuth" << azimuth.dx << azimuth.dy
423 <<
"angle" << azimuthAngle <<
"altitude" << cTouch.altitudeAngle
424 <<
"xTilt" <<
qBound(-60.0, altitudeAngle * azimuth.dx, 60.0) <<
"yTilt" <<
qBound(-60.0, altitudeAngle * azimuth.dy, 60.0);
429 pressure,
qBound(-60.0, altitudeAngle * azimuth.dx, 60.0),
qBound(-60.0, altitudeAngle * azimuth.dy, 60.0),
437 if (m_activeTouches.isEmpty())
439 for (
auto it = m_activeTouches.
begin();
it != m_activeTouches.
end(); ++
it) {
442 UITouch *uiTouch = nil;
443 for (UITouch *touch
in touches) {
444 if (touch.hash ==
hash) {
458 QPoint localViewPosition = QPointF::fromCGPoint([uiTouch locationInView:
self]).toPoint();
459 QPoint globalScreenPosition =
self.platformWindow->mapToGlobal(localViewPosition);
464 QSize screenSize =
self.platformWindow->screen()->geometry().
size();
466 globalScreenPosition.
y() / screenSize.
height());
468 if (supportsPressure) {
473 touchPoint.
pressure = uiTouch.force / uiTouch.maximumPossibleForce;
492 QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::AsynchronousDelivery>(
493 self.platformWindow->window(), timeStamp, iosIntegration->
touchDevice(), m_activeTouches.values());
498 QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::AsynchronousDelivery>(
499 self.platformWindow->window(), timeStamp, iosIntegration->
touchDevice(), m_activeTouches.values());
503- (
void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
509 for (UITouch *touch
in touches) {
510#if QT_CONFIG(tabletevent)
511 if (touch.type == UITouchTypeStylus) {
513 qWarning(
"ignoring additional Pencil while first is still active");
519 Q_ASSERT(!m_activeTouches.contains(touch.hash));
522#if QT_CONFIG(tabletevent)
527 if (
self.platformWindow->shouldAutoActivateWindow() && m_activeTouches.
size() == 1) {
535 [
self handleTouches:touches withEvent:event withState:QEventPoint::State::Pressed withTimestamp:getTimeStamp(event)];
538- (
void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
540 [
self handleTouches:touches withEvent:event withState:QEventPoint::State::Updated withTimestamp:getTimeStamp(event)];
543- (
void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
545 [
self handleTouches:touches withEvent:event withState:QEventPoint::State::Released withTimestamp:getTimeStamp(event)];
549 for (UITouch *touch
in touches) {
550#if QT_CONFIG(tabletevent)
551 if (touch.type == UITouchTypeStylus) {
556 m_activeTouches.remove(touch.hash);
561 m_activeTouches.clear();
568- (
void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
595 qWarning(
"Subset of active touches cancelled by UIKit");
597 m_activeTouches.clear();
601 ulong timestamp =
event ? getTimeStamp(
event) : ([[NSProcessInfo processInfo] systemUptime] * 1000);
608 QWindowSystemInterface::handleTouchCancelEvent<QWindowSystemInterface::AsynchronousDelivery>(
609 self.platformWindow->window(), timestamp, iosIntegration->
touchDevice());
612- (int)mapPressTypeToKey:(UIPress*)press withModifiers:(
Qt::KeyboardModifiers)qtModifiers text:(
QString &)text
614 switch (press.type) {
623 if (@available(ios 13.4, *)) {
624 NSString *charactersIgnoringModifiers = press.key.charactersIgnoringModifiers;
629 charactersIgnoringModifiers,
text);
634- (bool)isControlKey:(
Qt::
Key)key
649- (bool)handlePresses:(NSSet<UIPress *> *)presses eventType:(
QEvent::
Type)type
655 if (!
qApp->focusWindow())
658 bool eventHandled =
false;
661 for (UIPress* press
in presses) {
663 if (@available(ios 13.4, *))
666 int key = [
self mapPressTypeToKey:press withModifiers:qtModifiers text:text];
669 if (imEnabled && ![self isControlKey:
Qt::
Key(
key)])
674 eventHandled = eventHandled || keyHandled;
680- (
void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
682 if (![self handlePresses:presses eventType:
QEvent::KeyPress])
683 [super pressesBegan:presses withEvent:
event];
686- (
void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
688 if (![self handlePresses:presses eventType:
QEvent::KeyPress])
689 [super pressesChanged:presses withEvent:
event];
690 [
super pressesChanged:presses withEvent:event];
693- (
void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
695 if (![self handlePresses:presses eventType:
QEvent::KeyRelease])
696 [super pressesEnded:presses withEvent:
event];
697 [
super pressesEnded:presses withEvent:event];
700- (BOOL)canPerformAction:(
SEL)action withSender:(
id)sender
704 return [
QIOSMenu::menuActionTarget() targetForAction:action withSender:sender] != 0;
712- (
id)forwardingTargetForSelector:(
SEL)selector
722- (
void)addInteraction:(
id<UIInteraction>)interaction
724 if ([NSStringFromClass(interaction.class) isEqualToString:
@"UITextInteraction"])
727 [
super addInteraction:interaction];
730- (UIEditingInteractionConfiguration)editingInteractionConfiguration
739 UIEditingInteractionConfigurationDefault : UIEditingInteractionConfigurationNone;
742#if QT_CONFIG(wheelevent)
743- (
void)handleScroll:(UIPanGestureRecognizer *)recognizer
745 if (!
self.platformWindow->window())
748 if (!
self.canBecomeFirstResponder)
751 CGPoint translation = [recognizer translationInView:self];
761 const int pixelsToDegrees = 2;
762 angleDelta.
setX(deltaX * pixelsToDegrees);
763 angleDelta.
setY(deltaY * pixelsToDegrees);
766 pixelDelta.
setX(deltaX);
767 pixelDelta.
setY(deltaY);
769 NSTimeInterval time_stamp = [[NSProcessInfo processInfo] systemUptime];
770 ulong qt_timestamp = time_stamp * 1000;
773 if (@available(ios 13.4, *))
776 if (recognizer.state == UIGestureRecognizerStateBegan)
782 if (recognizer.state != UIGestureRecognizerStateEnded) {
790 QPoint qt_global =
self.platformWindow->mapToGlobal(qt_local);
792 qCInfo(lcQpaInputEvents).nospace() <<
"wheel event" <<
" at " << qt_local
793 <<
" pixelDelta=" << pixelDelta <<
" angleDelta=" << angleDelta;
801@implementation UIView (QtHelpers)
805 if ([self isKindOfClass:[
QUIView class]]) {
815 while ((responder = [responder nextResponder])) {
816 if ([responder isKindOfClass:UIViewController.class])
824 UIViewController *vc =
self.viewController;
833 return self.safeAreaInsets;
839@implementation QUIMetalView
843 return [CAMetalLayer class];
849#if QT_CONFIG(accessibility)
QIOSViewController * qtViewController()
UIViewController * viewController()
UIEdgeInsets qt_safeAreaInsets
static UIResponder * currentCandidate()
static Qt::Key fromNSString(Qt::KeyboardModifiers qtMods, NSString *characters, NSString *charactersIgnoringModifiers, QString &text)
static Qt::Key fromUIKitKey(NSString *keyCode)
static Qt::KeyboardModifiers fromUIKitModifiers(ulong uikitModifiers)
The QColorSpace class provides a color space abstraction.
The QEventPoint class provides information about a point in a QPointerEvent.
static QPlatformIntegration * platformIntegration()
static QWindow * focusWindow()
Returns the QWindow that receives events tied to focus, such as key events.
static QIOSInputContext * instance()
bool inputMethodAccepted() const
static QIOSIntegration * instance()
QPointingDevice * touchDevice()
static QOperatingSystemVersion current()
[0]
\inmodule QtCore\reentrant
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
\inmodule QtCore\reentrant
constexpr int x() const noexcept
Returns the x coordinate of this point.
constexpr void setY(int y) noexcept
Sets the y coordinate of this point to the given y coordinate.
constexpr int y() const noexcept
Returns the y coordinate of this point.
constexpr void setX(int x) noexcept
Sets the x coordinate of this point to the given x coordinate.
The QPointingDevice class describes a device from which mouse, touch or tablet events originate.
\inmodule QtCore\reentrant
\inmodule QtCore\reentrant
constexpr QSize size() const noexcept
Returns the size of the rectangle.
The QRegion class specifies a clip region for a painter.
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
\macro QT_RESTRICTED_CAST_FROM_ASCII
qsizetype size() const
Returns the number of characters in this string.
The QWindowSystemInterface provides an event queue for the QPA platform.
static void handleSafeAreaMarginsChanged(QWindow *window)
static bool handleTabletEvent(QWindow *window, ulong timestamp, const QPointingDevice *device, const QPointF &local, const QPointF &global, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, int z, Qt::KeyboardModifiers modifiers=Qt::NoModifier)
static void handleGeometryChange(QWindow *window, const QRect &newRect)
static bool handleKeyEvent(QWindow *window, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString &text=QString(), bool autorep=false, ushort count=1)
static bool handleExposeEvent(QWindow *window, const QRegion ®ion)
static void handleWindowActivated(QWindow *window, Qt::FocusReason r=Qt::OtherFocusReason)
static bool handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods=Qt::NoModifier, Qt::ScrollPhase phase=Qt::NoScrollPhase, Qt::MouseEventSource source=Qt::MouseEventNotSynthesized)
QHash< int, QWidget * > hash
[35multi]
QSet< QString >::iterator it
@ Key_MediaTogglePlayPause
@ WindowDoesNotAcceptFocus
@ WindowTransparentForInput
@ ActiveWindowFocusReason
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 return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
#define Q_LOGGING_CATEGORY(name,...)
#define qCInfo(category,...)
#define qCDebug(category,...)
constexpr float qRadiansToDegrees(float radians)
constexpr const T & qBound(const T &min, const T &val, const T &max)
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLenum GLenum GLsizei count
GLenum GLenum GLenum input
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
CGPoint m_lastScrollDelta
UITouch * m_activePencilTouch
UIPanGestureRecognizer * m_scrollGestureRecognizer
NSMutableArray< UIAccessibilityElement * > * m_accessibleElements
#define colorWithBrightness(br)
CGPoint m_lastScrollCursorPos
Q_GUI_EXPORT QWindowPrivate * qt_window_private(QWindow *window)
QT_END_NAMESPACE typedef QT_PREPEND_NAMESPACE(quintptr) WId
QFileSelector selector
[1]