/*
|
/*
|
* Copyright (c) 1999 Greg Haerr <greg@censoft.com>
|
* Copyright (c) 1999 Greg Haerr <greg@censoft.com>
|
*
|
*
|
* Microwindows Terminal Emulator for Linux
|
* Microwindows Terminal Emulator for Linux
|
*
|
*
|
* Yes, this is just a demo, and doesn't repaint contents on refresh.
|
* Yes, this is just a demo, and doesn't repaint contents on refresh.
|
*/
|
*/
|
|
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <fcntl.h>
|
#include <fcntl.h>
|
#include <unistd.h>
|
#include <unistd.h>
|
#include <errno.h>
|
#include <errno.h>
|
#include <signal.h>
|
#include <signal.h>
|
#define MWINCLUDECOLORS
|
#define MWINCLUDECOLORS
|
#include "windows.h"
|
#include "windows.h"
|
#include "wintern.h" /* for MwRegisterFdInput*/
|
#include "wintern.h" /* for MwRegisterFdInput*/
|
#include "wintools.h" /* Draw3dInset*/
|
#include "wintools.h" /* Draw3dInset*/
|
|
|
#define COLS 80
|
#define COLS 80
|
#define ROWS 24
|
#define ROWS 24
|
#define XMARGIN 2
|
#define XMARGIN 2
|
#define YMARGIN 2
|
#define YMARGIN 2
|
#define FGCOLOR GREEN
|
#define FGCOLOR GREEN
|
#define BKCOLOR BLACK
|
#define BKCOLOR BLACK
|
#define FONTNAME SYSTEM_FIXED_FONT
|
#define FONTNAME SYSTEM_FIXED_FONT
|
/*#define FONTNAME OEM_FIXED_FONT*/
|
/*#define FONTNAME OEM_FIXED_FONT*/
|
#define APPCLASS "mterm"
|
#define APPCLASS "mterm"
|
|
|
#if DOS_DJGPP
|
#if DOS_DJGPP
|
#define killpg kill
|
#define killpg kill
|
#define SIGCHLD 17 /* from Linux, not defined in DJGPP */
|
#define SIGCHLD 17 /* from Linux, not defined in DJGPP */
|
#endif
|
#endif
|
|
|
/* forward decls*/
|
/* forward decls*/
|
LRESULT CALLBACK WndProc(HWND hwnd,UINT uMsg,WPARAM wp,LPARAM lp);
|
LRESULT CALLBACK WndProc(HWND hwnd,UINT uMsg,WPARAM wp,LPARAM lp);
|
void EmOutChar(HWND hwnd, int ch);
|
void EmOutChar(HWND hwnd, int ch);
|
int CreatePtyShell(void);
|
int CreatePtyShell(void);
|
int ReadPtyShell(int fd, char *buf, int count);
|
int ReadPtyShell(int fd, char *buf, int count);
|
int WritePtyShell(int fd, char *buf, int count);
|
int WritePtyShell(int fd, char *buf, int count);
|
void ClosePtyShell(int fd);
|
void ClosePtyShell(int fd);
|
|
|
/* local data*/
|
/* local data*/
|
static int ttyfd = -1;
|
static int ttyfd = -1;
|
static int xpos = XMARGIN;
|
static int xpos = XMARGIN;
|
static int ypos = YMARGIN;
|
static int ypos = YMARGIN;
|
static int nCharWidth, nCharHeight;
|
static int nCharWidth, nCharHeight;
|
static int nScreenWidth, nScreenHeight;
|
static int nScreenWidth, nScreenHeight;
|
|
|
int
|
int
|
RegisterAppClass(void)
|
RegisterAppClass(void)
|
{
|
{
|
WNDCLASS wc;
|
WNDCLASS wc;
|
|
|
wc.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW;
|
wc.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW;
|
wc.lpfnWndProc = (WNDPROC)WndProc;
|
wc.lpfnWndProc = (WNDPROC)WndProc;
|
wc.cbClsExtra = 0;
|
wc.cbClsExtra = 0;
|
wc.cbWndExtra = 0;
|
wc.cbWndExtra = 0;
|
wc.hInstance = 0;
|
wc.hInstance = 0;
|
wc.hIcon = 0; /*LoadIcon(GetHInstance(), MAKEINTRESOURCE( 1));*/
|
wc.hIcon = 0; /*LoadIcon(GetHInstance(), MAKEINTRESOURCE( 1));*/
|
wc.hCursor = 0; /*LoadCursor(NULL, IDC_ARROW);*/
|
wc.hCursor = 0; /*LoadCursor(NULL, IDC_ARROW);*/
|
wc.hbrBackground = CreateSolidBrush(BKCOLOR);
|
wc.hbrBackground = CreateSolidBrush(BKCOLOR);
|
wc.lpszMenuName = NULL;
|
wc.lpszMenuName = NULL;
|
wc.lpszClassName = APPCLASS;
|
wc.lpszClassName = APPCLASS;
|
RegisterClass( &wc);
|
RegisterClass( &wc);
|
return 1;
|
return 1;
|
}
|
}
|
|
|
HWND
|
HWND
|
CreateAppWindow(void)
|
CreateAppWindow(void)
|
{
|
{
|
HWND hwnd;
|
HWND hwnd;
|
HDC hdc;
|
HDC hdc;
|
int w, h;
|
int w, h;
|
RECT rc;
|
RECT rc;
|
|
|
GetWindowRect(GetDesktopWindow(), &rc);
|
GetWindowRect(GetDesktopWindow(), &rc);
|
w = rc.right - 40;
|
w = rc.right - 40;
|
h = rc.bottom;
|
h = rc.bottom;
|
|
|
/* determine TE size from font*/
|
/* determine TE size from font*/
|
hdc = GetDC(NULL);
|
hdc = GetDC(NULL);
|
SelectObject(hdc, GetStockObject(FONTNAME));
|
SelectObject(hdc, GetStockObject(FONTNAME));
|
SetRect(&rc, 0, 0, 0, 0);
|
SetRect(&rc, 0, 0, 0, 0);
|
nCharHeight = DrawText(hdc, "m", 1, &rc, DT_CALCRECT);
|
nCharHeight = DrawText(hdc, "m", 1, &rc, DT_CALCRECT);
|
nCharWidth = rc.right;
|
nCharWidth = rc.right;
|
nScreenWidth = min(w, nCharWidth*COLS);
|
nScreenWidth = min(w, nCharWidth*COLS);
|
nScreenHeight = min(h, nCharHeight*ROWS);
|
nScreenHeight = min(h, nCharHeight*ROWS);
|
ReleaseDC(NULL, hdc);
|
ReleaseDC(NULL, hdc);
|
|
|
hwnd = CreateWindowEx(0L, APPCLASS,
|
hwnd = CreateWindowEx(0L, APPCLASS,
|
"Microwindows Terminal",
|
"Microwindows Terminal",
|
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
nScreenWidth+4, nScreenHeight+24,
|
nScreenWidth+4, nScreenHeight+24,
|
NULL, (HMENU)1, NULL, NULL);
|
NULL, (HMENU)1, NULL, NULL);
|
|
|
return hwnd;
|
return hwnd;
|
}
|
}
|
|
|
LRESULT CALLBACK
|
LRESULT CALLBACK
|
WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
{
|
{
|
unsigned char ch;
|
unsigned char ch;
|
HDC hdc;
|
HDC hdc;
|
RECT rc;
|
RECT rc;
|
PAINTSTRUCT ps;
|
PAINTSTRUCT ps;
|
|
|
switch(msg) {
|
switch(msg) {
|
case WM_CREATE:
|
case WM_CREATE:
|
ttyfd = CreatePtyShell();
|
ttyfd = CreatePtyShell();
|
/*if(ttyfd == -1)
|
/*if(ttyfd == -1)
|
return -1;*/
|
return -1;*/
|
MwRegisterFdInput(hwnd, ttyfd);
|
MwRegisterFdInput(hwnd, ttyfd);
|
xpos = XMARGIN;
|
xpos = XMARGIN;
|
ypos = YMARGIN;
|
ypos = YMARGIN;
|
break;
|
break;
|
|
|
case WM_DESTROY:
|
case WM_DESTROY:
|
MwUnregisterFdInput(hwnd, ttyfd);
|
MwUnregisterFdInput(hwnd, ttyfd);
|
ClosePtyShell(ttyfd);
|
ClosePtyShell(ttyfd);
|
break;
|
break;
|
|
|
case WM_CHAR:
|
case WM_CHAR:
|
ch = (char)wp;
|
ch = (char)wp;
|
/* echo half duplex if CreatePtyShell() failed*/
|
/* echo half duplex if CreatePtyShell() failed*/
|
if(ttyfd == -1) {
|
if(ttyfd == -1) {
|
EmOutChar(hwnd, ch);
|
EmOutChar(hwnd, ch);
|
if(ch == '\r')
|
if(ch == '\r')
|
EmOutChar(hwnd, '\n');
|
EmOutChar(hwnd, '\n');
|
} else
|
} else
|
WritePtyShell(ttyfd, &ch, 1);
|
WritePtyShell(ttyfd, &ch, 1);
|
break;
|
break;
|
|
|
case WM_FDINPUT:
|
case WM_FDINPUT:
|
if(ReadPtyShell(ttyfd, &ch, 1) == 1)
|
if(ReadPtyShell(ttyfd, &ch, 1) == 1)
|
EmOutChar(hwnd, ch);
|
EmOutChar(hwnd, ch);
|
break;
|
break;
|
|
|
case WM_PAINT:
|
case WM_PAINT:
|
hdc = BeginPaint(hwnd, &ps);
|
hdc = BeginPaint(hwnd, &ps);
|
GetClientRect(hwnd, &rc);
|
GetClientRect(hwnd, &rc);
|
Draw3dInset(hdc, 0, 0, rc.right-rc.left, rc.bottom-rc.top);
|
Draw3dInset(hdc, 0, 0, rc.right-rc.left, rc.bottom-rc.top);
|
EndPaint(hwnd, &ps);
|
EndPaint(hwnd, &ps);
|
break;
|
break;
|
|
|
default:
|
default:
|
return DefWindowProc(hwnd, msg, wp, lp);
|
return DefWindowProc(hwnd, msg, wp, lp);
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
int WINAPI
|
int WINAPI
|
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
|
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
|
int nShowCmd)
|
int nShowCmd)
|
{
|
{
|
MSG msg;
|
MSG msg;
|
extern MWIMAGEHDR image_car8;
|
extern MWIMAGEHDR image_car8;
|
|
|
RegisterAppClass();
|
RegisterAppClass();
|
MwSetDesktopWallpaper(&image_car8);
|
MwSetDesktopWallpaper(&image_car8);
|
|
|
CreateAppWindow();
|
CreateAppWindow();
|
|
|
/* type ESC to quit...*/
|
/* type ESC to quit...*/
|
while(GetMessage(&msg, NULL, 0, 0)) {
|
while(GetMessage(&msg, NULL, 0, 0)) {
|
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
void
|
void
|
EmOutChar(HWND hwnd, int ch)
|
EmOutChar(HWND hwnd, int ch)
|
{
|
{
|
HDC hdc;
|
HDC hdc;
|
RECT rc;
|
RECT rc;
|
|
|
switch(ch) {
|
switch(ch) {
|
case '\r':
|
case '\r':
|
xpos = XMARGIN;
|
xpos = XMARGIN;
|
return;
|
return;
|
case '\n':
|
case '\n':
|
ypos += nCharHeight;
|
ypos += nCharHeight;
|
GetClientRect(hwnd, &rc);
|
GetClientRect(hwnd, &rc);
|
if(ypos > (ROWS-1)*nCharHeight + YMARGIN) {
|
if(ypos > (ROWS-1)*nCharHeight + YMARGIN) {
|
ypos -= nCharHeight;
|
ypos -= nCharHeight;
|
|
|
/* scroll window using bitblt ;-)*/
|
/* scroll window using bitblt ;-)*/
|
hdc = GetDC(hwnd);
|
hdc = GetDC(hwnd);
|
BitBlt(hdc, XMARGIN, YMARGIN, rc.right-XMARGIN*2,
|
BitBlt(hdc, XMARGIN, YMARGIN, rc.right-XMARGIN*2,
|
rc.bottom-nCharHeight-YMARGIN*2,
|
rc.bottom-nCharHeight-YMARGIN*2,
|
hdc, XMARGIN, nCharHeight+YMARGIN, SRCCOPY);
|
hdc, XMARGIN, nCharHeight+YMARGIN, SRCCOPY);
|
rc.top = ypos;
|
rc.top = ypos;
|
rc.left += XMARGIN;
|
rc.left += XMARGIN;
|
rc.right -= XMARGIN;
|
rc.right -= XMARGIN;
|
rc.bottom -= YMARGIN;
|
rc.bottom -= YMARGIN;
|
FillRect(hdc, &rc,
|
FillRect(hdc, &rc,
|
(HBRUSH)GetClassLong(hwnd, GCL_HBRBACKGROUND));
|
(HBRUSH)GetClassLong(hwnd, GCL_HBRBACKGROUND));
|
ReleaseDC(hwnd, hdc);
|
ReleaseDC(hwnd, hdc);
|
}
|
}
|
return;
|
return;
|
case '\007': /* bel*/
|
case '\007': /* bel*/
|
write(STDERR_FILENO, "\007", 1);
|
write(STDERR_FILENO, "\007", 1);
|
return;
|
return;
|
case '\t':
|
case '\t':
|
xpos += nCharWidth;
|
xpos += nCharWidth;
|
while((xpos/nCharWidth) & 7)
|
while((xpos/nCharWidth) & 7)
|
EmOutChar(hwnd, ' ');
|
EmOutChar(hwnd, ' ');
|
return;
|
return;
|
case '\b':
|
case '\b':
|
if(xpos <= XMARGIN)
|
if(xpos <= XMARGIN)
|
return;
|
return;
|
xpos -= nCharWidth;
|
xpos -= nCharWidth;
|
EmOutChar(hwnd, ' ');
|
EmOutChar(hwnd, ' ');
|
xpos -= nCharWidth;
|
xpos -= nCharWidth;
|
return;
|
return;
|
}
|
}
|
|
|
/* draw some text*/
|
/* draw some text*/
|
hdc = GetDC(hwnd);
|
hdc = GetDC(hwnd);
|
SelectObject(hdc, GetStockObject(FONTNAME));
|
SelectObject(hdc, GetStockObject(FONTNAME));
|
SetBkColor(hdc, BKCOLOR);
|
SetBkColor(hdc, BKCOLOR);
|
SetTextColor(hdc, FGCOLOR);
|
SetTextColor(hdc, FGCOLOR);
|
SetRect(&rc, xpos, ypos, xpos+nCharWidth, ypos+nCharHeight);
|
SetRect(&rc, xpos, ypos, xpos+nCharWidth, ypos+nCharHeight);
|
ExtTextOut(hdc, xpos, ypos, ETO_OPAQUE, &rc, (char *)&ch, 1, NULL);
|
ExtTextOut(hdc, xpos, ypos, ETO_OPAQUE, &rc, (char *)&ch, 1, NULL);
|
ReleaseDC(hwnd, hdc);
|
ReleaseDC(hwnd, hdc);
|
xpos += nCharWidth;
|
xpos += nCharWidth;
|
if(xpos > (COLS-1)*nCharWidth) {
|
if(xpos > (COLS-1)*nCharWidth) {
|
xpos = XMARGIN;
|
xpos = XMARGIN;
|
EmOutChar(hwnd, '\n');
|
EmOutChar(hwnd, '\n');
|
}
|
}
|
}
|
}
|
|
|
#if ELKS
|
#if ELKS
|
#define SHELL "/bin/sash"
|
#define SHELL "/bin/sash"
|
#else
|
#else
|
#if DOS_DJGPP
|
#if DOS_DJGPP
|
#define SHELL "bash"
|
#define SHELL "bash"
|
#else
|
#else
|
#define SHELL "/bin/sh"
|
#define SHELL "/bin/sh"
|
#endif
|
#endif
|
#endif
|
#endif
|
|
|
static int pid;
|
static int pid;
|
|
|
static void
|
static void
|
ptysignaled(int signo)
|
ptysignaled(int signo)
|
{
|
{
|
switch(signo) {
|
switch(signo) {
|
case SIGINT: /* interrupt*/
|
case SIGINT: /* interrupt*/
|
#if !ELKS
|
#if !ELKS
|
/* this doesn't work, can anyone fix it?*/
|
/* this doesn't work, can anyone fix it?*/
|
killpg(pid, SIGINT);
|
killpg(pid, SIGINT);
|
#endif
|
#endif
|
return;
|
return;
|
case SIGCHLD: /* child status change - child exit*/
|
case SIGCHLD: /* child status change - child exit*/
|
DestroyWindow(GetActiveWindow());
|
DestroyWindow(GetActiveWindow());
|
CreateAppWindow();
|
CreateAppWindow();
|
return;
|
return;
|
}
|
}
|
fprintf(stderr, "Uncaught signal %d\n", signo);
|
fprintf(stderr, "Uncaught signal %d\n", signo);
|
}
|
}
|
|
|
/*
|
/*
|
* Create a shell running through a pseudo tty, return the shell fd.
|
* Create a shell running through a pseudo tty, return the shell fd.
|
*/
|
*/
|
int
|
int
|
CreatePtyShell(void)
|
CreatePtyShell(void)
|
{
|
{
|
int n = 0;
|
int n = 0;
|
int tfd;
|
int tfd;
|
char pty_name[12];
|
char pty_name[12];
|
char * argv[2];
|
char * argv[2];
|
|
|
again:
|
again:
|
sprintf(pty_name, "/dev/ptyp%d", n);
|
sprintf(pty_name, "/dev/ptyp%d", n);
|
if ((tfd = open(pty_name, O_RDWR | O_NONBLOCK)) < 0) {
|
if ((tfd = open(pty_name, O_RDWR | O_NONBLOCK)) < 0) {
|
if ((errno == EBUSY || errno == EIO) && n < 10) {
|
if ((errno == EBUSY || errno == EIO) && n < 10) {
|
++n;
|
++n;
|
goto again;
|
goto again;
|
}
|
}
|
fprintf(stderr, "Can't create pty %s\n", pty_name);
|
fprintf(stderr, "Can't create pty %s\n", pty_name);
|
return -1;
|
return -1;
|
}
|
}
|
signal(SIGCHLD, ptysignaled);
|
signal(SIGCHLD, ptysignaled);
|
signal(SIGINT, ptysignaled);
|
signal(SIGINT, ptysignaled);
|
if ((pid = fork()) == -1) {
|
if ((pid = fork()) == -1) {
|
fprintf(stderr, "No processes\n");
|
fprintf(stderr, "No processes\n");
|
return -1;
|
return -1;
|
}
|
}
|
if (!pid) {
|
if (!pid) {
|
close(STDIN_FILENO);
|
close(STDIN_FILENO);
|
close(STDOUT_FILENO);
|
close(STDOUT_FILENO);
|
close(STDERR_FILENO);
|
close(STDERR_FILENO);
|
close(tfd);
|
close(tfd);
|
|
|
setsid();
|
setsid();
|
pty_name[5] = 't';
|
pty_name[5] = 't';
|
if ((tfd = open(pty_name, O_RDWR)) < 0) {
|
if ((tfd = open(pty_name, O_RDWR)) < 0) {
|
fprintf(stderr, "Child: Can't open pty %s\n", pty_name);
|
fprintf(stderr, "Child: Can't open pty %s\n", pty_name);
|
exit(1);
|
exit(1);
|
}
|
}
|
dup2(tfd, STDIN_FILENO);
|
dup2(tfd, STDIN_FILENO);
|
dup2(tfd, STDOUT_FILENO);
|
dup2(tfd, STDOUT_FILENO);
|
dup2(tfd, STDERR_FILENO);
|
dup2(tfd, STDERR_FILENO);
|
/*if(!(argv[0] = getenv("SHELL")))*/
|
/*if(!(argv[0] = getenv("SHELL")))*/
|
argv[0] = SHELL;
|
argv[0] = SHELL;
|
argv[1] = NULL;
|
argv[1] = NULL;
|
execv(argv[0], argv);
|
execv(argv[0], argv);
|
exit(1);
|
exit(1);
|
}
|
}
|
return tfd;
|
return tfd;
|
}
|
}
|
|
|
int
|
int
|
ReadPtyShell(int fd, char *buf, int count)
|
ReadPtyShell(int fd, char *buf, int count)
|
{
|
{
|
return read(fd, buf, count);
|
return read(fd, buf, count);
|
}
|
}
|
|
|
int
|
int
|
WritePtyShell(int fd, char *buf, int count)
|
WritePtyShell(int fd, char *buf, int count)
|
{
|
{
|
return write(fd, buf, count);
|
return write(fd, buf, count);
|
}
|
}
|
|
|
void
|
void
|
ClosePtyShell(int fd)
|
ClosePtyShell(int fd)
|
{
|
{
|
if(ttyfd != -1)
|
if(ttyfd != -1)
|
close(fd);
|
close(fd);
|
}
|
}
|
|
|