* Copyright 2001-2019, Haiku.
* Copyright (c) 2003-2004 Kian Duffy <myob@users.sourceforge.net>
* Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai.
*
* Distributed unter the terms of the MIT license.
*
* Authors:
* Jeremiah Bailey, <jjbailey@gmail.com>
* Kian Duffy, <myob@users.sourceforge.net>
* Simon South, simon@simonsouth.net
* Siarzhuk Zharski, <zharik@gmx.li>
*/
#include "TermApp.h"
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <Alert.h>
#include <Catalog.h>
#include <Clipboard.h>
#include <Catalog.h>
#include <InterfaceDefs.h>
#include <Locale.h>
#include <NodeInfo.h>
#include <Path.h>
#include <Roster.h>
#include <Screen.h>
#include <String.h>
#include "Arguments.h"
#include "Globals.h"
#include "PrefHandler.h"
#include "TermConst.h"
#include "TermWindow.h"
static bool sUsageRequested = false;
rgb_color TermApp::fDefaultPalette[kTermColorCount];
int
main()
{
TermApp app;
app.Run();
return 0;
}
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Terminal TermApp"
TermApp::TermApp()
:
BApplication(TERM_SIGNATURE),
fChildCleanupThread(-1),
fTerminating(false),
fTermWindow(NULL),
fArgs(NULL)
{
fArgs = new Arguments(0, NULL);
_InitDefaultPalette();
}
TermApp::~TermApp()
{
delete fArgs;
}
void
TermApp::ReadyToRun()
{
if (sUsageRequested)
return;
struct sigaction action;
action.sa_handler = (__sighandler_t)_SigChildHandler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
if (sigaction(SIGCHLD, &action, NULL) < 0) {
fprintf(stderr, "sigaction() failed: %s\n", strerror(errno));
}
sigset_t blockedSignals;
sigemptyset(&blockedSignals);
sigaddset(&blockedSignals, SIGCHLD);
sigaddset(&blockedSignals, SIGUSR1);
int error = pthread_sigmask(SIG_BLOCK, &blockedSignals, NULL);
if (error != 0)
fprintf(stderr, "pthread_sigmask() failed: %s\n", strerror(errno));
fChildCleanupThread = spawn_thread(_ChildCleanupThreadEntry,
"child cleanup", B_NORMAL_PRIORITY, this);
if (fChildCleanupThread >= 0) {
resume_thread(fChildCleanupThread);
} else {
fprintf(stderr, "Failed to start child cleanup thread: %s\n",
strerror(fChildCleanupThread));
}
gMouseClipboard = new BClipboard(MOUSE_CLIPBOARD_NAME, true);
status_t status = _MakeTermWindow();
if (status < B_OK) {
BAlert* alert = new BAlert("alert",
B_TRANSLATE("Terminal couldn't start the shell. Sorry."),
B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_FROM_LABEL,
B_INFO_ALERT);
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
PostMessage(B_QUIT_REQUESTED);
return;
}
if (fArgs->FullScreen())
BMessenger(fTermWindow).SendMessage(FULLSCREEN);
}
bool
TermApp::QuitRequested()
{
BMessage* message = CurrentMessage();
bool shutdown;
if (message != NULL && message->FindBool("_shutdown_", &shutdown) == B_OK
&& shutdown) {
if (fTermWindow->Lock())
fTermWindow->Quit();
}
return BApplication::QuitRequested();
}
void
TermApp::Quit()
{
fTerminating = true;
if (fChildCleanupThread >= 0) {
send_signal(fChildCleanupThread, SIGUSR1);
wait_for_thread(fChildCleanupThread, NULL);
}
BApplication::Quit();
}
void
TermApp::MessageReceived(BMessage* message)
{
switch (message->what) {
case B_KEY_MAP_LOADED:
fTermWindow->PostMessage(message);
break;
case MSG_ACTIVATE_TERM:
fTermWindow->Activate();
break;
default:
BApplication::MessageReceived(message);
break;
}
}
void
TermApp::ArgvReceived(int32 argc, char **argv)
{
fArgs->Parse(argc, argv);
if (fArgs->UsageRequested()) {
_Usage(argv[0]);
sUsageRequested = true;
PostMessage(B_QUIT_REQUESTED);
return;
}
}
void
TermApp::RefsReceived(BMessage* message)
{
if (!IsLaunching())
return;
entry_ref ref;
if (message->FindRef("refs", 0, &ref) != B_OK)
return;
BFile file;
if (file.SetTo(&ref, B_READ_WRITE) != B_OK)
return;
BNodeInfo info(&file);
char mimetype[B_MIME_TYPE_LENGTH];
info.GetType(mimetype);
if (strcmp(mimetype, PREFFILE_MIMETYPE) == 0) {
BEntry ent(&ref);
BPath path(&ent);
PrefHandler::Default()->OpenText(path.Path());
return;
}
if (strcmp(mimetype, "text/x-haiku-shscript") == 0) {
return;
}
}
status_t
TermApp::_MakeTermWindow()
{
try {
fTermWindow = new TermWindow(*fArgs);
} catch (int error) {
return (status_t)error;
} catch (...) {
return B_ERROR;
}
fTermWindow->Show();
return B_OK;
}
void
TermApp::_SigChildHandler(int signal, void* data)
{
fprintf(stderr, "Terminal: _SigChildHandler() called! That should never "
"happen!\n");
}
status_t
TermApp::_ChildCleanupThreadEntry(void* data)
{
return ((TermApp*)data)->_ChildCleanupThread();
}
status_t
TermApp::_ChildCleanupThread()
{
sigset_t waitForSignals;
sigemptyset(&waitForSignals);
sigaddset(&waitForSignals, SIGCHLD);
sigaddset(&waitForSignals, SIGUSR1);
for (;;) {
int signal;
int error = sigwait(&waitForSignals, &signal);
if (fTerminating)
break;
if (error == 0 && signal == SIGCHLD)
fTermWindow->PostMessage(MSG_CHECK_CHILDREN);
}
return B_OK;
}
void
TermApp::_Usage(char *name)
{
fprintf(stderr, B_TRANSLATE("Haiku Terminal\n"
"Copyright 2001-2019 Haiku, Inc.\n"
"Copyright(C) 1999 Kazuho Okui and Takashi Murai.\n"
"\n"
"Usage: %s [OPTION] [SHELL]\n"), name);
fputs(B_TRANSLATE(
" -h, --help print this help\n"
" -t, --title set window title\n"
" -f, --fullscreen start fullscreen\n"
" -w, --working-directory set initial working directory\n")
, stderr);
}
void
TermApp::_InitDefaultPalette()
{
const char * keys[kANSIColorCount] = {
PREF_ANSI_BLACK_COLOR,
PREF_ANSI_RED_COLOR,
PREF_ANSI_GREEN_COLOR,
PREF_ANSI_YELLOW_COLOR,
PREF_ANSI_BLUE_COLOR,
PREF_ANSI_MAGENTA_COLOR,
PREF_ANSI_CYAN_COLOR,
PREF_ANSI_WHITE_COLOR,
PREF_ANSI_BLACK_HCOLOR,
PREF_ANSI_RED_HCOLOR,
PREF_ANSI_GREEN_HCOLOR,
PREF_ANSI_YELLOW_HCOLOR,
PREF_ANSI_BLUE_HCOLOR,
PREF_ANSI_MAGENTA_HCOLOR,
PREF_ANSI_CYAN_HCOLOR,
PREF_ANSI_WHITE_HCOLOR
};
rgb_color* color = fDefaultPalette;
PrefHandler* handler = PrefHandler::Default();
for (uint i = 0; i < kANSIColorCount; i++)
*color++ = handler->getRGB(keys[i]);
for (uint red = 0; red < 256; red += (red == 0) ? 95 : 40)
for (uint green = 0; green < 256; green += (green == 0) ? 95 : 40)
for (uint blue = 0; blue < 256; blue += (blue == 0) ? 95 : 40)
(*color++).set_to(red, green, blue);
for (uint gray = 8; gray < 240; gray += 10)
(*color++).set_to(gray, gray, gray);
}