1/* 2 * Copyright 2001-2010, Haiku, Inc. All rights reserved. 3 * Copyright (c) 2003-2004 Kian Duffy <myob@users.sourceforge.net> 4 * Copyright (C) 1998,99 Kazuho Okui and Takashi Murai. 5 * 6 * Distributed unter the terms of the MIT license. 7 */ 8 9 10#include "TermApp.h" 11 12#include <errno.h> 13#include <signal.h> 14#include <stdio.h> 15#include <stdlib.h> 16#include <unistd.h> 17 18#include <Alert.h> 19#include <Catalog.h> 20#include <Clipboard.h> 21#include <Catalog.h> 22#include <InterfaceDefs.h> 23#include <Locale.h> 24#include <NodeInfo.h> 25#include <Path.h> 26#include <Roster.h> 27#include <Screen.h> 28#include <String.h> 29 30#include "Arguments.h" 31#include "Globals.h" 32#include "PrefHandler.h" 33#include "TermConst.h" 34#include "TermWindow.h" 35 36 37static bool sUsageRequested = false; 38//static bool sGeometryRequested = false; 39 40 41int 42main() 43{ 44 TermApp app; 45 app.Run(); 46 47 return 0; 48} 49 50#undef B_TRANSLATION_CONTEXT 51#define B_TRANSLATION_CONTEXT "Terminal TermApp" 52 53TermApp::TermApp() 54 : BApplication(TERM_SIGNATURE), 55 fStartFullscreen(false), 56 fTermWindow(NULL), 57 fArgs(NULL) 58{ 59 fArgs = new Arguments(0, NULL); 60} 61 62 63TermApp::~TermApp() 64{ 65 delete fArgs; 66} 67 68 69void 70TermApp::ReadyToRun() 71{ 72 // Prevent opeing window when option -h is given. 73 if (sUsageRequested) 74 return; 75 76 // Install a SIGCHLD signal handler, so that we will be notified, when 77 // a shell exits. 78 struct sigaction action; 79#ifdef __HAIKU__ 80 action.sa_handler = (__sighandler_t)_SigChildHandler; 81#else 82 action.sa_handler = (__signal_func_ptr)_SigChildHandler; 83#endif 84 sigemptyset(&action.sa_mask); 85#ifdef SA_NODEFER 86 action.sa_flags = SA_NODEFER; 87#endif 88 action.sa_userdata = this; 89 if (sigaction(SIGCHLD, &action, NULL) < 0) { 90 fprintf(stderr, "sigaction() failed: %s\n", 91 strerror(errno)); 92 // continue anyway 93 } 94 95 // init the mouse copy'n'paste clipboard 96 gMouseClipboard = new BClipboard(MOUSE_CLIPBOARD_NAME, true); 97 98 status_t status = _MakeTermWindow(); 99 100 // failed spawn, print stdout and open alert panel 101 // TODO: This alert does never show up. 102 if (status < B_OK) { 103 BAlert* alert = new BAlert("alert", 104 B_TRANSLATE("Terminal couldn't start the shell. Sorry."), 105 B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_FROM_LABEL, 106 B_INFO_ALERT); 107 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 108 alert->Go(NULL); 109 PostMessage(B_QUIT_REQUESTED); 110 return; 111 } 112 113 // using BScreen::Frame isn't enough 114 if (fStartFullscreen) 115 BMessenger(fTermWindow).SendMessage(FULLSCREEN); 116} 117 118 119bool 120TermApp::QuitRequested() 121{ 122 // check whether the system is shutting down 123 BMessage* message = CurrentMessage(); 124 bool shutdown; 125 if (message != NULL && message->FindBool("_shutdown_", &shutdown) == B_OK 126 && shutdown) { 127 // The system is shutting down. Quit the window synchronously. This 128 // skips the checks for running processes and the "Are you sure..." 129 // alert. 130 if (fTermWindow->Lock()) 131 fTermWindow->Quit(); 132 } 133 134 return BApplication::QuitRequested(); 135} 136 137 138void 139TermApp::Quit() 140{ 141 BApplication::Quit(); 142} 143 144 145void 146TermApp::MessageReceived(BMessage* message) 147{ 148 switch (message->what) { 149 case MSG_ACTIVATE_TERM: 150 fTermWindow->Activate(); 151 break; 152 153 case MSG_CHECK_CHILDREN: 154 _HandleChildCleanup(); 155 break; 156 157 default: 158 BApplication::MessageReceived(message); 159 break; 160 } 161} 162 163 164void 165TermApp::ArgvReceived(int32 argc, char **argv) 166{ 167 fArgs->Parse(argc, argv); 168 169 if (fArgs->UsageRequested()) { 170 _Usage(argv[0]); 171 sUsageRequested = true; 172 PostMessage(B_QUIT_REQUESTED); 173 return; 174 } 175 176 if (fArgs->Title() != NULL) 177 fWindowTitle = fArgs->Title(); 178 179 fStartFullscreen = fArgs->FullScreen(); 180} 181 182 183void 184TermApp::RefsReceived(BMessage* message) 185{ 186 // Works Only Launced by Double-Click file, or Drags file to App. 187 if (!IsLaunching()) 188 return; 189 190 entry_ref ref; 191 if (message->FindRef("refs", 0, &ref) != B_OK) 192 return; 193 194 BFile file; 195 if (file.SetTo(&ref, B_READ_WRITE) != B_OK) 196 return; 197 198 BNodeInfo info(&file); 199 char mimetype[B_MIME_TYPE_LENGTH]; 200 info.GetType(mimetype); 201 202 // if App opened by Pref file 203 if (strcmp(mimetype, PREFFILE_MIMETYPE) == 0) { 204 205 BEntry ent(&ref); 206 BPath path(&ent); 207 PrefHandler::Default()->OpenText(path.Path()); 208 return; 209 } 210 211 // if App opened by Shell Script 212 if (strcmp(mimetype, "text/x-haiku-shscript") == 0) { 213 // Not implemented. 214 // beep(); 215 return; 216 } 217} 218 219 220status_t 221TermApp::_MakeTermWindow() 222{ 223 try { 224 fTermWindow = new TermWindow(fWindowTitle, fArgs); 225 } catch (int error) { 226 return (status_t)error; 227 } catch (...) { 228 return B_ERROR; 229 } 230 231 fTermWindow->Show(); 232 233 return B_OK; 234} 235 236 237//#ifndef B_NETPOSITIVE_APP_SIGNATURE 238//#define B_NETPOSITIVE_APP_SIGNATURE "application/x-vnd.Be-NPOS" 239//#endif 240// 241//void 242//TermApp::ShowHTML(BMessage *msg) 243//{ 244// const char *url; 245// msg->FindString("Url", &url); 246// BMessage message; 247// 248// message.what = B_NETPOSITIVE_OPEN_URL; 249// message.AddString("be:url", url); 250 251// be_roster->Launch(B_NETPOSITIVE_APP_SIGNATURE, &message); 252// while(!(be_roster->IsRunning(B_NETPOSITIVE_APP_SIGNATURE))) 253// snooze(10000); 254// 255// // Activate net+ 256// be_roster->ActivateApp(be_roster->TeamFor(B_NETPOSITIVE_APP_SIGNATURE)); 257//} 258 259 260void 261TermApp::_HandleChildCleanup() 262{ 263} 264 265 266/*static*/ void 267TermApp::_SigChildHandler(int signal, void* data) 268{ 269 // Spawing a thread that does the actual signal handling is pretty much 270 // the only safe thing to do in a multi-threaded application. The 271 // interrupted thread might have been anywhere, e.g. in a critical section, 272 // holding locks. If we do anything that does require locking at any point 273 // (e.g. memory allocation, messaging), we risk a dead-lock or data 274 // structure corruption. Spawing a thread is safe though, since its only 275 // a system call. 276 thread_id thread = spawn_thread(_ChildCleanupThread, "child cleanup", 277 B_NORMAL_PRIORITY, ((TermApp*)data)->fTermWindow); 278 if (thread >= 0) 279 resume_thread(thread); 280} 281 282 283/*static*/ status_t 284TermApp::_ChildCleanupThread(void* data) 285{ 286 // Just drop the windowa message and let it do the actual work. This 287 // saves us additional synchronization measures. 288 return ((TermWindow*)data)->PostMessage(MSG_CHECK_CHILDREN); 289} 290 291 292 293void 294TermApp::_Usage(char *name) 295{ 296 fprintf(stderr, B_TRANSLATE("Haiku Terminal\n" 297 "Copyright 2001-2009 Haiku, Inc.\n" 298 "Copyright(C) 1999 Kazuho Okui and Takashi Murai.\n" 299 "\n" 300 "Usage: %s [OPTION] [SHELL]\n"), name); 301 302 fprintf(stderr, 303 B_TRANSLATE(" -h, --help print this help\n" 304 //" -p, --preference load preference file\n" 305 " -t, --title set window title\n" 306 " -f, --fullscreen start fullscreen\n") 307 //" -geom, --geometry set window geometry\n" 308 //" An example of geometry is \"80x25+100+100\"\n" 309 ); 310} 311 312