Skip to content

Commit

Permalink
Merge pull request ish-app#545 from tbodt/multiwindow
Browse files Browse the repository at this point in the history
  • Loading branch information
tbodt committed Nov 4, 2019
2 parents c2baeef + 51102d7 commit 64576c8
Show file tree
Hide file tree
Showing 18 changed files with 450 additions and 165 deletions.
2 changes: 2 additions & 0 deletions app/AppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
@property (strong, nonatomic) UIWindow *window;
- (void)exitApp;

+ (int)bootError;

@end

extern NSString *const ProcessExitedNotification;
92 changes: 23 additions & 69 deletions app/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,12 @@
#import "UserPreferences.h"
#include "kernel/init.h"
#include "kernel/calls.h"
#include "fs/path.h"
#include "fs/dyndev.h"
#include "fs/devices.h"
#include "fs/path.h"

@interface AppDelegate ()

@property int sessionPid;

@property BOOL exiting;

@end
Expand Down Expand Up @@ -52,7 +50,7 @@ static void ios_handle_die(const char *msg) {

@implementation AppDelegate

- (int)startThings {
- (int)boot {
NSFileManager *manager = [NSFileManager defaultManager];
NSURL *container = [manager containerURLForSecurityApplicationGroupIdentifier:PRODUCT_APP_GROUP_IDENTIFIER];
NSURL *alpineRoot = [container URLByAppendingPathComponent:@"roots/alpine"];
Expand Down Expand Up @@ -158,60 +156,35 @@ - (int)startThings {
NSString *sockTmp = [NSTemporaryDirectory() stringByAppendingString:@"ishsock"];
sock_tmp_prefix = strdup(sockTmp.UTF8String);

tty_drivers[TTY_CONSOLE_MAJOR] = &ios_tty_driver;
tty_drivers[TTY_CONSOLE_MAJOR] = &ios_console_driver;
set_console_device(TTY_CONSOLE_MAJOR, 1);
err = create_stdio("/dev/console");
err = create_stdio("/dev/console", TTY_CONSOLE_MAJOR, 1);
if (err < 0)
return err;

NSArray<NSString *> *command;
command = UserPreferences.shared.bootCommand;
NSLog(@"%@", command);
char argv[4096];
[self convertCommand:command toArgs:argv limitSize:sizeof(argv)];
[Terminal convertCommand:command toArgs:argv limitSize:sizeof(argv)];
const char *envp = "TERM=xterm-256color\0";
err = sys_execve(argv, argv, envp);
if (err < 0)
return err;
task_start(current);

err = [self startSession];
if (err < 0)
return err;

return 0;
}

- (int)startSession {
int err = become_new_init_child();
if (err < 0)
return err;
err = create_stdio("/dev/tty7");
if (err < 0)
return err;
char argv[4096];
[self convertCommand:UserPreferences.shared.launchCommand toArgs:argv limitSize:sizeof(argv)];
const char *envp = "TERM=xterm-256color\0";
err = sys_execve(argv, argv, envp);
if (err < 0)
return err;
self.sessionPid = current->pid;
task_start(current);
return 0;
static int bootError;

+ (int)bootError {
return bootError;
}

- (void)convertCommand:(NSArray<NSString *> *)command toArgs:(char *)argv limitSize:(size_t)maxSize {
char *p = argv;
for (NSString *cmd in command) {
const char *c = cmd.UTF8String;
// Save space for the final NUL byte in argv
while (p < argv + maxSize - 1 && (*p++ = *c++));
// If we reach the end of the buffer, the last string still needs to be
// NUL terminated
*p = '\0';
}
// Add the final NUL byte to argv
*++p = '\0';
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey,id> *)launchOptions {
bootError = [self boot];
return YES;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
Expand All @@ -220,19 +193,10 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(

[UserPreferences.shared addObserver:self forKeyPath:@"shouldDisableDimming" options:NSKeyValueObservingOptionInitial context:nil];

[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(processExited:)
name:ProcessExitedNotification
object:nil];

int err = [self startThings];
if (err < 0) {
NSString *message = [NSString stringWithFormat:@"could not initialize"];
NSString *subtitle = [NSString stringWithFormat:@"error code %d", err];
if (err == _EINVAL)
subtitle = [subtitle stringByAppendingString:@"\n(try reinstalling the app, see release notes for details)"];
[self showMessage:message subtitle:subtitle fatal:NO];
NSLog(@"failed with code %d", err);
if (self.window != nil) {
// For iOS <13, where the app delegate owns the window instead of the scene
TerminalViewController *vc = (TerminalViewController *) self.window.rootViewController;
[vc startNewSession];
}
return YES;
}
Expand All @@ -241,23 +205,6 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
UIApplication.sharedApplication.idleTimerDisabled = UserPreferences.shared.shouldDisableDimming;
}

- (void)processExited:(NSNotification *)notif {
int pid = [notif.userInfo[@"pid"] intValue];
if (pid == self.sessionPid) {
[self startSession];
}
}

- (void)showMessage:(NSString *)message subtitle:(NSString *)subtitle fatal:(BOOL)fatal {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:message message:subtitle preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"k"
style:UIAlertActionStyleDefault
handler:nil]];
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
});
}

- (void)exitApp {
self.exiting = YES;
id app = [UIApplication sharedApplication];
Expand All @@ -269,6 +216,13 @@ - (void)applicationDidEnterBackground:(UIApplication *)application {
exit(0);
}

- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions API_AVAILABLE(ios(13.0)) {
for (UISceneSession *sceneSession in sceneSessions) {
NSString *terminalUUID = sceneSession.stateRestorationActivity.userInfo[@"TerminalUUID"];
[[Terminal terminalWithUUID:[[NSUUID alloc] initWithUUIDString:terminalUUID]] destroy];
}
}

@end

NSString *const ProcessExitedNotification = @"ProcessExitedNotification";
33 changes: 29 additions & 4 deletions app/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,35 @@
<string>61</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>A program running in iSH wants to track your location in the background.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>A program running in iSH wants to track your location.</string>
<key>NSUserActivityTypes</key>
<array>
<string>app.ish.scene</string>
</array>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
<key>UISceneConfigurationName</key>
<string>Terminal</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
</dict>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
Expand Down Expand Up @@ -50,9 +79,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>A program running in iSH wants to track your location in the background.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>A program running in iSH wants to track your location.</string>
</dict>
</plist>
19 changes: 19 additions & 0 deletions app/SceneDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// SceneDelegate.h
// iSH
//
// Created by Theodore Dubois on 10/26/19.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

API_AVAILABLE(ios(13))
@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>

@property (nonatomic) UIWindow *window;

@end

NS_ASSUME_NONNULL_END
43 changes: 43 additions & 0 deletions app/SceneDelegate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// SceneDelegate.m
// iSH
//
// Created by Theodore Dubois on 10/26/19.
//

#import "SceneDelegate.h"
#import "TerminalViewController.h"

@interface SceneDelegate ()

@property NSString *terminalUUID;

@end

static NSString *const TerminalUUID = @"TerminalUUID";

@implementation SceneDelegate

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
TerminalViewController *vc = (TerminalViewController *) self.window.rootViewController;
vc.sceneSession = session;
if (session.stateRestorationActivity == nil) {
[vc startNewSession];
} else {
self.terminalUUID = session.stateRestorationActivity.userInfo[TerminalUUID];
[vc reconnectSessionFromTerminalUUID:
[[NSUUID alloc] initWithUUIDString:self.terminalUUID]];
}
}

- (NSUserActivity *)stateRestorationActivityForScene:(UIScene *)scene {
NSUserActivity *activity = [[NSUserActivity alloc] initWithActivityType:@"app.ish.scene"];
TerminalViewController *vc = (TerminalViewController *) self.window.rootViewController;
self.terminalUUID = vc.sessionTerminalUUID.UUIDString;
if (self.terminalUUID != nil) {
[activity addUserInfoEntriesFromDictionary:@{TerminalUUID: self.terminalUUID}];
}
return activity;
}

@end
14 changes: 13 additions & 1 deletion app/Terminal.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,30 @@
#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>

struct tty;

@interface Terminal : NSObject

+ (Terminal *)terminalWithType:(int)type number:(int)number;
// Returns a strong struct tty and a Terminal that has a weak reference to the same tty
+ (Terminal *)createPseudoTerminal:(struct tty **)tty;

+ (Terminal *)terminalWithUUID:(NSUUID *)uuid;
@property (readonly) NSUUID *uuid;

+ (void)convertCommand:(NSArray<NSString *> *)command toArgs:(char *)argv limitSize:(size_t)maxSize;

- (int)write:(const void *)buf length:(size_t)len;
- (void)sendInput:(const char *)buf length:(size_t)len;

- (NSString *)arrow:(char)direction;

// Make this terminal no longer be the singleton terminal with its type and number. Will happen eventually if all references go away, but sometimes you want it to happen now.
- (void)destroy;

@property (readonly) WKWebView *webView;
@property (nonatomic) BOOL enableVoiceOverAnnounce;

@end

extern struct tty_driver ios_tty_driver;
extern struct tty_driver ios_console_driver;
Loading

0 comments on commit 64576c8

Please sign in to comment.