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