summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/ios/qioswindow.mm
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@digia.com>2014-07-03 17:55:59 +0200
committerTor Arne Vestbø <tor.arne.vestbo@digia.com>2014-07-21 15:10:59 +0200
commitf86993cdeef298131bfcdc4e2078e7a353d42dc4 (patch)
tree4e87f53c4cfbaa1355037330d4facdbf6b56464f /src/plugins/platforms/ios/qioswindow.mm
parent7daf920e97ecbc22d794fe2fc52472a625228620 (diff)
iOS: Refactor qioswindow.mm into quiview.mm and quiview_accessibility.mm
Change-Id: Ib6297e37d67b2c0ea251ae054b8ff877af2673a5 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
Diffstat (limited to 'src/plugins/platforms/ios/qioswindow.mm')
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm380
1 files changed, 6 insertions, 374 deletions
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index 3ed2bbe1a1..76bd9bb2b5 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -39,391 +39,23 @@
**
****************************************************************************/
-#include "qiosglobal.h"
#include "qioswindow.h"
-#include "quiview.h"
+
+#include "qiosapplicationdelegate.h"
#include "qioscontext.h"
-#include "qiosinputcontext.h"
+#include "qiosglobal.h"
+#include "qiosintegration.h"
#include "qiosscreen.h"
-#include "qiosapplicationdelegate.h"
#include "qiosviewcontroller.h"
-#include "qiosintegration.h"
-#include <QtGui/private/qguiapplication_p.h>
+#include "quiview.h"
+
#include <QtGui/private/qwindow_p.h>
#include <qpa/qplatformintegration.h>
-#include "qiosplatformaccessibility.h"
-#import "quiaccessibilityelement.h"
-
#import <QuartzCore/CAEAGLLayer.h>
-#include <QtGui/QKeyEvent>
-#include <qpa/qwindowsysteminterface.h>
-
#include <QtDebug>
-// Include category as an alternative to using -ObjC (Apple QA1490)
-#include "quiview_textinput.mm"
-
-@implementation QUIView
-
-@synthesize autocapitalizationType;
-@synthesize autocorrectionType;
-@synthesize enablesReturnKeyAutomatically;
-@synthesize keyboardAppearance;
-@synthesize keyboardType;
-@synthesize returnKeyType;
-@synthesize secureTextEntry;
-
-+ (Class)layerClass
-{
- return [CAEAGLLayer class];
-}
-
--(id)initWithQIOSWindow:(QIOSWindow *)window
-{
- if (self = [self initWithFrame:toCGRect(window->geometry())])
- m_qioswindow = window;
-
- m_accessibleElements = [[NSMutableArray alloc] init];
- return self;
-}
-
-- (void)createAccessibleElement:(QAccessibleInterface *)iface
-{
- if (!iface || iface->state().invisible)
- return;
- QAccessible::Id accessibleId = QAccessible::uniqueId(iface);
- UIAccessibilityElement *elem = [[QMacAccessibilityElement alloc] initWithId: accessibleId withAccessibilityContainer: self];
- [m_accessibleElements addObject: elem];
-}
-
-- (void)createAccessibleContainer:(QAccessibleInterface *)iface
-{
- if (!iface)
- return;
-
- if (iface->childCount() == 0) {
- [self createAccessibleElement: iface];
- } else {
- for (int i = 0; i < iface->childCount(); ++i)
- [self createAccessibleContainer: iface->child(i)];
- }
-}
-
-- (void)initAccessibility
-{
- static bool init = false;
- if (!init)
- QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true);
- init = true;
-
- if ([m_accessibleElements count])
- return;
-
- QWindow *win = m_qioswindow->window();
- QAccessibleInterface *iface = win->accessibleRoot();
- if (iface)
- [self createAccessibleContainer: iface];
-}
-
-- (void)clearAccessibleCache
-{
- [m_accessibleElements removeAllObjects];
- UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, @"");
-}
-
-// this is a container, returning yes here means the functions below will never be called
-- (BOOL)isAccessibilityElement {
- return NO;
-}
-
-- (NSInteger)accessibilityElementCount {
- [self initAccessibility];
- return [m_accessibleElements count];
-}
-
-- (id)accessibilityElementAtIndex:(NSInteger)index {
- [self initAccessibility];
- return m_accessibleElements[index];
-}
-
-- (NSInteger)indexOfAccessibilityElement:(id)element {
- [self initAccessibility];
- return [m_accessibleElements indexOfObject:element];
-}
-
-- (id)initWithFrame:(CGRect)frame
-{
- if ((self = [super initWithFrame:frame])) {
- // Set up EAGL layer
- CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer);
- eaglLayer.opaque = TRUE;
- eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking,
- kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
-
- if (isQtApplication())
- self.hidden = YES;
-
- self.multipleTouchEnabled = YES;
- m_inSendEventToFocusObject = NO;
- }
-
- return self;
-}
-
-- (void)willMoveToWindow:(UIWindow *)newWindow
-{
- // UIKIt will normally set the scale factor of a view to match the corresponding
- // screen scale factor, but views backed by CAEAGLLayers need to do this manually.
- self.contentScaleFactor = newWindow && newWindow.screen ?
- newWindow.screen.scale : [[UIScreen mainScreen] scale];
-
- // FIXME: Allow the scale factor to be customized through QSurfaceFormat.
-}
-
-- (void)didAddSubview:(UIView *)subview
-{
- if ([subview isKindOfClass:[QUIView class]])
- self.clipsToBounds = YES;
-}
-
-- (void)willRemoveSubview:(UIView *)subview
-{
- for (UIView *view in self.subviews) {
- if (view != subview && [view isKindOfClass:[QUIView class]])
- return;
- }
-
- self.clipsToBounds = NO;
-}
-
-- (void)setNeedsDisplay
-{
- [super setNeedsDisplay];
-
- // We didn't implement drawRect: so we have to manually
- // mark the layer as needing display.
- [self.layer setNeedsDisplay];
-}
-
-- (void)layoutSubviews
-{
- // This method is the de facto way to know that view has been resized,
- // or otherwise needs invalidation of its buffers. Note though that we
- // do not get this callback when the view just changes its position, so
- // the position of our QWindow (and platform window) will only get updated
- // when the size is also changed.
-
- if (!CGAffineTransformIsIdentity(self.transform))
- qWarning() << m_qioswindow->window()
- << "is backed by a UIView that has a transform set. This is not supported.";
-
- // The original geometry requested by setGeometry() might be different
- // from what we end up with after applying window constraints.
- QRect requestedGeometry = m_qioswindow->geometry();
-
- QRect actualGeometry;
- if (m_qioswindow->window()->isTopLevel()) {
- UIWindow *uiWindow = self.window;
- UIView *rootView = uiWindow.rootViewController.view;
- CGRect rootViewPositionInRelationToRootViewController =
- [rootView convertRect:uiWindow.bounds fromView:uiWindow];
-
- actualGeometry = fromCGRect(CGRectOffset([self.superview convertRect:self.frame toView:rootView],
- -rootViewPositionInRelationToRootViewController.origin.x,
- -rootViewPositionInRelationToRootViewController.origin.y
- + rootView.bounds.origin.y)).toRect();
- } else {
- actualGeometry = fromCGRect(self.frame).toRect();
- }
-
- // Persist the actual/new geometry so that QWindow::geometry() can
- // be queried on the resize event.
- m_qioswindow->QPlatformWindow::setGeometry(actualGeometry);
-
- QRect previousGeometry = requestedGeometry != actualGeometry ?
- requestedGeometry : qt_window_private(m_qioswindow->window())->geometry;
-
- QWindowSystemInterface::handleGeometryChange(m_qioswindow->window(), actualGeometry, previousGeometry);
- QWindowSystemInterface::flushWindowSystemEvents();
-
- if (actualGeometry.size() != previousGeometry.size()) {
- // Trigger expose event on resize
- [self setNeedsDisplay];
-
- // A new size means we also need to resize the FBO's corresponding buffers,
- // but we defer that to when the application calls makeCurrent.
- }
-}
-
-- (void)displayLayer:(CALayer *)layer
-{
- Q_UNUSED(layer);
- Q_ASSERT(layer == self.layer);
-
- [self sendUpdatedExposeEvent];
-}
-
-- (void)sendUpdatedExposeEvent
-{
- QRegion region;
-
- if (m_qioswindow->isExposed()) {
- QSize bounds = fromCGRect(self.layer.bounds).toRect().size();
-
- Q_ASSERT(m_qioswindow->geometry().size() == bounds);
- Q_ASSERT(self.hidden == !m_qioswindow->window()->isVisible());
-
- region = QRect(QPoint(), bounds);
- }
-
- QWindowSystemInterface::handleExposeEvent(m_qioswindow->window(), region);
- QWindowSystemInterface::flushWindowSystemEvents();
-}
-
-- (void)updateTouchList:(NSSet *)touches withState:(Qt::TouchPointState)state
-{
- // We deliver touch events in global coordinates. But global in this respect
- // means the same coordinate system that we use for describing the geometry
- // of the top level QWindow we're inside. And that would be the coordinate
- // system of the superview of the UIView that backs that window:
- QPlatformWindow *topLevel = m_qioswindow;
- while (QPlatformWindow *topLevelParent = topLevel->parent())
- topLevel = topLevelParent;
- UIView *rootView = reinterpret_cast<UIView *>(topLevel->winId()).superview;
- CGSize rootViewSize = rootView.frame.size;
-
- foreach (UITouch *uiTouch, m_activeTouches.keys()) {
- QWindowSystemInterface::TouchPoint &touchPoint = m_activeTouches[uiTouch];
- if (![touches containsObject:uiTouch]) {
- touchPoint.state = Qt::TouchPointStationary;
- } else {
- touchPoint.state = state;
- touchPoint.pressure = (state == Qt::TouchPointReleased) ? 0.0 : 1.0;
- QPoint touchPos = fromCGPoint([uiTouch locationInView:rootView]).toPoint();
- touchPoint.area = QRectF(touchPos, QSize(0, 0));
- touchPoint.normalPosition = QPointF(touchPos.x() / rootViewSize.width, touchPos.y() / rootViewSize.height);
- }
- }
-}
-
-- (void) sendTouchEventWithTimestamp:(ulong)timeStamp
-{
- // Send touch event synchronously
- QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
- QWindowSystemInterface::handleTouchEvent(m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
- QWindowSystemInterface::flushWindowSystemEvents();
-}
-
-- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
-{
- // UIKit generates [Began -> Moved -> Ended] event sequences for
- // each touch point. Internally we keep a hashmap of active UITouch
- // points to QWindowSystemInterface::TouchPoints, and assigns each TouchPoint
- // an id for use by Qt.
- for (UITouch *touch in touches) {
- Q_ASSERT(!m_activeTouches.contains(touch));
- m_activeTouches[touch].id = m_nextTouchId++;
- }
-
- if (m_activeTouches.size() == 1) {
- QPlatformWindow *topLevel = m_qioswindow;
- while (QPlatformWindow *p = topLevel->parent())
- topLevel = p;
- if (topLevel->window() != QGuiApplication::focusWindow())
- topLevel->requestActivateWindow();
- }
-
- [self updateTouchList:touches withState:Qt::TouchPointPressed];
- [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)];
-}
-
-- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
-{
- [self updateTouchList:touches withState:Qt::TouchPointMoved];
- [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)];
-}
-
-- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
-{
- [self updateTouchList:touches withState:Qt::TouchPointReleased];
- [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)];
-
- // Remove ended touch points from the active set:
- for (UITouch *touch in touches)
- m_activeTouches.remove(touch);
- if (m_activeTouches.isEmpty())
- m_nextTouchId = 0;
-}
-
-- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
-{
- if (m_activeTouches.isEmpty())
- return;
-
- // When four-finger swiping, we get a touchesCancelled callback
- // which includes all four touch points. The swipe gesture is
- // then active until all four touches have been released, and
- // we start getting touchesBegan events again.
-
- // When five-finger pinching, we also get a touchesCancelled
- // callback with all five touch points, but the pinch gesture
- // ends when the second to last finger is released from the
- // screen. The last finger will not emit any more touch
- // events, _but_, will contribute to starting another pinch
- // gesture. That second pinch gesture will _not_ trigger a
- // touchesCancelled event when starting, but as each finger
- // is released, and we may get touchesMoved events for the
- // remaining fingers. [event allTouches] also contains one
- // less touch point than it should, so this behavior is
- // likely a bug in the iOS system gesture recognizer, but we
- // have to take it into account when maintaining the Qt state.
- // We do this by assuming that there are no cases where a
- // sub-set of the active touch events are intentionally cancelled.
-
- if (touches && (static_cast<NSInteger>([touches count]) != m_activeTouches.count()))
- qWarning("Subset of active touches cancelled by UIKit");
-
- m_activeTouches.clear();
- m_nextTouchId = 0;
-
- NSTimeInterval timestamp = event ? event.timestamp : [[NSProcessInfo processInfo] systemUptime];
-
- // Send cancel touch event synchronously
- QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
- QWindowSystemInterface::handleTouchCancelEvent(m_qioswindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice());
- QWindowSystemInterface::flushWindowSystemEvents();
-}
-
-@end
-
-@implementation UIView (QIOS)
-
-- (QWindow *)qwindow
-{
- if ([self isKindOfClass:[QUIView class]]) {
- if (QIOSWindow *w = static_cast<QUIView *>(self)->m_qioswindow)
- return w->window();
- }
- return nil;
-}
-
-- (UIViewController *)viewController
-{
- id responder = self;
- while ((responder = [responder nextResponder])) {
- if ([responder isKindOfClass:UIViewController.class])
- return responder;
- }
- return nil;
-}
-
-@end
-
-QT_BEGIN_NAMESPACE
-
QIOSWindow::QIOSWindow(QWindow *window)
: QPlatformWindow(window)
, m_view([[QUIView alloc] initWithQIOSWindow:this])