This is a minimalistic version of a terminal.

It can be run under R5 and Haiku (binary compatible) and should work
with the Haiku app_server and input_server.
It gives access to a /bin/sh like a normal terminal, but has no fancy features
like different text encoding support and it cannot even redraw itself when
something else overdraws it.
But it's pretty impressiv that it works so well under Haiku.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12068 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2005-03-27 06:11:38 +00:00
parent 6109122c9b
commit 160bd2ffca
11 changed files with 1396 additions and 0 deletions

View File

@ -0,0 +1,576 @@
/*
* Console.cpp - Mimicing the console driver
* Based on the console driver.
*
* Copyright 2005 Michael Lotz. All rights reserved.
* Distributed under the Haiku License.
*
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
#include "Console.h"
#include "ViewBuffer.h"
#include <stdio.h>
Console::Console(ViewBuffer *output)
: fOutput(output)
{
fOutput->GetSize(&fColumns, &fLines);
fOutput->SetResizeCallback(&ResizeCallback, this);
ResetConsole();
GotoXY(0, 0);
SaveCursor(true);
fOutput->Clear(0x0f);
}
Console::~Console()
{
}
void
Console::ResetConsole()
{
fAttr = 0x0f;
fScrollTop = 0;
fScrollBottom = fLines - 1;
fBrightAttr = true;
fReverseAttr = false;
}
void
Console::ResizeCallback(int32 width, int32 height, void *data)
{
Console *console = (Console *)data;
console->fColumns = width;
console->fLines = height;
console->SetScrollRegion(console->fScrollTop, height - 1);
}
void
Console::SetScrollRegion(int top, int bottom)
{
if (top < 0)
top = 0;
if (bottom >= fLines)
bottom = fLines - 1;
if (top > bottom)
return;
fScrollTop = top;
fScrollBottom = bottom;
}
void
Console::ScrollUp()
{
// see if cursor is outside of scroll region
if (fY < fScrollTop || fY > fScrollBottom)
return;
if (fY - fScrollTop > 1) {
// move the screen up one
fOutput->Blit(0, fScrollTop + 1, fColumns, fY - fScrollTop, 0, fScrollTop);
}
// clear the bottom line
fOutput->FillGlyph(0, fY, fColumns, 1, ' ', fAttr);
}
void
Console::ScrollDown()
{
// see if cursor is outside of scroll region
if (fY < fScrollTop || fY > fScrollBottom)
return;
if (fScrollBottom - fY > 1) {
// move the screen down one
fOutput->Blit(0, fY, fColumns, fScrollBottom - fY, 0, fY + 1);
}
// clear the top line
fOutput->FillGlyph(0, fY, fColumns, 1, ' ', fAttr);
}
void
Console::LineFeed()
{
if (fY == fScrollBottom) {
// we hit the bottom of our scroll region
ScrollUp();
} else if (fY < fScrollBottom) {
fY++;
}
}
void
Console::RLineFeed()
{
if (fY == fScrollTop) {
// we hit the top of our scroll region
ScrollDown();
} else if (fY > fScrollTop) {
fY--;
}
}
void
Console::CariageReturn()
{
fX = 0;
}
void
Console::Delete()
{
if (fX > 0) {
fX--;
} else if (fY > 0) {
fY--;
fX = fColumns - 1;
} else {
ScrollDown();
fY--;
fX = fColumns - 1;
return;
}
fOutput->PutGlyph(fX, fY, ' ', fAttr);
}
void
Console::Tab()
{
fX = (fX + TAB_SIZE) & ~TAB_MASK;
if (fX >= fColumns) {
fX -= fColumns;
LineFeed();
}
}
void
Console::EraseLine(erase_line_mode mode)
{
switch (mode) {
case LINE_ERASE_WHOLE:
fOutput->FillGlyph(0, fY, fColumns, 1, ' ', fAttr);
break;
case LINE_ERASE_LEFT:
fOutput->FillGlyph(0, fY, fX + 1, 1, ' ', fAttr);
break;
case LINE_ERASE_RIGHT:
fOutput->FillGlyph(fX, fY, fColumns - fX, 1, ' ', fAttr);
break;
default:
return;
}
}
void
Console::EraseScreen(erase_screen_mode mode)
{
switch (mode) {
case SCREEN_ERASE_WHOLE:
fOutput->Clear(fAttr);
break;
case SCREEN_ERASE_UP:
fOutput->FillGlyph(0, 0, fColumns, fY + 1, ' ', fAttr);
break;
case SCREEN_ERASE_DOWN:
fOutput->FillGlyph(fY, 0, fColumns, fLines - fY, ' ', fAttr);
break;
default:
return;
}
}
void
Console::SaveCursor(bool save_attrs)
{
fSavedX = fX;
fSavedY = fY;
if (save_attrs)
fSavedAttr = fAttr;
}
void
Console::RestoreCursor(bool restore_attrs)
{
fX = fSavedX;
fY = fSavedY;
if (restore_attrs)
fAttr = fSavedAttr;
}
void
Console::UpdateCursor(int x, int y)
{
fOutput->MoveCursor(x, y);
}
void
Console::GotoXY(int new_x, int new_y)
{
if (new_x >= fColumns)
new_x = fColumns - 1;
if (new_x < 0)
new_x = 0;
if (new_y >= fLines)
new_y = fLines - 1;
if (new_y < 0)
new_y = 0;
fX = new_x;
fY = new_y;
}
void
Console::PutChar(const char c)
{
fOutput->PutGlyph(fX, fY, c, fAttr);
if (++fX >= fColumns) {
CariageReturn();
LineFeed();
}
}
void
Console::SetVT100Attributes(int32 *args, int32 argCount)
{
if (argCount == 0) {
// that's the default (attributes off)
argCount++;
args[0] = 0;
}
for (int32 i = 0; i < argCount; i++) {
switch (args[i]) {
case 0: // reset
fAttr = 0x0f;
fBrightAttr = true;
fReverseAttr = false;
break;
case 1: // bright
fBrightAttr = true;
fAttr |= 0x08; // set the bright bit
break;
case 2: // dim
fBrightAttr = false;
fAttr &= ~0x08; // unset the bright bit
break;
case 4: // underscore we can't do
break;
case 5: // blink
fAttr |= 0x80; // set the blink bit
break;
case 7: // reverse
fReverseAttr = true;
fAttr = ((fAttr & BMASK) >> 4) | ((fAttr & FMASK) << 4);
if (fBrightAttr)
fAttr |= 0x08;
break;
case 8: // hidden?
break;
/* foreground colors */
case 30: fAttr = (fAttr & ~FMASK) | 0 | (fBrightAttr ? 0x08 : 0); break; // black
case 31: fAttr = (fAttr & ~FMASK) | 4 | (fBrightAttr ? 0x08 : 0); break; // red
case 32: fAttr = (fAttr & ~FMASK) | 2 | (fBrightAttr ? 0x08 : 0); break; // green
case 33: fAttr = (fAttr & ~FMASK) | 6 | (fBrightAttr ? 0x08 : 0); break; // yellow
case 34: fAttr = (fAttr & ~FMASK) | 1 | (fBrightAttr ? 0x08 : 0); break; // blue
case 35: fAttr = (fAttr & ~FMASK) | 5 | (fBrightAttr ? 0x08 : 0); break; // magenta
case 36: fAttr = (fAttr & ~FMASK) | 3 | (fBrightAttr ? 0x08 : 0); break; // cyan
case 37: fAttr = (fAttr & ~FMASK) | 7 | (fBrightAttr ? 0x08 : 0); break; // white
/* background colors */
case 40: fAttr = (fAttr & ~BMASK) | (0 << 4); break; // black
case 41: fAttr = (fAttr & ~BMASK) | (4 << 4); break; // red
case 42: fAttr = (fAttr & ~BMASK) | (2 << 4); break; // green
case 43: fAttr = (fAttr & ~BMASK) | (6 << 4); break; // yellow
case 44: fAttr = (fAttr & ~BMASK) | (1 << 4); break; // blue
case 45: fAttr = (fAttr & ~BMASK) | (5 << 4); break; // magenta
case 46: fAttr = (fAttr & ~BMASK) | (3 << 4); break; // cyan
case 47: fAttr = (fAttr & ~BMASK) | (7 << 4); break; // white
}
}
}
bool
Console::ProcessVT100Command(const char c, bool seen_bracket, int32 *args, int32 argCount)
{
bool ret = true;
if (seen_bracket) {
switch(c) {
case 'H': /* set cursor position */
case 'f': {
int32 row = argCount > 0 ? args[0] : 1;
int32 col = argCount > 1 ? args[1] : 1;
if (row > 0)
row--;
if (col > 0)
col--;
GotoXY(col, row);
break;
}
case 'A': { /* move up */
int32 deltay = argCount > 0 ? -args[0] : -1;
if (deltay == 0)
deltay = -1;
GotoXY(fX, fY + deltay);
break;
}
case 'e':
case 'B': { /* move down */
int32 deltay = argCount > 0 ? args[0] : 1;
if (deltay == 0)
deltay = 1;
GotoXY(fX, fY + deltay);
break;
}
case 'D': { /* move left */
int32 deltax = argCount > 0 ? -args[0] : -1;
if (deltax == 0)
deltax = -1;
GotoXY(fX + deltax, fY);
break;
}
case 'a':
case 'C': { /* move right */
int32 deltax = argCount > 0 ? args[0] : 1;
if (deltax == 0)
deltax = 1;
GotoXY(fX + deltax, fY);
break;
}
case '`':
case 'G': { /* set X position */
int32 newx = argCount > 0 ? args[0] : 1;
if (newx > 0)
newx--;
GotoXY(newx, fY);
break;
}
case 'd': { /* set y position */
int32 newy = argCount > 0 ? args[0] : 1;
if (newy > 0)
newy--;
GotoXY(fX, newy);
break;
}
case 's': /* save current cursor */
SaveCursor(false);
break;
case 'u': /* restore cursor */
RestoreCursor(false);
break;
case 'r': { /* set scroll region */
int32 low = argCount > 0 ? args[0] : 1;
int32 high = argCount > 1 ? args[1] : fLines;
if (low <= high)
SetScrollRegion(low - 1, high - 1);
break;
}
case 'L': { /* scroll virtual down at cursor */
int32 lines = argCount > 0 ? args[0] : 1;
while (lines > 0) {
ScrollDown();
lines--;
}
break;
}
case 'M': { /* scroll virtual up at cursor */
int32 lines = argCount > 0 ? args[0] : 1;
while (lines > 0) {
ScrollUp();
lines--;
}
break;
}
case 'K':
if (argCount == 0 || args[0] == 0) {
// erase to end of line
EraseLine(LINE_ERASE_RIGHT);
} else if (argCount > 0) {
if (args[0] == 1)
EraseLine(LINE_ERASE_LEFT);
else if (args[0] == 2)
EraseLine(LINE_ERASE_WHOLE);
}
break;
case 'J':
if (argCount == 0 || args[0] == 0) {
// erase to end of screen
EraseScreen(SCREEN_ERASE_DOWN);
} else if (argCount > 0) {
if (args[0] == 1)
EraseScreen(SCREEN_ERASE_UP);
else if (args[0] == 2)
EraseScreen(SCREEN_ERASE_WHOLE);
}
break;
case 'm':
if (argCount >= 0)
SetVT100Attributes(args, argCount);
break;
default:
ret = false;
}
} else {
switch (c) {
case 'c':
ResetConsole();
break;
case 'D':
RLineFeed();
break;
case 'M':
LineFeed();
break;
case '7':
SaveCursor(true);
break;
case '8':
RestoreCursor(true);
break;
default:
ret = false;
}
}
return ret;
}
void
Console::Write(const void *buf, size_t len)
{
UpdateCursor(-1, -1); // hide the cursor
const char *c;
size_t pos = 0;
while (pos < len) {
c = &((const char *)buf)[pos++];
switch (fState) {
case CONSOLE_STATE_NORMAL:
// just output the stuff
switch (*c) {
case '\n':
LineFeed();
break;
case '\r':
CariageReturn();
break;
case 0x8: // backspace
Delete();
break;
case '\t':
Tab();
break;
case '\a':
// beep
printf("<BEEP>\n");
break;
case '\0':
break;
case 0x1b:
// escape character
fArgCount = -1;
fState = CONSOLE_STATE_GOT_ESCAPE;
break;
default:
PutChar(*c);
}
break;
case CONSOLE_STATE_GOT_ESCAPE:
// look for either commands with no argument, or the '[' character
switch (*c) {
case '[':
fState = CONSOLE_STATE_SEEN_BRACKET;
break;
default:
fArgs[fArgCount] = 0;
ProcessVT100Command(*c, false, fArgs, fArgCount + 1);
fState = CONSOLE_STATE_NORMAL;
}
break;
case CONSOLE_STATE_SEEN_BRACKET:
switch (*c) {
case '0'...'9':
fArgCount = 0;
fArgs[fArgCount] = *c - '0';
fState = CONSOLE_STATE_PARSING_ARG;
break;
case '?':
// private DEC mode parameter follows - we ignore those anyway
// ToDo: check if it was really used in combination with a mode command
break;
default:
ProcessVT100Command(*c, true, fArgs, fArgCount + 1);
fState = CONSOLE_STATE_NORMAL;
}
break;
case CONSOLE_STATE_NEW_ARG:
switch (*c) {
case '0'...'9':
fArgCount++;
if (fArgCount == MAX_ARGS) {
fState = CONSOLE_STATE_NORMAL;
break;
}
fArgs[fArgCount] = *c - '0';
fState = CONSOLE_STATE_PARSING_ARG;
break;
default:
ProcessVT100Command(*c, true, fArgs, fArgCount + 1);
fState = CONSOLE_STATE_NORMAL;
}
break;
case CONSOLE_STATE_PARSING_ARG:
// parse args
switch (*c) {
case '0'...'9':
fArgs[fArgCount] *= 10;
fArgs[fArgCount] += *c - '0';
break;
case ';':
fState = CONSOLE_STATE_NEW_ARG;
break;
default:
ProcessVT100Command(*c, true, fArgs, fArgCount + 1);
fState = CONSOLE_STATE_NORMAL;
}
}
}
UpdateCursor(fX, fY); // show it again
}

View File

@ -0,0 +1,96 @@
#ifndef _CONSOLE_H_
#define _CONSOLE_H_
#include <SupportDefs.h>
#define TAB_SIZE 8
#define TAB_MASK 7
#define FMASK 0x0f
#define BMASK 0x70
typedef enum {
CONSOLE_STATE_NORMAL = 0,
CONSOLE_STATE_GOT_ESCAPE,
CONSOLE_STATE_SEEN_BRACKET,
CONSOLE_STATE_NEW_ARG,
CONSOLE_STATE_PARSING_ARG,
} console_state;
typedef enum {
SCREEN_ERASE_WHOLE,
SCREEN_ERASE_UP,
SCREEN_ERASE_DOWN
} erase_screen_mode;
typedef enum {
LINE_ERASE_WHOLE,
LINE_ERASE_LEFT,
LINE_ERASE_RIGHT
} erase_line_mode;
#define MAX_ARGS 8
class ViewBuffer;
class Console {
public:
Console(ViewBuffer *output);
~Console();
void ResetConsole();
void SetScrollRegion(int top, int bottom);
void ScrollUp();
void ScrollDown();
void LineFeed();
void RLineFeed();
void CariageReturn();
void Delete();
void Tab();
void EraseLine(erase_line_mode mode);
void EraseScreen(erase_screen_mode mode);
void SaveCursor(bool save_attrs);
void RestoreCursor(bool restore_attrs);
void UpdateCursor(int x, int y);
void GotoXY(int new_x, int new_y);
void PutChar(const char c);
void SetVT100Attributes(int32 *args, int32 argCount);
bool ProcessVT100Command(const char c, bool seen_bracket, int32 *args, int32 argCount);
void Write(const void *buf, size_t len);
private:
static void ResizeCallback(int32 width, int32 height, void *data);
int32 fLines;
int32 fColumns;
uint8 fAttr;
uint8 fSavedAttr;
bool fBrightAttr;
bool fReverseAttr;
int32 fX; // current x coordinate
int32 fY; // current y coordinate
int32 fSavedX; // used to save x and y
int32 fSavedY;
int32 fScrollTop; // top of the scroll region
int32 fScrollBottom; // bottom of the scroll region
/* state machine */
console_state fState;
int32 fArgCount;
int32 fArgs[MAX_ARGS];
ViewBuffer *fOutput;
};
#endif

View File

@ -0,0 +1,13 @@
SubDir OBOS_TOP src tests apps miniterminal ;
UseHeaders [ FDirName $(OBOS_TOP) src tests apps miniterminal ] ;
UseHeaders [ FDirName $(OBOS_TOP) src apps terminal MYOB ] ;
App MiniTerminal :
MiniApp.cpp
MiniWin.cpp
MiniView.cpp
Console.cpp
ViewBuffer.cpp ;
LinkSharedOSLibs MiniTerminal : libbe.so ;

View File

@ -0,0 +1,39 @@
/*
* Part of the MiniTerminal.
*
* Copyright 2005 Michael Lotz. All rights reserved.
* Distributed under the Haiku License.
*/
#include "MiniApp.h"
#include "MiniWin.h"
#include "MiniView.h"
MiniApp::MiniApp()
: BApplication("application/x-vnd.Haiku.MiniTerminal")
{
fWindow = new MiniWin(BRect(50, 50, 630, 435));
fWindow->Show();
}
void
MiniApp::ReadyToRun()
{
fWindow->View()->Start();
}
MiniApp::~MiniApp()
{
}
int
main(void)
{
MiniApp *app = new MiniApp();
app->Run();
delete app;
return 0;
}

View File

@ -0,0 +1,19 @@
#ifndef _MINI_APP_H_
#define _MINI_APP_H_
#include <Application.h>
class MiniWin;
class MiniApp : public BApplication {
public:
MiniApp();
virtual ~MiniApp();
virtual void ReadyToRun();
private:
MiniWin *fWindow;
};
#endif

View File

@ -0,0 +1,306 @@
/*
* MiniTerminal - A basic windowed terminal to allow
* command-line interaction from within app_server.
* Based on consoled and MuTerminal.
*
* Copyright 2005 Michael Lotz. All rights reserved.
* Distributed under the Haiku License.
*
* Copyright 2004-2005, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Copyright 2002, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
#include <OS.h>
#include <image.h>
#include <termios.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "MiniView.h"
#include "Console.h"
#include "VTkeymap.h"
//#define TRACE_MINI_TERMINAL
#ifdef TRACE_MINI_TERMINAL
#ifdef __HAIKU__
#define TRACE(x) debug_printf x
#else
#define TRACE(x) printf x
#endif
#else
#define TRACE(x)
#endif
void
Setenv(const char *var, const char *value)
{
int envindex = 0;
const int len = strlen(var);
const int val_len = strlen (value);
while (environ [envindex] != NULL) {
if (strncmp (environ [envindex], var, len) == 0) {
/* found it */
environ[envindex] = (char *)malloc ((unsigned)len + val_len + 1);
sprintf (environ [envindex], "%s%s", var, value);
return;
}
envindex ++;
}
environ [envindex] = (char *) malloc ((unsigned)len + val_len + 1);
sprintf (environ [envindex], "%s%s", var, value);
environ [++envindex] = NULL;
}
static int32
ConsoleWriter(void *arg)
{
char buf[1024];
ssize_t len;
MiniView *view = (MiniView *)arg;
for (;;) {
len = read(view->fMasterFD, buf, sizeof(buf));
if (len < 0)
break;
view->fConsole->Write(buf, len);
}
return 0;
}
static int32
ExecuteShell(void *arg)
{
MiniView *view = (MiniView *)arg;
for (;;) {
const char *argv[3];
argv[0] = "/bin/sh";
argv[1] = "--login";
argv[2] = NULL;
int saved_stdin = dup(0);
int saved_stdout = dup(1);
int saved_stderr = dup(2);
dup2(view->fSlaveFD, 0);
dup2(view->fSlaveFD, 1);
dup2(view->fSlaveFD, 2);
thread_id shell = load_image(2, argv, (const char **)environ);
setpgid(shell, 0);
status_t return_code;
wait_for_thread(shell, &return_code);
dup2(saved_stdin, 0);
dup2(saved_stdout, 1);
dup2(saved_stderr, 2);
close(saved_stdin);
close(saved_stdout);
close(saved_stderr);
}
return B_OK;
}
MiniView::MiniView(BRect frame)
: ViewBuffer(frame)
{
}
MiniView::~MiniView()
{
}
void
MiniView::Start()
{
fConsole = new Console(this);
if (OpenTTY() != B_OK) {
TRACE(("error in OpenTTY\n"));
return;
}
// we're a session leader
setsid();
// move our stdin and stdout to the console
dup2(fSlaveFD, 0);
dup2(fSlaveFD, 1);
dup2(fSlaveFD, 2);
if (SpawnThreads() != B_OK)
TRACE(("error in SpawnThreads\n"));
}
status_t
MiniView::OpenTTY()
{
DIR *dir;
dir = opendir("/dev/pt");
if (dir != NULL) {
struct dirent *entry;
char name[64];
while ((entry = readdir(dir)) != NULL) {
if (entry->d_name[0] == '.') // filter out . and ..
continue;
sprintf(name, "/dev/pt/%s", entry->d_name);
fMasterFD = open(name, O_RDWR);
if (fMasterFD >= 0) {
sprintf(name, "/dev/tt/%s", entry->d_name);
fSlaveFD = open(name, O_RDWR);
if (fSlaveFD < 0) {
TRACE(("cannot open tty\n"));
close(fMasterFD);
} else {
struct termios tio;
tcgetattr(fSlaveFD, &tio);
// set signal default
signal(SIGCHLD, SIG_DFL);
signal(SIGHUP, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGTTOU, SIG_DFL);
// set terminal interface
tio.c_line = 0;
tio.c_lflag |= ECHOE;
// input: nl->nl, cr->nl
tio.c_iflag &= ~(INLCR|IGNCR);
tio.c_iflag |= ICRNL;
tio.c_iflag &= ~ISTRIP;
// output: cr->cr, nl in not retrun, no delays, ln->cr/ln
tio.c_oflag &= ~(OCRNL|ONLRET|NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
tio.c_oflag |= ONLCR;
tio.c_oflag |= OPOST;
// baud rate is 19200 (equal to beterm)
tio.c_cflag &= ~(CBAUD);
tio.c_cflag |= B19200;
tio.c_cflag &= ~CSIZE;
tio.c_cflag |= CS8;
tio.c_cflag |= CREAD;
tio.c_cflag |= HUPCL;
tio.c_iflag &= ~(IGNBRK|BRKINT);
// enable signals, canonical processing (erase, kill, etc), echo
tio.c_lflag |= ISIG|ICANON|ECHO|ECHOE|ECHONL;
tio.c_lflag &= ~ECHOK;
tio.c_lflag &= ~IEXTEN;
// set control charactors
tio.c_cc[VINTR] = 'C' & 0x1f; /* '^C' */
tio.c_cc[VQUIT] = '\\'& 0x1f; /* '^\' */
tio.c_cc[VERASE] = 0x08; /* '^H' */
tio.c_cc[VKILL] = 'U' & 0x1f; /* '^U' */
tio.c_cc[VEOF] = 'D' & 0x1f; /* '^D' */
tio.c_cc[VEOL] = 0; /* '^@' */
tio.c_cc[VMIN] = 4;
tio.c_cc[VTIME] = 0;
tio.c_cc[VEOL2] = 0; /* '^@' */
tio.c_cc[VSWTCH] = 0; /* '^@' */
tio.c_cc[VSTART] = 'S' & 0x1f; /* '^S' */
tio.c_cc[VSTOP] = 'Q' & 0x1f; /* '^Q' */
tio.c_cc[VSUSP] = '@' & 0x1f; /* '^@' */
// set terminal interface
tcsetattr(fSlaveFD, TCSANOW, &tio);
// set window size (currently disabled)
/*ws.ws_row = rows;
ws.ws_col = cols;
ioctl(con->tty_slave_fd, TIOCSWINSZ, &ws);*/
}
break;
}
}
Setenv("TTY", name);
}
if (fMasterFD < 0 || fSlaveFD < 0) {
TRACE(("could not open master or slave fd\n"));
return B_ERROR;
}
Setenv("TERM", "beterm");
return B_OK;
}
void
MiniView::KeyDown(const char *bytes, int32 numBytes)
{
// TODO: add interrupt char handling
uint32 mod = modifiers();
if (numBytes == 1) {
if (mod & B_OPTION_KEY) {
char c = bytes[0] | 0x80;
write(fMasterFD, &c, 1);
} else {
switch (bytes[0]) {
case B_LEFT_ARROW:
write(fMasterFD, LEFT_ARROW_KEY_CODE, sizeof(LEFT_ARROW_KEY_CODE));
break;
case B_RIGHT_ARROW:
write(fMasterFD, RIGHT_ARROW_KEY_CODE, sizeof(RIGHT_ARROW_KEY_CODE));
break;
case B_UP_ARROW:
write(fMasterFD, UP_ARROW_KEY_CODE, sizeof(UP_ARROW_KEY_CODE));
break;
case B_DOWN_ARROW:
write(fMasterFD, DOWN_ARROW_KEY_CODE, sizeof(DOWN_ARROW_KEY_CODE));
break;
default:
write(fMasterFD, bytes, numBytes);
}
}
} else
write(fMasterFD, bytes, numBytes);
}
status_t
MiniView::SpawnThreads()
{
fConsoleWriter = spawn_thread(&ConsoleWriter, "console writer", B_URGENT_DISPLAY_PRIORITY, this);
if (fConsoleWriter < 0)
return B_ERROR;
TRACE(("console writer thread is: %d\n", fConsoleWriter));
fShellProcess = spawn_thread(&ExecuteShell, "shell process", B_URGENT_DISPLAY_PRIORITY, this);
if (fShellProcess < 0)
return B_ERROR;
TRACE(("shell process thread is: %d\n", fShellProcess));
resume_thread(fConsoleWriter);
resume_thread(fShellProcess);
return B_OK;
}

View File

@ -0,0 +1,24 @@
#ifndef _MINI_TERMINAL_H_
#define _MINI_TERMINAL_H_
#include "ViewBuffer.h"
#include "Console.h"
class MiniView : public ViewBuffer {
public:
MiniView(BRect frame);
virtual ~MiniView();
void Start();
status_t OpenTTY();
status_t SpawnThreads();
virtual void KeyDown(const char *bytes, int32 numBytes);
Console *fConsole;
int fMasterFD;
int fSlaveFD;
thread_id fShellProcess;
thread_id fConsoleWriter;
};
#endif

View File

@ -0,0 +1,29 @@
/*
* Part of the MiniTerminal.
*
* Copyright 2005 Michael Lotz. All rights reserved.
* Distributed under the Haiku License.
*/
#include "MiniWin.h"
#include "MiniView.h"
MiniWin::MiniWin(BRect bounds)
: BWindow(bounds, "MiniTerminal", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE)
{
fView = new MiniView(bounds.OffsetToSelf(0, 0));
AddChild(fView);
fView->MakeFocus();
}
MiniWin::~MiniWin()
{
}
MiniView *
MiniWin::View()
{
return fView;
}

View File

@ -0,0 +1,19 @@
#ifndef _MINI_WIN_H_
#define _MINI_WIN_H_
#include <Window.h>
class MiniView;
class MiniWin : public BWindow {
public:
MiniWin(BRect bounds);
virtual ~MiniWin();
MiniView *View();
private:
MiniView *fView;
};
#endif

View File

@ -0,0 +1,232 @@
/*
* ViewBuffer - Mimicing a frame buffer output - but using a BView.
* Based on frame_buffer_console.
*
* Copyright 2005 Michael Lotz. All rights reserved.
* Distributed under the Haiku License.
*
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "ViewBuffer.h"
#define CHAR_WIDTH 7
#define CHAR_HEIGHT 12
// Palette is (black and white are swapt like in normal BeOS Terminal)
// 0 - black,
// 1 - blue,
// 2 - green,
// 3 - cyan,
// 4 - red,
// 5 - magenta,
// 6 - yellow,
// 7 - white
// 8-15 - same but bright (we're ignoring those)
static uint32 sPalette32[] = {
0xffffff,
0x0000ff,
0x00ff00,
0x00ffff,
0xff0000,
0xff00ff,
0xffff00,
0x000000,
};
ViewBuffer::ViewBuffer(BRect frame)
: BView(frame, "ViewBuffer", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS)
{
SetFont(be_fixed_font);
fColumns = frame.IntegerWidth() / CHAR_WIDTH;
fRows = frame.IntegerHeight() / CHAR_HEIGHT;
fResizeCallback = NULL;
// initially, the cursor is hidden
fCursorX = -1;
fCursorY = -1;
// initialize private palette
for (int i = 0; i < 8; i++) {
fPalette[i].red = (sPalette32[i] >> 16) & 0xff;
fPalette[i].green = (sPalette32[i] >> 8) & 0xff;
fPalette[i].blue = (sPalette32[i] >> 0) & 0xff;
fPalette[i].alpha = 0xff;
}
}
ViewBuffer::~ViewBuffer()
{
}
void
ViewBuffer::FrameResized(float width, float height)
{
fColumns = (int32)width / CHAR_WIDTH;
fRows = (int32)height / CHAR_HEIGHT;
if (fResizeCallback)
fResizeCallback(fColumns, fRows, fResizeCallbackData);
}
status_t
ViewBuffer::GetSize(int32 *width, int32 *height)
{
*width = fColumns;
*height = fRows;
return B_OK;
}
void
ViewBuffer::SetResizeCallback(resize_callback callback, void *data)
{
fResizeCallback = callback;
fResizeCallbackData = data;
}
uint8
ViewBuffer::ForegroundColor(uint8 attr)
{
return attr & 0x7;
}
uint8
ViewBuffer::BackgroundColor(uint8 attr)
{
return (attr >> 4) & 0x7;
}
rgb_color
ViewBuffer::GetPaletteEntry(uint8 index)
{
return fPalette[index];
}
void
ViewBuffer::PutGlyph(int32 x, int32 y, uint8 glyph, uint8 attr)
{
if (x >= fColumns || y >= fRows)
return;
RenderGlyph(x, y, glyph, attr);
}
void
ViewBuffer::FillGlyph(int32 x, int32 y, int32 width, int32 height, uint8 glyph, uint8 attr)
{
if (x >= fColumns || y >= fRows)
return;
int32 left = x + width;
if (left > fColumns)
left = fColumns;
int32 bottom = y + height;
if (bottom > fRows)
bottom = fRows;
for (; y < bottom; y++) {
for (int32 x2 = x; x2 < left; x2++) {
RenderGlyph(x2, y, glyph, attr);
}
}
}
void
ViewBuffer::RenderGlyph(int32 x, int32 y, uint8 glyph, uint8 attr)
{
BPoint where(x * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT - 3);
char string[2];
string[0] = glyph;
string[1] = 0;
if (LockLooper()) {
SetHighColor(GetPaletteEntry(ForegroundColor(attr)));
SetLowColor(GetPaletteEntry(BackgroundColor(attr)));
FillRect(BRect(x * CHAR_WIDTH, y * CHAR_HEIGHT, (x + 1) * CHAR_WIDTH, (y + 1) * CHAR_HEIGHT), B_SOLID_LOW);
DrawString(string, where);
Sync();
UnlockLooper();
}
}
void
ViewBuffer::DrawCursor(int32 x, int32 y)
{
if (x < 0 || y < 0)
return;
x *= CHAR_WIDTH;
y *= CHAR_HEIGHT;
if (LockLooper()) {
InvertRect(BRect(x, y, x + CHAR_WIDTH, y + CHAR_HEIGHT));
Sync();
UnlockLooper();
}
}
void
ViewBuffer::MoveCursor(int32 x, int32 y)
{
DrawCursor(fCursorX, fCursorY);
DrawCursor(x, y);
fCursorX = x;
fCursorY = y;
}
void
ViewBuffer::Blit(int32 srcx, int32 srcy, int32 width, int32 height, int32 destx, int32 desty)
{
height *= CHAR_HEIGHT;
width *= CHAR_WIDTH;
srcx *= CHAR_WIDTH;
srcy *= CHAR_HEIGHT;
BRect source(srcx, srcy, srcx + width, srcy + height);
destx *= CHAR_WIDTH;
desty *= CHAR_HEIGHT;
BRect dest(destx, desty, destx + width, desty + height);
if (LockLooper()) {
CopyBits(source, dest);
Sync();
UnlockLooper();
}
}
void
ViewBuffer::Clear(uint8 attr)
{
if (LockLooper()) {
SetLowColor(GetPaletteEntry(BackgroundColor(attr)));
SetViewColor(LowColor());
FillRect(Frame(), B_SOLID_LOW);
Sync();
UnlockLooper();
}
fCursorX = -1;
fCursorY = -1;
}

View File

@ -0,0 +1,43 @@
#ifndef _VIEW_BUFFER_H_
#define _VIEW_BUFFER_H_
#include <SupportDefs.h>
#include <View.h>
typedef void (*resize_callback)(int32 width, int32 height, void *data);
class ViewBuffer : public BView {
public:
ViewBuffer(BRect frame);
virtual ~ViewBuffer();
virtual void FrameResized(float new_width, float new_height);
void SetResizeCallback(resize_callback callback, void *data);
status_t GetSize(int32 *width, int32 *height);
uint8 ForegroundColor(uint8 attr);
uint8 BackgroundColor(uint8 attr);
rgb_color GetPaletteEntry(uint8 index);
void PutGlyph(int32 x, int32 y, uint8 glyph, uint8 attr);
void FillGlyph(int32 x, int32 y, int32 width, int32 height, uint8 glyph, uint8 attr);
void RenderGlyph(int32 x, int32 y, uint8 glyph, uint8 attr);
void DrawCursor(int32 x, int32 y);
void MoveCursor(int32 x, int32 y);
void Blit(int32 srcx, int32 srcy, int32 width, int32 height, int32 destx, int32 desty);
void Clear(uint8 attr);
private:
int32 fColumns;
int32 fRows;
resize_callback fResizeCallback;
void *fResizeCallbackData;
int32 fCursorX;
int32 fCursorY;
rgb_color fPalette[8];
};
#endif