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 37 static bool sUsageRequested = false; 38 //static bool sGeometryRequested = false; 39 40 41 int 42 main() 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 53 TermApp::TermApp() 54 : BApplication(TERM_SIGNATURE), 55 fStartFullscreen(false), 56 fTermWindow(NULL), 57 fArgs(NULL) 58 { 59 fArgs = new Arguments(0, NULL); 60 } 61 62 63 TermApp::~TermApp() 64 { 65 delete fArgs; 66 } 67 68 69 void 70 TermApp::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 119 bool 120 TermApp::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 138 void 139 TermApp::Quit() 140 { 141 BApplication::Quit(); 142 } 143 144 145 void 146 TermApp::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 164 void 165 TermApp::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 183 void 184 TermApp::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 220 status_t 221 TermApp::_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 260 void 261 TermApp::_HandleChildCleanup() 262 { 263 } 264 265 266 /*static*/ void 267 TermApp::_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 284 TermApp::_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 293 void 294 TermApp::_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