Files
gio/app/os_ios.m
T
Inkeliz 2a32ece084 app: [iOS] replace ViewEvent.View with add ViewController field
For mixing native UI with Gio UI, the UIViewController is sometimes
needed, not just the UIView. This change replace the View field of
ViewEvent with ViewController.

Signed-off-by: Inkeliz <inkeliz@inkeliz.com>
2021-12-10 06:16:26 +01:00

275 lines
7.6 KiB
Objective-C

// SPDX-License-Identifier: Unlicense OR MIT
// +build darwin,ios
@import UIKit;
#include <stdint.h>
#include "_cgo_export.h"
#include "framework_ios.h"
__attribute__ ((visibility ("hidden"))) Class gio_layerClass(void);
@interface GioView: UIView <UIKeyInput>
@end
@implementation GioViewController
CGFloat _keyboardHeight;
- (void)loadView {
gio_runMain();
CGRect zeroFrame = CGRectMake(0, 0, 0, 0);
self.view = [[UIView alloc] initWithFrame:zeroFrame];
self.view.layoutMargins = UIEdgeInsetsMake(0, 0, 0, 0);
UIView *drawView = [[GioView alloc] initWithFrame:zeroFrame];
[self.view addSubview: drawView];
#ifndef TARGET_OS_TV
drawView.multipleTouchEnabled = YES;
#endif
drawView.preservesSuperviewLayoutMargins = YES;
drawView.layoutMargins = UIEdgeInsetsMake(0, 0, 0, 0);
onCreate((__bridge CFTypeRef)drawView, (__bridge CFTypeRef)self);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillChange:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillChange:)
name:UIKeyboardWillChangeFrameNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(applicationDidEnterBackground:)
name: UIApplicationDidEnterBackgroundNotification
object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(applicationWillEnterForeground:)
name: UIApplicationWillEnterForegroundNotification
object: nil];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
UIView *drawView = self.view.subviews[0];
if (drawView != nil) {
gio_onDraw((__bridge CFTypeRef)drawView);
}
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIView *drawView = self.view.subviews[0];
if (drawView != nil) {
onStop((__bridge CFTypeRef)drawView);
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
CFTypeRef viewRef = (__bridge CFTypeRef)self.view.subviews[0];
onDestroy(viewRef);
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UIView *view = self.view.subviews[0];
CGRect frame = self.view.bounds;
// Adjust view bounds to make room for the keyboard.
frame.size.height -= _keyboardHeight;
view.frame = frame;
gio_onDraw((__bridge CFTypeRef)view);
}
- (void)didReceiveMemoryWarning {
onLowMemory();
[super didReceiveMemoryWarning];
}
- (void)keyboardWillChange:(NSNotification *)note {
NSDictionary *userInfo = note.userInfo;
CGRect f = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
_keyboardHeight = f.size.height;
[self.view setNeedsLayout];
}
- (void)keyboardWillHide:(NSNotification *)note {
_keyboardHeight = 0.0;
[self.view setNeedsLayout];
}
@end
static void handleTouches(int last, UIView *view, NSSet<UITouch *> *touches, UIEvent *event) {
CGFloat scale = view.contentScaleFactor;
NSUInteger i = 0;
NSUInteger n = [touches count];
CFTypeRef viewRef = (__bridge CFTypeRef)view;
for (UITouch *touch in touches) {
CFTypeRef touchRef = (__bridge CFTypeRef)touch;
i++;
NSArray<UITouch *> *coalescedTouches = [event coalescedTouchesForTouch:touch];
NSUInteger j = 0;
NSUInteger m = [coalescedTouches count];
for (UITouch *coalescedTouch in [event coalescedTouchesForTouch:touch]) {
CGPoint loc = [coalescedTouch locationInView:view];
j++;
int lastTouch = last && i == n && j == m;
onTouch(lastTouch, viewRef, touchRef, touch.phase, loc.x*scale, loc.y*scale, [coalescedTouch timestamp]);
}
}
}
@implementation GioView
NSArray<UIKeyCommand *> *_keyCommands;
+ (void)onFrameCallback:(CADisplayLink *)link {
gio_onFrameCallback((__bridge CFTypeRef)link);
}
+ (Class)layerClass {
return gio_layerClass();
}
- (void)willMoveToWindow:(UIWindow *)newWindow {
if (self.window != nil) {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIWindowDidBecomeKeyNotification
object:self.window];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIWindowDidResignKeyNotification
object:self.window];
}
self.contentScaleFactor = newWindow.screen.nativeScale;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onWindowDidBecomeKey:)
name:UIWindowDidBecomeKeyNotification
object:newWindow];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onWindowDidResignKey:)
name:UIWindowDidResignKeyNotification
object:newWindow];
}
- (void)onWindowDidBecomeKey:(NSNotification *)note {
if (self.isFirstResponder) {
onFocus((__bridge CFTypeRef)self, YES);
}
}
- (void)onWindowDidResignKey:(NSNotification *)note {
if (self.isFirstResponder) {
onFocus((__bridge CFTypeRef)self, NO);
}
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
handleTouches(0, self, touches, event);
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
handleTouches(0, self, touches, event);
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
handleTouches(1, self, touches, event);
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
handleTouches(1, self, touches, event);
}
- (void)insertText:(NSString *)text {
onText((__bridge CFTypeRef)self, (char *)text.UTF8String);
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (BOOL)hasText {
return YES;
}
- (void)deleteBackward {
onDeleteBackward((__bridge CFTypeRef)self);
}
- (void)onUpArrow {
onUpArrow((__bridge CFTypeRef)self);
}
- (void)onDownArrow {
onDownArrow((__bridge CFTypeRef)self);
}
- (void)onLeftArrow {
onLeftArrow((__bridge CFTypeRef)self);
}
- (void)onRightArrow {
onRightArrow((__bridge CFTypeRef)self);
}
- (NSArray<UIKeyCommand *> *)keyCommands {
if (_keyCommands == nil) {
_keyCommands = @[
[UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow
modifierFlags:0
action:@selector(onUpArrow)],
[UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow
modifierFlags:0
action:@selector(onDownArrow)],
[UIKeyCommand keyCommandWithInput:UIKeyInputLeftArrow
modifierFlags:0
action:@selector(onLeftArrow)],
[UIKeyCommand keyCommandWithInput:UIKeyInputRightArrow
modifierFlags:0
action:@selector(onRightArrow)]
];
}
return _keyCommands;
}
@end
CFTypeRef gio_createDisplayLink(void) {
CADisplayLink *dl = [CADisplayLink displayLinkWithTarget:[GioView class] selector:@selector(onFrameCallback:)];
dl.paused = YES;
NSRunLoop *runLoop = [NSRunLoop mainRunLoop];
[dl addToRunLoop:runLoop forMode:[runLoop currentMode]];
return (__bridge_retained CFTypeRef)dl;
}
int gio_startDisplayLink(CFTypeRef dlref) {
CADisplayLink *dl = (__bridge CADisplayLink *)dlref;
dl.paused = NO;
return 0;
}
int gio_stopDisplayLink(CFTypeRef dlref) {
CADisplayLink *dl = (__bridge CADisplayLink *)dlref;
dl.paused = YES;
return 0;
}
void gio_releaseDisplayLink(CFTypeRef dlref) {
CADisplayLink *dl = (__bridge CADisplayLink *)dlref;
[dl invalidate];
CFRelease(dlref);
}
void gio_setDisplayLinkDisplay(CFTypeRef dl, uint64_t did) {
// Nothing to do on iOS.
}
void gio_hideCursor() {
// Not supported.
}
void gio_showCursor() {
// Not supported.
}
void gio_setCursor(NSUInteger curID) {
// Not supported.
}