2010-07-08 22:26:58 +00:00
|
|
|
//
|
|
|
|
// TermWindowController.m
|
|
|
|
// 2Term
|
|
|
|
//
|
|
|
|
// Created by Kelvin Sherlock on 7/2/2010.
|
|
|
|
// Copyright 2010 __MyCompanyName__. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "TermWindowController.h"
|
|
|
|
#import "EmulatorView.h"
|
2010-12-18 17:40:58 +00:00
|
|
|
#import "CurveView.h"
|
2010-10-05 19:05:42 +00:00
|
|
|
|
2010-12-18 17:40:58 +00:00
|
|
|
#import "VT52.h"
|
|
|
|
#import "PTSE.h"
|
2010-07-08 22:26:58 +00:00
|
|
|
|
2010-12-20 23:37:02 +00:00
|
|
|
#import "Defaults.h"
|
|
|
|
|
|
|
|
|
2010-07-08 22:26:58 +00:00
|
|
|
#define TTYDEFCHARS
|
|
|
|
|
|
|
|
#include <util.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/ttydefaults.h>
|
|
|
|
|
2010-10-05 18:56:45 +00:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
2010-07-08 22:26:58 +00:00
|
|
|
@implementation TermWindowController
|
|
|
|
|
2010-10-05 18:56:45 +00:00
|
|
|
@synthesize emulator = _emulator;
|
2010-12-18 17:40:58 +00:00
|
|
|
@synthesize emulatorView = _emulatorView;
|
|
|
|
@synthesize curveView = _curveView;
|
2010-10-05 18:56:45 +00:00
|
|
|
|
2010-12-20 23:37:02 +00:00
|
|
|
@synthesize parameters = _parameters;
|
|
|
|
|
2010-07-08 22:26:58 +00:00
|
|
|
+(id)new
|
|
|
|
{
|
|
|
|
return [[self alloc] initWithWindowNibName: @"TermWindow"];
|
|
|
|
}
|
|
|
|
|
2010-10-05 18:56:45 +00:00
|
|
|
-(void)dealloc
|
2011-01-20 02:36:06 +00:00
|
|
|
{
|
2010-10-05 18:56:45 +00:00
|
|
|
[_emulator release];
|
2010-12-18 17:40:58 +00:00
|
|
|
[_emulatorView release];
|
|
|
|
[_curveView release];
|
|
|
|
|
2010-12-20 23:37:02 +00:00
|
|
|
[_parameters release];
|
2011-01-20 02:36:06 +00:00
|
|
|
|
2010-10-05 18:56:45 +00:00
|
|
|
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-07-08 22:26:58 +00:00
|
|
|
-(void)awakeFromNib
|
|
|
|
{
|
|
|
|
[self initPTY];
|
|
|
|
}
|
2010-10-05 18:56:45 +00:00
|
|
|
*/
|
2010-07-08 22:26:58 +00:00
|
|
|
|
|
|
|
-(void)initPTY
|
|
|
|
{
|
|
|
|
struct termios term;
|
2010-10-06 00:39:09 +00:00
|
|
|
struct winsize ws = [_emulator defaultSize];
|
2010-07-08 22:26:58 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
term.c_cflag = TTYDEF_CFLAG;
|
|
|
|
|
|
|
|
term.c_ispeed = term.c_ospeed = TTYDEF_SPEED;
|
|
|
|
|
|
|
|
memcpy(term.c_cc, ttydefchars, sizeof(ttydefchars));
|
|
|
|
|
2011-01-11 00:29:59 +00:00
|
|
|
if ([_emulator respondsToSelector: @selector(initTerm:)])
|
|
|
|
[_emulator initTerm: &term];
|
2010-07-08 22:26:58 +00:00
|
|
|
|
|
|
|
|
2016-07-06 17:15:13 +00:00
|
|
|
_pid = forkpty(&_fd, NULL, &term, &ws);
|
2010-07-08 22:26:58 +00:00
|
|
|
|
2016-07-06 17:15:13 +00:00
|
|
|
if (_pid < 0)
|
2010-07-08 22:26:58 +00:00
|
|
|
{
|
2010-10-06 00:39:09 +00:00
|
|
|
fprintf(stderr, "forkpty failed\n");
|
|
|
|
fflush(stderr);
|
|
|
|
|
2010-07-08 22:26:58 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-07-06 17:15:13 +00:00
|
|
|
if (_pid == 0)
|
2010-07-08 22:26:58 +00:00
|
|
|
{
|
2010-10-05 18:56:45 +00:00
|
|
|
|
|
|
|
std::vector<const char *> environ;
|
|
|
|
std::string s;
|
2010-10-06 00:39:09 +00:00
|
|
|
|
2010-10-05 18:56:45 +00:00
|
|
|
|
|
|
|
s.append("TERM_PROGRAM=2Term");
|
|
|
|
s.append(1, (char)0);
|
|
|
|
|
|
|
|
s.append("LANG=C");
|
|
|
|
s.append(1, (char)0);
|
|
|
|
|
|
|
|
s.append("TERM=");
|
|
|
|
s.append([_emulator termName]);
|
|
|
|
|
|
|
|
s.append(1, (char)0);
|
|
|
|
s.append(1, (char )0);
|
|
|
|
|
|
|
|
for (std::string::size_type index = 0;;)
|
|
|
|
{
|
|
|
|
environ.push_back(&s[index]);
|
|
|
|
|
|
|
|
index = s.find((char)0, index);
|
|
|
|
if (index == std::string::npos) break;
|
|
|
|
|
|
|
|
if (s[++index] == 0) break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
environ.push_back(NULL);
|
|
|
|
|
|
|
|
|
2010-07-08 22:26:58 +00:00
|
|
|
// call login -f [username]
|
2010-10-05 18:56:45 +00:00
|
|
|
// -p -- do NOT ignore environment.
|
2010-07-08 22:26:58 +00:00
|
|
|
// export TERM=...
|
|
|
|
|
|
|
|
|
2010-10-05 18:56:45 +00:00
|
|
|
// TODO -- option for localhost, telnet, ssh, etc.
|
|
|
|
execle("/usr/bin/login", "login", "-pf", getlogin(), NULL, &environ[0]);
|
2010-10-06 00:39:09 +00:00
|
|
|
|
2010-07-08 22:26:58 +00:00
|
|
|
fprintf(stderr, "execle failed\n");
|
|
|
|
fflush(stderr);
|
|
|
|
|
2010-12-21 05:17:15 +00:00
|
|
|
// should not call exit.
|
|
|
|
_exit(-1);
|
2010-07-08 22:26:58 +00:00
|
|
|
// child
|
|
|
|
}
|
|
|
|
|
2016-07-06 17:15:13 +00:00
|
|
|
|
2010-12-20 23:37:02 +00:00
|
|
|
|
2011-01-11 04:35:45 +00:00
|
|
|
[_emulatorView resizeTo: iSize(ws.ws_col, ws.ws_row) animated: NO];
|
2010-07-08 22:26:58 +00:00
|
|
|
|
2016-07-06 17:15:13 +00:00
|
|
|
|
|
|
|
NSWindow *window = [self window];
|
|
|
|
|
2010-10-06 00:39:09 +00:00
|
|
|
if (![_emulator resizable])
|
|
|
|
{
|
|
|
|
|
|
|
|
NSUInteger mask = [window styleMask];
|
|
|
|
|
|
|
|
|
|
|
|
[window setShowsResizeIndicator: NO];
|
|
|
|
|
|
|
|
[window setStyleMask: mask & ~NSResizableWindowMask];
|
|
|
|
}
|
2016-07-06 17:15:13 +00:00
|
|
|
|
|
|
|
[window setMinSize: [window frame].size];
|
|
|
|
|
|
|
|
[_emulatorView setFd: _fd];
|
|
|
|
[self monitor];
|
|
|
|
|
|
|
|
/*
|
2011-01-20 02:36:06 +00:00
|
|
|
if (!_childMonitor)
|
|
|
|
{
|
|
|
|
_childMonitor = [ChildMonitor new];
|
|
|
|
[_childMonitor setDelegate: _emulatorView];
|
|
|
|
}
|
2016-07-06 17:15:13 +00:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void)monitor {
|
|
|
|
|
|
|
|
int fd = _fd;
|
|
|
|
int pid = _pid;
|
|
|
|
|
|
|
|
int flags;
|
|
|
|
// non-blocking io.
|
|
|
|
if (fcntl(_fd, F_GETFL, &flags) < 0) flags = 0;
|
|
|
|
fcntl(_fd, F_SETFL, flags | O_NONBLOCK);
|
2011-01-20 02:36:06 +00:00
|
|
|
|
2016-07-06 17:15:13 +00:00
|
|
|
|
|
|
|
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;
|
2016-07-06 17:37:15 +00:00
|
|
|
waitpid(pid, &status, WNOHANG);
|
2016-07-06 17:15:13 +00:00
|
|
|
|
|
|
|
_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);
|
|
|
|
}
|
|
|
|
|
2010-07-08 22:26:58 +00:00
|
|
|
|
2016-07-06 17:15:13 +00:00
|
|
|
_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];
|
2016-07-06 19:12:51 +00:00
|
|
|
size_t estimated = dispatch_source_get_data(_read_source);
|
2016-07-06 17:15:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
uint8_t *buffer = estimated > sizeof(sbuffer) ? (uint8_t *)malloc(estimated) : sbuffer;
|
|
|
|
if (buffer)
|
|
|
|
{
|
|
|
|
ssize_t actual;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
actual = read(fd, buffer, (estimated));
|
|
|
|
if (actual < 0) {
|
|
|
|
if (errno == EINTR || errno == EAGAIN) 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 && _pid == 0) {
|
|
|
|
dispatch_source_cancel(_read_source);
|
|
|
|
dispatch_release(_read_source);
|
|
|
|
_read_source = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2010-07-08 22:26:58 +00:00
|
|
|
|
2016-07-06 17:15:13 +00:00
|
|
|
|
|
|
|
dispatch_source_set_cancel_handler(_read_source, ^{
|
|
|
|
_fd = -1;
|
|
|
|
[_emulatorView setFd: -1];
|
|
|
|
close(fd);
|
|
|
|
});
|
|
|
|
|
|
|
|
dispatch_resume(_read_source);
|
|
|
|
}
|
|
|
|
}
|
2010-07-08 22:26:58 +00:00
|
|
|
|
2010-10-05 18:56:45 +00:00
|
|
|
#pragma mark -
|
|
|
|
#pragma mark NSWindowDelegate
|
|
|
|
|
|
|
|
- (void)windowDidLoad
|
|
|
|
{
|
2010-12-20 23:37:02 +00:00
|
|
|
|
|
|
|
BOOL scanLines;
|
|
|
|
NSColor *foregroundColor;
|
|
|
|
NSColor *backgroundColor;
|
|
|
|
Class klass;
|
|
|
|
id o;
|
|
|
|
|
2011-01-17 02:34:48 +00:00
|
|
|
NSWindow *window;
|
|
|
|
|
2010-10-05 18:56:45 +00:00
|
|
|
[super windowDidLoad];
|
|
|
|
|
2011-01-17 02:34:48 +00:00
|
|
|
window = [self window];
|
|
|
|
|
2011-11-26 17:04:20 +00:00
|
|
|
//[(CurveView *)[window contentView] setColor: [NSColor clearColor]];
|
|
|
|
|
|
|
|
//[window setContentView: _curveView];
|
|
|
|
|
|
|
|
// resize in 2.0 height increments to prevent jittering the scan lines.
|
|
|
|
//[window setResizeIncrements: NSMakeSize(1.0, 2.0)];
|
2011-01-17 02:34:48 +00:00
|
|
|
|
|
|
|
|
2010-12-20 23:37:02 +00:00
|
|
|
klass = [_parameters objectForKey: kClass];
|
|
|
|
if (!klass || ![klass conformsToProtocol: @protocol(Emulator)])
|
2010-12-18 17:40:58 +00:00
|
|
|
{
|
2010-12-20 23:37:02 +00:00
|
|
|
klass = [VT52 class];
|
2010-12-18 17:40:58 +00:00
|
|
|
}
|
2010-10-05 18:56:45 +00:00
|
|
|
|
2010-12-20 23:37:02 +00:00
|
|
|
o = [_parameters objectForKey: kScanLines];
|
|
|
|
scanLines = o ? [(NSNumber *)o boolValue] : YES;
|
|
|
|
|
|
|
|
o = [_parameters objectForKey: kForegroundColor];
|
|
|
|
foregroundColor = o ? (NSColor *)o : [NSColor greenColor];
|
|
|
|
|
|
|
|
o = [_parameters objectForKey: kBackgroundColor];
|
|
|
|
backgroundColor = o ? (NSColor *)o : [NSColor blackColor];
|
|
|
|
|
|
|
|
|
|
|
|
[self willChangeValueForKey: @"emulator"];
|
|
|
|
_emulator = [klass new];
|
|
|
|
[self didChangeValueForKey: @"emulator"];
|
|
|
|
|
2011-12-23 20:35:00 +00:00
|
|
|
[window setBackgroundColor: backgroundColor];
|
2010-12-20 23:37:02 +00:00
|
|
|
|
2010-10-05 18:56:45 +00:00
|
|
|
[_emulatorView setEmulator: _emulator];
|
2010-12-20 23:37:02 +00:00
|
|
|
[_emulatorView setForegroundColor: foregroundColor];
|
|
|
|
[_emulatorView setBackgroundColor: backgroundColor];
|
2011-02-14 16:34:05 +00:00
|
|
|
//[_emulatorView setScanLines: scanLines];
|
2010-12-20 23:37:02 +00:00
|
|
|
|
2011-02-14 16:34:05 +00:00
|
|
|
[_curveView setColor: backgroundColor];
|
|
|
|
|
|
|
|
o = [_parameters objectForKey: kContentFilters];
|
|
|
|
if (o)
|
|
|
|
{
|
2011-11-26 17:04:20 +00:00
|
|
|
//CALayer *layer;
|
2011-02-14 16:34:05 +00:00
|
|
|
[_curveView setWantsLayer: YES];
|
2011-11-26 17:04:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
CGColorRef color;
|
|
|
|
|
|
|
|
color = CGColorCreateGenericRGB(1.0, 0.0, 0.0, 1.0);
|
|
|
|
|
|
|
|
layer = [_curveView layer];
|
|
|
|
[layer setCornerRadius: 20.0];
|
|
|
|
[layer setBorderWidth: 4.0];
|
|
|
|
[layer setBorderColor: color];
|
|
|
|
[layer setBackgroundColor: color];
|
|
|
|
|
|
|
|
[layer setBackgroundFilters: (NSArray *)o];
|
|
|
|
|
|
|
|
CGColorRelease(color);
|
|
|
|
*/
|
2011-02-14 16:34:05 +00:00
|
|
|
[_curveView setContentFilters: (NSArray *)o];
|
2011-12-21 01:40:16 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
CALayer *layer;
|
|
|
|
CGColorRef color;
|
|
|
|
|
|
|
|
color = CGColorCreateGenericRGB(1.0, 0.0, 0.0, 1.0);
|
|
|
|
layer = [CALayer layer];
|
|
|
|
[layer setFrame: CGRectMake(100, 100, 100, 100)];
|
|
|
|
[layer setBackgroundColor: color];
|
|
|
|
[layer setBackgroundFilters: nil];
|
|
|
|
|
|
|
|
CGColorRelease(color);
|
|
|
|
|
|
|
|
[[_curveView layer] addSublayer: layer];
|
|
|
|
|
|
|
|
NSLog(@"%@", [layer backgroundFilters]);
|
|
|
|
NSLog(@"%@", [[_curveView layer] backgroundFilters]);
|
|
|
|
*/
|
2011-02-14 16:34:05 +00:00
|
|
|
}
|
2010-10-05 18:56:45 +00:00
|
|
|
|
2011-11-26 17:04:20 +00:00
|
|
|
/*
|
|
|
|
NSShadow *shadow;
|
|
|
|
shadow = [[NSShadow alloc] init];
|
|
|
|
[shadow setShadowColor:[NSColor blackColor]];
|
|
|
|
[shadow setShadowOffset: NSZeroSize];
|
|
|
|
[shadow setShadowBlurRadius: 10.0];
|
|
|
|
|
|
|
|
[_curveView setShadow: shadow];
|
|
|
|
[shadow release];
|
|
|
|
*/
|
|
|
|
|
2010-12-20 23:37:02 +00:00
|
|
|
//[_curveView initScanLines];
|
|
|
|
//[_curveView setColor: [NSColor blueColor]];
|
2011-01-20 02:36:06 +00:00
|
|
|
|
2010-10-05 18:56:45 +00:00
|
|
|
[self initPTY];
|
2011-01-17 02:34:48 +00:00
|
|
|
|
2010-10-05 18:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
-(void)windowWillClose:(NSNotification *)notification
|
|
|
|
{
|
2016-07-06 17:15:13 +00:00
|
|
|
if (_wait_source) {
|
|
|
|
dispatch_source_cancel(_wait_source);
|
|
|
|
dispatch_release(_wait_source);
|
|
|
|
}
|
2011-01-20 02:36:06 +00:00
|
|
|
|
2016-07-06 17:15:13 +00:00
|
|
|
if (_read_source) {
|
|
|
|
dispatch_source_cancel(_read_source);
|
|
|
|
dispatch_release(_read_source);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_pid) kill(_pid, 9);
|
|
|
|
|
2010-10-05 18:56:45 +00:00
|
|
|
[self autorelease];
|
|
|
|
}
|
|
|
|
|
2010-07-08 22:26:58 +00:00
|
|
|
@end
|
2016-07-06 17:15:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
|