diff --git a/src/tests/apps/miniterminal/Console.cpp b/src/tests/apps/miniterminal/Console.cpp new file mode 100644 index 0000000000..0336b47886 --- /dev/null +++ b/src/tests/apps/miniterminal/Console.cpp @@ -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 + +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("\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 +} diff --git a/src/tests/apps/miniterminal/Console.h b/src/tests/apps/miniterminal/Console.h new file mode 100644 index 0000000000..e12357c5d6 --- /dev/null +++ b/src/tests/apps/miniterminal/Console.h @@ -0,0 +1,96 @@ +#ifndef _CONSOLE_H_ +#define _CONSOLE_H_ + +#include + +#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 diff --git a/src/tests/apps/miniterminal/Jamfile b/src/tests/apps/miniterminal/Jamfile new file mode 100644 index 0000000000..20f0d0a5b8 --- /dev/null +++ b/src/tests/apps/miniterminal/Jamfile @@ -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 ; diff --git a/src/tests/apps/miniterminal/MiniApp.cpp b/src/tests/apps/miniterminal/MiniApp.cpp new file mode 100644 index 0000000000..0e665800cc --- /dev/null +++ b/src/tests/apps/miniterminal/MiniApp.cpp @@ -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; +} diff --git a/src/tests/apps/miniterminal/MiniApp.h b/src/tests/apps/miniterminal/MiniApp.h new file mode 100644 index 0000000000..58dbc92cdb --- /dev/null +++ b/src/tests/apps/miniterminal/MiniApp.h @@ -0,0 +1,19 @@ +#ifndef _MINI_APP_H_ +#define _MINI_APP_H_ + +#include + +class MiniWin; + +class MiniApp : public BApplication { +public: + MiniApp(); +virtual ~MiniApp(); + +virtual void ReadyToRun(); + +private: + MiniWin *fWindow; +}; + +#endif \ No newline at end of file diff --git a/src/tests/apps/miniterminal/MiniView.cpp b/src/tests/apps/miniterminal/MiniView.cpp new file mode 100644 index 0000000000..e8c15986cb --- /dev/null +++ b/src/tests/apps/miniterminal/MiniView.cpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/src/tests/apps/miniterminal/MiniView.h b/src/tests/apps/miniterminal/MiniView.h new file mode 100644 index 0000000000..6973a8c147 --- /dev/null +++ b/src/tests/apps/miniterminal/MiniView.h @@ -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 diff --git a/src/tests/apps/miniterminal/MiniWin.cpp b/src/tests/apps/miniterminal/MiniWin.cpp new file mode 100644 index 0000000000..c6595d1eff --- /dev/null +++ b/src/tests/apps/miniterminal/MiniWin.cpp @@ -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; +} diff --git a/src/tests/apps/miniterminal/MiniWin.h b/src/tests/apps/miniterminal/MiniWin.h new file mode 100644 index 0000000000..0718bab74d --- /dev/null +++ b/src/tests/apps/miniterminal/MiniWin.h @@ -0,0 +1,19 @@ +#ifndef _MINI_WIN_H_ +#define _MINI_WIN_H_ + +#include + +class MiniView; + +class MiniWin : public BWindow { +public: + MiniWin(BRect bounds); +virtual ~MiniWin(); + + MiniView *View(); + +private: + MiniView *fView; +}; + +#endif diff --git a/src/tests/apps/miniterminal/ViewBuffer.cpp b/src/tests/apps/miniterminal/ViewBuffer.cpp new file mode 100644 index 0000000000..94d1d0a8b1 --- /dev/null +++ b/src/tests/apps/miniterminal/ViewBuffer.cpp @@ -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; +} diff --git a/src/tests/apps/miniterminal/ViewBuffer.h b/src/tests/apps/miniterminal/ViewBuffer.h new file mode 100644 index 0000000000..942f6bc279 --- /dev/null +++ b/src/tests/apps/miniterminal/ViewBuffer.h @@ -0,0 +1,43 @@ +#ifndef _VIEW_BUFFER_H_ +#define _VIEW_BUFFER_H_ + +#include +#include + +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