15 Commits
r1 ... r3

Author SHA1 Message Date
Kelvin Sherlock
4507998f1d version bump 2018-01-31 22:54:46 -05:00
Kelvin Sherlock
9fcf9f333f fix (?) some bugs with IIe/gsos high-bit characters. 2018-01-31 22:37:52 -05:00
Kelvin Sherlock
6a117c7b8a include the a2-terminfo database 2018-01-31 22:37:23 -05:00
Kelvin Sherlock
5bd035e33e add terminfo submodule 2018-01-31 22:02:21 -05:00
Kelvin Sherlock
66040a8366 add ChildMonitor sources to xcode project. 2018-01-31 21:19:31 -05:00
Kelvin Sherlock
b63b60826d set TERMINFO_DIRS to bundle/Resources/terminfo. 2018-01-31 21:19:05 -05:00
Kelvin Sherlock
e0bc21d663 move all the child/fd/kevent monitoring to a dedicated thread / class. 2018-01-31 21:17:31 -05:00
Kelvin Sherlock
8d282293f0 version bump. 2018-01-29 21:35:26 -05:00
Kelvin Sherlock
c41a520ef8 Merge branch 'master' of https://github.com/ksherlock/TwoTerm 2018-01-29 21:24:51 -05:00
Kelvin Sherlock
42b9206abe replace grand-central io/pid monitoring with a dedicated thread and kevents.
based on testing, the pty EOF is never flagged. Instead, exit the thread when the child pid dies.
2018-01-29 21:24:15 -05:00
Kelvin Sherlock
3542ed50ce fix scroll-right bug (PTSE) 2018-01-29 21:22:08 -05:00
ksherlock
b25935338e Create README.md 2018-01-27 14:43:44 -05:00
Kelvin Sherlock
6299c68117 pics 2018-01-27 14:42:24 -05:00
Kelvin Sherlock
0044693288 pics 2018-01-27 14:34:02 -05:00
Kelvin Sherlock
4f1e79178f use ragel version of gno console emulator 2018-01-27 13:26:15 -05:00
16 changed files with 382 additions and 200 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "a2-terminfo"]
path = a2-terminfo
url = https://github.com/ksherlock/a2-terminfo

20
ChildMonitor.h Normal file
View File

@@ -0,0 +1,20 @@
//
// ChildMonitor.h
// TwoTerm
//
// Created by Kelvin Sherlock on 1/31/2018.
//
#import <Foundation/Foundation.h>
@class TermWindowController;
@interface ChildMonitor : NSObject {
}
+(id)monitor;
-(void)removeController: (TermWindowController *)controller;
-(void)addController: (TermWindowController *)controller pid: (pid_t)pid fd: (int)fd;
@end

239
ChildMonitor.mm Normal file
View File

@@ -0,0 +1,239 @@
//
// ChildMonitor.m
// TwoTerm
//
// Created by Kelvin Sherlock on 1/31/2018.
//
#import "ChildMonitor.h"
#import "TermWindowController.h"
#include "Lock.h"
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <vector>
#include <algorithm>
namespace {
struct entry {
pid_t pid;
int fd;
TermWindowController *controller;
};
typedef std::vector<entry> entry_vector;
entry_vector::iterator find_controller(entry_vector &table, TermWindowController *controller) {
return std::find_if(table.begin(), table.end(), [=](const entry &e){
return e.controller == controller;
});
}
entry_vector::iterator find_pid(entry_vector &table, pid_t pid) {
return std::find_if(table.begin(), table.end(), [=](const entry &e){
return e.pid == pid;
});
}
entry_vector::iterator find_fd(entry_vector &table, int fd) {
return std::find_if(table.begin(), table.end(), [=](const entry &e){
return e.fd == fd;
});
}
/* return NO on EOF */
BOOL read(int fd, TermWindowController *controller) {
size_t total = 0;
for (;;) {
uint8_t buffer[2048];
ssize_t ok = ::read(fd, buffer, sizeof(buffer));
if (ok == 0) return total > 0;
if (ok < 1) {
if (errno == EINTR) continue;
if (errno == EAGAIN) return YES;
return YES;
}
[controller processData: buffer size: ok];
if (ok < sizeof(buffer)) return YES;
total += ok;
}
}
}
@interface ChildMonitor() {
std::vector<entry> _table;
int _kq;
Lock _lock;
}
@end
@implementation ChildMonitor
+(id)monitor {
static ChildMonitor *me = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
me = [ChildMonitor new];
[NSThread detachNewThreadSelector: @selector(run) toTarget: me withObject: nil];
});
return me;
}
-(id)init {
if ((self = [super init])) {
_kq = kqueue();
}
return self;
}
-(void)dealloc {
_lock.lock();
close(_kq);
for (const auto &e : _table) {
if (e.fd >= 0) close(e.fd);
if (e.pid > 0) kill(e.pid, SIGHUP);
if (e.controller) [e.controller release];
}
_lock.unlock();
[super dealloc];
}
-(void)removeController: (TermWindowController *)controller {
if (!controller) return;
Locker l(_lock);
auto iter = find_controller(_table, controller);
if (iter != _table.end()) {
[iter->controller release];
iter->controller = nil;
if (iter->pid > 0) kill(iter->pid, SIGHUP);
}
}
-(void)addController: (TermWindowController *)controller pid: (pid_t)pid fd: (int)fd {
NSLog(@"Adding pid: %d fd: %d", pid, fd);
int flags;
// non-blocking io.
if (fcntl(fd, F_GETFL, &flags) < 0) flags = 0;
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
Locker l(_lock);
_table.emplace_back(entry{pid, fd, [controller retain]});
struct kevent events[2] = {};
EV_SET(&events[0], fd, EVFILT_READ, EV_ADD | EV_RECEIPT, 0, 0, NULL);
EV_SET(&events[1], pid, EVFILT_PROC, EV_ADD | EV_ONESHOT | EV_RECEIPT, NOTE_EXIT | NOTE_EXITSTATUS, 0, NULL);
kevent(_kq, events, 2, NULL, 0, NULL);
}
-(void) run {
struct kevent events[16] = {};
for(;;) {
@autoreleasepool {
int n = kevent(_kq, NULL, 0, events, 2, NULL);
if (n < 0) {
NSLog(@"kevent: %s", strerror(errno));
continue;
}
if (n == 0) {
continue;
}
Locker l(_lock);
// should process twice, first for reading, second for dead children.
std::for_each(events, events + n, [&](const struct kevent &e){
if (e.filter != EVFILT_READ) return;
int fd = (int)e.ident;
if (e.flags & EV_EOF) {
NSLog(@"EV_EOF %d", fd);
return;
}
if (e.flags & EV_ERROR) {
NSLog(@"EV_ERROR %d", fd);
return;
}
auto iter = find_fd(_table, fd);
if (iter == _table.end() || iter->controller == nil) {
NSLog(@"Closing fd %d (not found)", fd);
close(fd); // should automatically remove itself from kevent
iter->fd = -1;
} else {
BOOL ok = read(fd, iter->controller);
if (!ok) {
NSLog(@"Closing fd %d (eof)", fd);
close(fd); // should automatically remove itself from kevent
iter->fd = -1;
}
}
});
std::for_each(events, events + n, [&](const struct kevent &e){
if (e.filter != EVFILT_PROC) return;
pid_t pid = (pid_t)e.ident;
int status = 0;
for(;;) {
int ok = waitpid(pid, &status, WNOHANG);
if (ok >= 0) break;
if (errno == EINTR) continue;
NSLog(@"waitpid(%d): %s", pid, strerror(errno));
break;
}
auto iter = find_pid(_table, pid);
if (iter == _table.end()) {
} else {
if (iter->fd >= 0) {
// check for pending i/o ?
if (iter->controller)
read(iter->fd, iter->controller);
NSLog(@"Closing fd %d (child exited)", iter->fd);
close(iter->fd);
iter->fd = -1;
}
[iter->controller childFinished: status];
[iter->controller release];
iter->controller = nil;
*iter = std::move(_table.back());
_table.pop_back();
}
NSLog(@"Child %d finished", pid);
});
}
}
}
@end

View File

@@ -220,26 +220,26 @@
| 0x80 .. 0x9f ${
/* uppercase inverse/normal */
uint8_t flag = ~(_context.flags & Screen::FlagInverse);
uint8_t flag = _context.flags ^ Screen::FlagInverse;
screen->putc(fc - 0x40, _context.cursor, flag);
} $advance
| 0xa0 .. 0xbf ${
/* special inverse/normal */
uint8_t flag = ~(_context.flags & Screen::FlagInverse);
uint8_t flag = _context.flags ^ Screen::FlagInverse;
screen->putc(fc - 0x80, _context.cursor, flag);
} $advance
| 0xc0 .. 0xdf ${
/* uppercase normal / mouse text. */
uint8_t flag = ~(_context.flags & Screen::FlagInverse);
uint8_t flag = _context.flags ^ Screen::FlagInverse;
if (flag) flag |= Screen::FlagMouseText;
screen->putc(fc - 0x80, _context.cursor, flag);
} $advance
| 0xe0 .. 0xff ${
/* special inverse/normal */
uint8_t flag = ~(_context.flags & Screen::FlagInverse);
uint8_t flag = _context.flags ^ Screen::FlagInverse;
screen->putc(fc - 0x80, _context.cursor, flag);
} $advance

View File

@@ -357,7 +357,7 @@
screen->eraseRect(tmp);
}
// hmmm ... embedded control characters seem to be processed as control characters...
# hmmm ... embedded control characters seem to be processed as control characters...
| 0x1e arg1 arg2 ${
// CTRL('^'):
// goto x y
@@ -390,9 +390,6 @@
@implementation GNOConsole
+(void)load
{
[EmulatorManager registerClass: self];

View File

@@ -178,7 +178,7 @@ static void advance(Screen *screen, gsos_context &ctx) {
*/
if (cursor.y < window.maxY()-1) cursor.y++;
else if (_context.consScroll)
screen->scrollUp(window);
screen->scrollUp(window);
}
| 0x0b ${
@@ -420,26 +420,26 @@ static void advance(Screen *screen, gsos_context &ctx) {
| 0x80 .. 0x9f ${
/* uppercase inverse/normal */
uint8_t flags = ~(_context.flags & Screen::FlagInverse);
uint8_t flags = _context.flags ^ Screen::FlagInverse;
screen->putc(fc - 0x40, cursor, flags);
} $advance_if
| 0xa0 .. 0xbf ${
/* special inverse/normal */
uint8_t flags = ~(_context.flags & Screen::FlagInverse);
uint8_t flags = _context.flags ^ Screen::FlagInverse;
screen->putc(fc - 0x80, cursor, flags);
} $advance_if
| 0xc0 .. 0xdf ${
/* uppercase normal / mouse text. */
uint8_t flags = ~(_context.flags & Screen::FlagInverse);
uint8_t flags = _context.flags ^ Screen::FlagInverse;
if (flags) flags |= Screen::FlagMouseText;
screen->putc(fc - 0x80, cursor, flags);
} $advance_if
| 0xe0 .. 0xff ${
/* special inverse/normal */
uint8_t flags = ~(_context.flags & Screen::FlagInverse);
uint8_t flags = _context.flags ^ Screen::FlagInverse;
screen->putc(fc - 0x80, cursor, flags);
} $advance_if

View File

@@ -21,7 +21,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<string>3</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>

12
README.md Normal file
View File

@@ -0,0 +1,12 @@
# TwoTerm
Apple-II inspired terminal emulator for OS X
Uses the Apple II character generator font but also emulates the GS/OS Console, GNO/ME Console, etc.
You'll probably need a [termcap](https://github.com/ksherlock/a2-terminfo) entry.
![](screenshots/vim.png?raw=true)
![](screenshots/cal.png?raw=true)

View File

@@ -7,7 +7,7 @@
//
#import <Cocoa/Cocoa.h>
#include <atomic>
@class EmulatorView;
@class ColorView;
@@ -25,12 +25,6 @@
NSObject <Emulator> *_emulator;
int _fd;
pid_t _pid;
dispatch_source_t _read_source;
dispatch_source_t _wait_source;
}
@property (nonatomic, retain) NSDictionary *parameters;
@@ -41,5 +35,7 @@
@property (nonatomic, retain) NSObject<Emulator> *emulator;
-(void)initPTY;
-(void)childFinished: (int)status;
-(void)processData: (const void *)buffer size: (size_t)size;
@end

View File

@@ -11,8 +11,11 @@
#import "CurveView.h"
#import "EmulatorWindow.h"
//#import "VT52.h"
//#import "PTSE.h"
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <atomic>
#import "Defaults.h"
@@ -28,6 +31,8 @@
#include <string>
#include <vector>
#include "ChildMonitor.h"
@implementation TermWindowController
@synthesize emulator = _emulator;
@@ -43,12 +48,13 @@
-(void)dealloc
{
[[ChildMonitor monitor] removeController: self];
[_emulator release];
[_emulatorView release];
[_colorView release];
[_parameters release];
[super dealloc];
}
@@ -63,16 +69,30 @@
-(void)initPTY
{
static std::string username;
static std::string terminfo;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// getlogin() sometimes returns crap.
username = [NSUserName() UTF8String];
char *cp = getenv("TERMINFO_DIRS");
if (cp && *cp) {
terminfo = cp;
terminfo.push_back(':');
}
NSString *s = [[NSBundle mainBundle] resourcePath];
s = [s stringByAppendingPathComponent: @"terminfo"];
terminfo += [s UTF8String];
});
pid_t pid;
int fd;
struct termios term;
struct winsize ws = [_emulator defaultSize];
memset(&term, 0, sizeof(term));
//term.c_oflag = OPOST | ONLCR;
//term.c_lflag = ECHO;
//term.c_iflag = ICRNL; // | ICANON | ECHOE | ISIG;
term.c_oflag = TTYDEF_OFLAG;
term.c_lflag = TTYDEF_LFLAG;
term.c_iflag = TTYDEF_IFLAG;
@@ -86,21 +106,16 @@
[_emulator initTerm: &term];
// getlogin() sometimes returns crap.
if (username.empty()) {
username = [NSUserName() UTF8String];
}
//NSLog(@"%@ %s %s", NSUserName(), getlogin(), getpwent()->pw_name);
_pid = forkpty(&_fd, NULL, &term, &ws);
pid = forkpty(&fd, NULL, &term, &ws);
if (_pid < 0)
if (pid < 0)
{
fprintf(stderr, "forkpty failed\n");
fflush(stderr);
return;
}
if (_pid == 0)
if (pid == 0)
{
std::vector<const char *> environ;
@@ -115,8 +130,12 @@
s.append("TERM=");
s.append([_emulator termName]);
s.append(1, (char)0);
s.append("TERMINFO_DIRS=");
s.append(terminfo.c_str());
s.append(1, (char)0);
s.append(1, (char)0);
for (std::string::size_type index = 0;;)
@@ -172,145 +191,18 @@
[window setMinSize: [window frame].size];
[_emulatorView setFd: _fd];
[self monitor];
/*
if (!_childMonitor)
{
_childMonitor = [ChildMonitor new];
[_childMonitor setDelegate: _emulatorView];
}
*/
[_emulatorView setFd: fd];
[[ChildMonitor monitor] addController: self pid: pid fd: fd];
}
-(void)monitor {
int fd = _fd;
int pid = _pid;
-(void)childFinished: (int)status {
[_emulatorView childFinished: status];
}
int flags;
// non-blocking io.
if (fcntl(_fd, F_GETFL, &flags) < 0) flags = 0;
fcntl(_fd, F_SETFL, flags | O_NONBLOCK);
[_emulatorView childBegan];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
_wait_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC,
pid, DISPATCH_PROC_EXIT, queue);
if (_wait_source)
{
dispatch_source_set_event_handler(_wait_source, ^{
int status = 0;
int ok;
for(;;) {
ok = waitpid(pid, &status, WNOHANG);
if (ok >= 0) break;
if (errno == EINTR) continue;
break;
}
_pid = 0;
//dispatch_async(dispatch_get_main_queue(), ^(){
[_emulatorView childFinished: status];
//});
dispatch_source_cancel(_wait_source);
dispatch_release(_wait_source);
_wait_source = nullptr;
});
dispatch_resume(_wait_source);
}
#if 0
dispatch_io_t io = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error){
close(fd);
NSLog(@"dispatch_io_create: %d", error);
});
dispatch_io_read(io, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t data, int error){
if (error) {
NSLog(@"dispatch_io_read: %d", error);
dispatch_io_close(io, DISPATCH_IO_STOP);
return;
}
dispatch_data_apply(data, ^(dispatch_data_t, size_t, const void *buffer, size_t size){
[_emulatorView processData: (uint8_t *)buffer size: size];
return true;
} );
if (done) {
NSLog(@"closing fd");
dispatch_io_close(io, DISPATCH_IO_STOP);
return;
}
});
#else
_read_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
fd, 0, queue);
if (_read_source)
{
// Install the event handler
dispatch_source_set_event_handler(_read_source, ^{
static uint8_t sbuffer[1024];
size_t estimated = dispatch_source_get_data(_read_source);
estimated = std::max(estimated, sizeof(sbuffer));
uint8_t *buffer = estimated > sizeof(sbuffer) ? (uint8_t *)malloc(estimated) : sbuffer;
if (buffer)
{
ssize_t actual;
for (;;) {
actual = read(fd, buffer, estimated);
//fprintf(stderr, "read: %ld\n", actual);
if (actual < 0) {
if (errno == EINTR) continue;
if (errno == EAGAIN) {
if (buffer != sbuffer) free(buffer);
return;
}
NSLog(@"read: %s", strerror(errno));
dispatch_source_cancel(_read_source);
dispatch_release(_read_source);
_read_source = nullptr;
}
break;
}
if (actual > 0) [_emulatorView processData: buffer size: actual];
if (buffer != sbuffer) free(buffer);
if (actual == 0) {
dispatch_source_cancel(_read_source);
dispatch_release(_read_source);
_read_source = nullptr;
}
}
});
dispatch_source_set_cancel_handler(_read_source, ^{
NSLog(@"closing fd");
_fd = -1;
[_emulatorView setFd: -1];
close(fd);
});
dispatch_resume(_read_source);
}
#endif
-(void)processData: (const void *)buffer size: (size_t)size {
[_emulatorView processData: (uint8_t *)buffer size: size];
}
#pragma mark -
@@ -379,31 +271,7 @@
-(void)windowWillClose:(NSNotification *)notification
{
if (_wait_source) {
dispatch_source_cancel(_wait_source);
dispatch_release(_wait_source);
}
if (_read_source) {
dispatch_source_cancel(_read_source);
dispatch_release(_read_source);
}
int status;
int ok;
if (_pid) {
kill(_pid, 9);
for(;;) {
ok = waitpid(_pid, &status, 0);
if (ok >= 0) break;
if (errno == EINTR) continue;
perror("waitpid: ");
break;
}
}
[[ChildMonitor monitor] removeController: self];
[self autorelease];
}

View File

@@ -33,6 +33,7 @@
B61EF7D81482FB6D008C1891 /* titlebar-left.png in Resources */ = {isa = PBXBuildFile; fileRef = B61EF7D51482FB6D008C1891 /* titlebar-left.png */; };
B61EF7D91482FB6D008C1891 /* titlebar-right.png in Resources */ = {isa = PBXBuildFile; fileRef = B61EF7D61482FB6D008C1891 /* titlebar-right.png */; };
B638188214A179D60027D007 /* ColorView.m in Sources */ = {isa = PBXBuildFile; fileRef = B638188114A179D60027D007 /* ColorView.m */; };
B6407805201CE93500D3F2D1 /* GNOConsole.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B612F45B12DD5DF1005D1B77 /* GNOConsole.mm.ragel */; };
B66412391480A070003BC8D3 /* EmulatorWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = B66412381480A070003BC8D3 /* EmulatorWindow.m */; };
B675F4A81E540394004B0D9C /* Screen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B612F44D12DD5DAD005D1B77 /* Screen.cpp */; };
B675F4A91E561D20004B0D9C /* Apple80.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B612F45712DD5DF1005D1B77 /* Apple80.mm.ragel */; };
@@ -43,7 +44,7 @@
B67B3CE612B6FA040033AE07 /* a2-charset-80.png in Resources */ = {isa = PBXBuildFile; fileRef = B67B3CE412B6FA040033AE07 /* a2-charset-80.png */; };
B6801BD912EB549300B22E9E /* vt100-charset.png in Resources */ = {isa = PBXBuildFile; fileRef = B6801BD812EB549300B22E9E /* vt100-charset.png */; };
B68E632A12FF909D00EAFF5F /* ExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = B68E632912FF909C00EAFF5F /* ExampleView.m */; };
B6ACA2AC1E5C8BEC000E774B /* GNOConsole.mm in Sources */ = {isa = PBXBuildFile; fileRef = B6ACA2AB1E5C8BEC000E774B /* GNOConsole.mm */; };
B69E32A920221C9E0086D7B1 /* ChildMonitor.mm in Sources */ = {isa = PBXBuildFile; fileRef = B69E32A820221C9E0086D7B1 /* ChildMonitor.mm */; };
B6ACA2AD1E614E38000E774B /* VT52.mm in Sources */ = {isa = PBXBuildFile; fileRef = B612F46312DD5DF1005D1B77 /* VT52.mm */; };
B6ACA2AF1E635CEC000E774B /* vt52-charset.png in Resources */ = {isa = PBXBuildFile; fileRef = B6ACA2AE1E635CEC000E774B /* vt52-charset.png */; };
B6C704EF15CCC64100CC0401 /* titlebar-center@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C704EC15CCC64100CC0401 /* titlebar-center@2x.png */; };
@@ -102,6 +103,10 @@
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8D1107320486CEB800E47090 /* TwoTerm.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TwoTerm.app; sourceTree = BUILT_PRODUCTS_DIR; };
B60B98712022BAF100E688E3 /* appleIIgs.ti */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = appleIIgs.ti; sourceTree = "<group>"; };
B60B98732022BAF100E688E3 /* gno-console.ti */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "gno-console.ti"; sourceTree = "<group>"; };
B60B98742022BAF100E688E3 /* gsos-console.ti */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "gsos-console.ti"; sourceTree = "<group>"; };
B60B98762022BAF100E688E3 /* proterm-special.ti */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "proterm-special.ti"; sourceTree = "<group>"; };
B60EBD1111E8DEEF00C1974F /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; };
B60EBDE111E90FC300C1974F /* ScanLineFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScanLineFilter.h; sourceTree = "<group>"; };
B60EBDE211E90FC300C1974F /* ScanLineFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScanLineFilter.m; sourceTree = "<group>"; };
@@ -159,6 +164,8 @@
B6801BD812EB549300B22E9E /* vt100-charset.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "vt100-charset.png"; sourceTree = "<group>"; };
B68E632812FF909C00EAFF5F /* ExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleView.h; sourceTree = "<group>"; };
B68E632912FF909C00EAFF5F /* ExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleView.m; sourceTree = "<group>"; };
B69E32A820221C9E0086D7B1 /* ChildMonitor.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ChildMonitor.mm; sourceTree = "<group>"; };
B69E32AA20221CCA0086D7B1 /* ChildMonitor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ChildMonitor.h; sourceTree = "<group>"; };
B6ACA2AB1E5C8BEC000E774B /* GNOConsole.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GNOConsole.mm; sourceTree = "<group>"; };
B6ACA2AE1E635CEC000E774B /* vt52-charset.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "vt52-charset.png"; sourceTree = "<group>"; };
B6C173901D31D2B80024E360 /* GSOSConsole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GSOSConsole.h; sourceTree = "<group>"; };
@@ -200,6 +207,8 @@
B6EBE2B411E0EA9100EA0458 /* CharacterGenerator.mm */,
B60EBDE111E90FC300C1974F /* ScanLineFilter.h */,
B60EBDE211E90FC300C1974F /* ScanLineFilter.m */,
B69E32A820221C9E0086D7B1 /* ChildMonitor.mm */,
B69E32AA20221CCA0086D7B1 /* ChildMonitor.h */,
);
name = Classes;
sourceTree = "<group>";
@@ -260,6 +269,7 @@
29B97317FDCFA39411CA2CEA /* Resources */ = {
isa = PBXGroup;
children = (
B60B98702022BAF100E688E3 /* a2-terminfo */,
B60EBDE711E9143F00C1974F /* ScanLineFilter.cikernel */,
B66979CE11E6BCAE002ED475 /* images */,
8D1107310486CEB800E47090 /* Info.plist */,
@@ -281,6 +291,17 @@
name = Frameworks;
sourceTree = "<group>";
};
B60B98702022BAF100E688E3 /* a2-terminfo */ = {
isa = PBXGroup;
children = (
B60B98712022BAF100E688E3 /* appleIIgs.ti */,
B60B98732022BAF100E688E3 /* gno-console.ti */,
B60B98742022BAF100E688E3 /* gsos-console.ti */,
B60B98762022BAF100E688E3 /* proterm-special.ti */,
);
path = "a2-terminfo";
sourceTree = "<group>";
};
B612F44612DD5DAD005D1B77 /* cpp */ = {
isa = PBXGroup;
children = (
@@ -375,6 +396,7 @@
8D11072C0486CEB800E47090 /* Sources */,
8D11072E0486CEB800E47090 /* Frameworks */,
B61D0D57125B728D001C713B /* CopyFiles */,
B60B98802022BF5900E688E3 /* ShellScript */,
);
buildRules = (
B6C173931D32A8840024E360 /* PBXBuildRule */,
@@ -441,6 +463,22 @@
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
B60B98802022BF5900E688E3 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "for x in \"$PROJECT_DIR/a2-terminfo/\"*.ti ; do\ntic -N -s -o \"$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/terminfo\" \"$x\"\ndone";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8D11072C0486CEB800E47090 /* Sources */ = {
isa = PBXSourcesBuildPhase;
@@ -449,6 +487,8 @@
B675F4A91E561D20004B0D9C /* Apple80.mm.ragel in Sources */,
B675F4AC1E56A7F2004B0D9C /* GSOSConsole.mm.ragel in Sources */,
B6D1CD071E577E7D00C4A6BC /* PTSE.mm.ragel in Sources */,
B69E32A920221C9E0086D7B1 /* ChildMonitor.mm in Sources */,
B6407805201CE93500D3F2D1 /* GNOConsole.mm.ragel in Sources */,
8D11072D0486CEB800E47090 /* main.m in Sources */,
256AC3DA0F4B6AC300CF3369 /* TwoTermAppDelegate.mm in Sources */,
B676063B11DEAD3500D6B66C /* TermWindowController.mm in Sources */,
@@ -457,7 +497,6 @@
B61D0D60125B7ACA001C713B /* NewTerminalWindowController.mm in Sources */,
B61D0D69125B8E06001C713B /* Defaults.m in Sources */,
B6ECFF271D2EEA2B00871A81 /* TextLabel.m in Sources */,
B6ACA2AC1E5C8BEC000E774B /* GNOConsole.mm in Sources */,
B612F45012DD5DAD005D1B77 /* iGeometry.cpp in Sources */,
B612F45112DD5DAD005D1B77 /* Lock.cpp in Sources */,
B612F45212DD5DAD005D1B77 /* OutputChannel.cpp in Sources */,

View File

@@ -31,6 +31,13 @@
NSDictionary *parameters;
CIFilter *filter;
#if 0
struct sigaction sa = {};
sa.sa_handler = SIG_IGN;
sa.sa_flags = SA_RESTART;
sigaction(SIGCHLD, &sa, NULL);
#endif
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver: self selector: @selector(newTerminal:) name: kNotificationNewTerminal object: nil];

1
a2-terminfo Submodule

Submodule a2-terminfo added at b91763ed70

View File

@@ -321,7 +321,7 @@ void Screen::scrollRight(iRect rect, int n) {
auto xIter = line.begin() + rect.minX();
auto xEnd = line.begin() + rect.maxX();
auto iter = std::copy(xIter, xEnd-n, xEnd);
auto iter = std::copy_backward(xIter, xEnd-n, xEnd);
while (n--) { --iter; *iter = char_info(); }
}

BIN
screenshots/cal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

BIN
screenshots/vim.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB