xref: /haiku/src/apps/terminal/TermApp.cpp (revision e8cd7007416a323259791ac09c013dcce2956976)
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