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