xref: /haiku/src/kits/app/Application.cpp (revision 67bce78b48ed6d01b5a8eef89f5694c372b7e0a1)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2002, OpenBeOS
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		Application.cpp
23 //	Author:			Erik Jaesler (erik@cgsoftware.com)
24 //	Description:	BApplication class is the center of the application
25 //					universe.  The global be_app and be_app_messenger
26 //					variables are defined here as well.
27 //------------------------------------------------------------------------------
28 
29 // Standard Includes -----------------------------------------------------------
30 #include <new>
31 #include <stdio.h>
32 #include <string.h>
33 #include <unistd.h>
34 
35 // System Includes -------------------------------------------------------------
36 #include <Alert.h>
37 #include <AppFileInfo.h>
38 #include <Application.h>
39 #include <AppMisc.h>
40 #include <Cursor.h>
41 #include <Entry.h>
42 #include <File.h>
43 #include <InterfaceDefs.h>
44 #include <Locker.h>
45 #include <Path.h>
46 #include <PropertyInfo.h>
47 #include <RegistrarDefs.h>
48 #include <Roster.h>
49 #include <RosterPrivate.h>
50 #include <Window.h>
51 
52 // Project Includes ------------------------------------------------------------
53 #include <LooperList.h>
54 #include <ObjectLocker.h>
55 #include <AppServerLink.h>
56 #include <ServerProtocol.h>
57 #include <PortLink.h>
58 #include <PortMessage.h>
59 
60 // Local Includes --------------------------------------------------------------
61 
62 // Local Defines ---------------------------------------------------------------
63 
64 // Globals ---------------------------------------------------------------------
65 BApplication*	be_app = NULL;
66 BMessenger		be_app_messenger;
67 
68 BResources*	BApplication::_app_resources = NULL;
69 BLocker		BApplication::_app_resources_lock("_app_resources_lock");
70 
71 property_info gApplicationPropInfo[] =
72 {
73 	{
74 		"Window",
75 			{},
76 			{B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER},
77 			NULL, 0,
78 			{},
79 			{},
80 			{}
81 	},
82 	{
83 		"Window",
84 			{},
85 			{B_NAME_SPECIFIER},
86 			NULL, 1,
87 			{},
88 			{},
89 			{}
90 	},
91 	{
92 		"Looper",
93 			{},
94 			{B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER},
95 			NULL, 2,
96 			{},
97 			{},
98 			{}
99 	},
100 	{
101 		"Looper",
102 			{},
103 			{B_ID_SPECIFIER},
104 			NULL, 3,
105 			{},
106 			{},
107 			{}
108 	},
109 	{
110 		"Looper",
111 			{},
112 			{B_NAME_SPECIFIER},
113 			NULL, 4,
114 			{},
115 			{},
116 			{}
117 	},
118 	{
119 		"Name",
120 			{B_GET_PROPERTY},
121 			{B_DIRECT_SPECIFIER},
122 			NULL, 5,
123 			{B_STRING_TYPE},
124 			{},
125 			{}
126 	},
127 	{
128 		"Window",
129 			{B_COUNT_PROPERTIES},
130 			{B_DIRECT_SPECIFIER},
131 			NULL, 5,
132 			{B_INT32_TYPE},
133 			{},
134 			{}
135 	},
136 	{
137 		"Loopers",
138 			{B_GET_PROPERTY},
139 			{B_DIRECT_SPECIFIER},
140 			NULL, 5,
141 			{B_MESSENGER_TYPE},
142 			{},
143 			{}
144 	},
145 	{
146 		"Windows",
147 			{B_GET_PROPERTY},
148 			{B_DIRECT_SPECIFIER},
149 			NULL, 5,
150 			{B_MESSENGER_TYPE},
151 			{},
152 			{}
153 	},
154 	{
155 		"Looper",
156 			{B_COUNT_PROPERTIES},
157 			{B_DIRECT_SPECIFIER},
158 			NULL, 5,
159 			{B_INT32_TYPE},
160 			{},
161 			{}
162 	},
163 	{}
164 };
165 
166 // argc/argv
167 extern const int __libc_argc;
168 extern const char * const *__libc_argv;
169 
170 class BMenuWindow : public BWindow
171 {
172 };
173 //------------------------------------------------------------------------------
174 
175 // debugging
176 //#define DBG(x) x
177 #define DBG(x)
178 #define OUT	printf
179 
180 enum {
181 	NOT_IMPLEMENTED	= B_ERROR,
182 };
183 
184 // prototypes of helper functions
185 static const char* looper_name_for(const char *signature);
186 static status_t check_app_signature(const char *signature);
187 
188 //------------------------------------------------------------------------------
189 BApplication::BApplication(const char* signature)
190 			: BLooper(looper_name_for(signature)),
191 			  fAppName(NULL),
192 			  fServerFrom(-1),
193 			  fServerTo(-1),
194 			  fServerHeap(NULL),
195 			  fPulseRate(500000),
196 			  fInitialWorkspace(0),
197 			  fDraggedMessage(NULL),
198 			  fPulseRunner(NULL),
199 			  fInitError(B_NO_INIT),
200 			  fReadyToRunCalled(false)
201 {
202 	InitData(signature, NULL);
203 }
204 //------------------------------------------------------------------------------
205 BApplication::BApplication(const char* signature, status_t* error)
206 			: BLooper(looper_name_for(signature)),
207 			  fAppName(NULL),
208 			  fServerFrom(-1),
209 			  fServerTo(-1),
210 			  fServerHeap(NULL),
211 			  fPulseRate(500000),
212 			  fInitialWorkspace(0),
213 			  fDraggedMessage(NULL),
214 			  fPulseRunner(NULL),
215 			  fInitError(B_NO_INIT),
216 			  fReadyToRunCalled(false)
217 {
218 	InitData(signature, error);
219 }
220 //------------------------------------------------------------------------------
221 BApplication::~BApplication()
222 {
223 	// tell all loopers(usualy windows) to quit. Also, wait for them.
224 	BWindow*	window = NULL;
225 	BList		looperList;
226 	{
227 		using namespace BPrivate;
228 		BObjectLocker<BLooperList> ListLock(gLooperList);
229 		if (ListLock.IsLocked())
230 			gLooperList.GetLooperList(&looperList);
231 	}
232 
233 	for (int32 i = 0; i < looperList.CountItems(); i++)
234 	{
235 		window	= dynamic_cast<BWindow*>((BLooper*)looperList.ItemAt(i));
236 		if (window)
237 		{
238 			window->Lock();
239 			window->Quit();
240 		}
241 	}
242 
243 	// unregister from the roster
244 	BRoster::Private().RemoveApp(Team());
245 
246 	// tell app_server we're quiting...
247 	PortLink		link(fServerFrom);
248 	link.SetOpCode(B_QUIT_REQUESTED);
249 	link.Flush();
250 
251 	// uninitialize be_app and be_app_messenger
252 	be_app = NULL;
253 // R5 doesn't uninitialize be_app_messenger.
254 //	be_app_messenger = BMessenger();
255 }
256 //------------------------------------------------------------------------------
257 BApplication::BApplication(BMessage* data)
258 			: BLooper(looper_name_for(NULL)),
259 			  fAppName(NULL),
260 			  fServerFrom(-1),
261 			  fServerTo(-1),
262 			  fServerHeap(NULL),
263 			  fPulseRate(500000),
264 			  fInitialWorkspace(0),
265 			  fDraggedMessage(NULL),
266 			  fPulseRunner(NULL),
267 			  fInitError(B_NO_INIT),
268 			  fReadyToRunCalled(false)
269 {
270 }
271 //------------------------------------------------------------------------------
272 BArchivable* BApplication::Instantiate(BMessage* data)
273 {
274 	if (!validate_instantiation(data, "BApplication"))
275 	{
276 		return NULL;
277 	}
278 
279 	return new BApplication(data);
280 }
281 //------------------------------------------------------------------------------
282 status_t BApplication::Archive(BMessage* data, bool deep) const
283 {
284 	return NOT_IMPLEMENTED;
285 }
286 //------------------------------------------------------------------------------
287 status_t BApplication::InitCheck() const
288 {
289 	return fInitError;
290 }
291 //------------------------------------------------------------------------------
292 thread_id BApplication::Run()
293 {
294 	AssertLocked();
295 
296 	if (fRunCalled)
297 	{
298 		// Not allowed to call Run() more than once
299 		// TODO: test
300 		// find out what message is actually here
301 		debugger("");
302 	}
303 
304 	// Note: We need a local variable too (for the return value), since
305 	// fTaskID is cleared by Quit().
306 	thread_id thread = fTaskID = find_thread(NULL);
307 
308 	if (fMsgPort == B_NO_MORE_PORTS || fMsgPort == B_BAD_VALUE)
309 	{
310 		return fMsgPort;
311 	}
312 
313 	fRunCalled = true;
314 
315 	run_task();
316 
317 	return thread;
318 }
319 //------------------------------------------------------------------------------
320 void BApplication::Quit()
321 {
322 	bool unlock = false;
323 	if (!IsLocked()) {
324 		const char* name = Name();
325 		if (!name)
326 			name = "no-name";
327 		printf("ERROR - you must Lock the application object before calling "
328 			   "Quit(), team=%ld, looper=%s\n", Team(), name);
329 		unlock = true;
330 		if (!Lock())
331 			return;
332 	}
333 	// Delete the object, if not running only.
334 	if (!fRunCalled) {
335 		delete this;
336 	} else if (find_thread(NULL) != fTaskID) {
337 		// We are not the looper thread.
338 		// We push a _QUIT_ into the queue.
339 		// TODO: When BLooper::AddMessage() is done, use that instead of
340 		// PostMessage()??? This would overtake messages that are still at
341 		// the port.
342 		// NOTE: We must not unlock here -- otherwise we had to re-lock, which
343 		// may not work. This is bad, since, if the port is full, it
344 		// won't get emptier, as the looper thread needs to lock the object
345 		// before dispatching messages.
346 		while (PostMessage(_QUIT_, this) == B_WOULD_BLOCK)
347 			snooze(10000);
348 	} else {
349 		// We are the looper thread.
350 		// Just set fTerminating to true which makes us fall through the
351 		// message dispatching loop and return from Run().
352 		fTerminating = true;
353 	}
354 	// If we had to lock the object, unlock now.
355 	if (unlock)
356 		Unlock();
357 }
358 //------------------------------------------------------------------------------
359 bool BApplication::QuitRequested()
360 {
361 	// No windows -- nothing to do.
362 	// TODO: Au contraire, we can have opened windows, and we have
363 	// to quit them.
364 
365 	return BLooper::QuitRequested();
366 }
367 //------------------------------------------------------------------------------
368 void BApplication::Pulse()
369 {
370 }
371 //------------------------------------------------------------------------------
372 void BApplication::ReadyToRun()
373 {
374 }
375 //------------------------------------------------------------------------------
376 void BApplication::MessageReceived(BMessage* msg)
377 {
378 	BLooper::MessageReceived(msg);
379 }
380 //------------------------------------------------------------------------------
381 void BApplication::ArgvReceived(int32 argc, char** argv)
382 {
383 }
384 //------------------------------------------------------------------------------
385 void BApplication::AppActivated(bool active)
386 {
387 }
388 //------------------------------------------------------------------------------
389 void BApplication::RefsReceived(BMessage* a_message)
390 {
391 }
392 //------------------------------------------------------------------------------
393 void BApplication::AboutRequested()
394 {
395 	thread_info info;
396 	if (get_thread_info(Thread(), &info) == B_OK) {
397 		BAlert *alert = new BAlert("_about_", info.name, "OK");
398 		alert->Go(NULL);
399 	}
400 }
401 //------------------------------------------------------------------------------
402 BHandler* BApplication::ResolveSpecifier(BMessage* msg, int32 index,
403 										 BMessage* specifier, int32 form,
404 										 const char* property)
405 {
406 	return NULL;	// not implemented
407 }
408 //------------------------------------------------------------------------------
409 void BApplication::ShowCursor()
410 {
411 	// Because we're just sending an opcode, we can skip the BSession and fake the protocol
412 	int32 foo=AS_SHOW_CURSOR;
413 	write_port(fServerTo,AS_SHOW_CURSOR,&foo,sizeof(int32));
414 }
415 //------------------------------------------------------------------------------
416 void BApplication::HideCursor()
417 {
418 	// Because we're just sending an opcode, we can skip the BSession and fake the protocol
419 	int32 foo=AS_HIDE_CURSOR;
420 	write_port(fServerTo,AS_HIDE_CURSOR,&foo,sizeof(int32));
421 }
422 //------------------------------------------------------------------------------
423 void BApplication::ObscureCursor()
424 {
425 	// Because we're just sending an opcode, we can skip the BSession and fake the protocol
426 	int32 foo=AS_OBSCURE_CURSOR;
427 	write_port(fServerTo,AS_OBSCURE_CURSOR,&foo,sizeof(int32));
428 }
429 //------------------------------------------------------------------------------
430 bool BApplication::IsCursorHidden() const
431 {
432 	PortMessage msg;
433 
434 	BPrivate::BAppServerLink link;
435 	link.SetOpCode(AS_QUERY_CURSOR_HIDDEN);
436 	link.FlushWithReply(&msg);
437 	return (msg.Code()==SERVER_TRUE)?true:false;
438 }
439 //------------------------------------------------------------------------------
440 void BApplication::SetCursor(const void* cursor)
441 {
442 	// BeBook sez: If you want to call SetCursor() without forcing an immediate
443 	//				sync of the Application Server, you have to use a BCursor.
444 	// By deductive reasoning, this function forces a sync. =)
445 	BCursor Cursor(cursor);
446 	SetCursor(&Cursor, true);
447 }
448 //------------------------------------------------------------------------------
449 void BApplication::SetCursor(const BCursor* cursor, bool sync)
450 {
451 	BPrivate::BAppServerLink link;
452 	PortMessage msg;
453 
454 	link.SetOpCode(AS_SET_CURSOR_BCURSOR);
455 	link.Attach<bool>(sync);
456 	link.Attach<int32>(cursor->m_serverToken);
457 	if(sync)
458 		link.FlushWithReply(&msg);
459 	else
460 		link.Flush();
461 }
462 //------------------------------------------------------------------------------
463 int32 BApplication::CountWindows() const
464 {
465 	// BeBook sez: The windows list includes all windows explicitely created by
466 	//				the app ... but excludes private windows create by Be
467 	//				classes.
468 	// I'm taking this to include private menu windows, thus the incl_menus
469 	// param is false.
470 	return count_windows(false);
471 }
472 //------------------------------------------------------------------------------
473 BWindow* BApplication::WindowAt(int32 index) const
474 {
475 	// BeBook sez: The windows list includes all windows explicitely created by
476 	//				the app ... but excludes private windows create by Be
477 	//				classes.
478 	// I'm taking this to include private menu windows, thus the incl_menus
479 	// param is false.
480 	return window_at(index, false);
481 }
482 //------------------------------------------------------------------------------
483 int32 BApplication::CountLoopers() const
484 {
485 	using namespace BPrivate;
486 	BObjectLocker<BLooperList> ListLock(gLooperList);
487 	if (ListLock.IsLocked())
488 	{
489 		return gLooperList.CountLoopers();
490 	}
491 
492 	return B_ERROR;	// Some bad, non-specific thing has happened
493 }
494 //------------------------------------------------------------------------------
495 BLooper* BApplication::LooperAt(int32 index) const
496 {
497 	using namespace BPrivate;
498 	BLooper* Looper = NULL;
499 	BObjectLocker<BLooperList> ListLock(gLooperList);
500 	if (ListLock.IsLocked())
501 	{
502 		Looper = gLooperList.LooperAt(index);
503 	}
504 
505 	return Looper;
506 }
507 //------------------------------------------------------------------------------
508 bool BApplication::IsLaunching() const
509 {
510 	return !fReadyToRunCalled;
511 }
512 //------------------------------------------------------------------------------
513 status_t BApplication::GetAppInfo(app_info* info) const
514 {
515 	return be_roster->GetRunningAppInfo(be_app->Team(), info);
516 }
517 //------------------------------------------------------------------------------
518 BResources* BApplication::AppResources()
519 {
520 	return NULL;	// not implemented
521 }
522 //------------------------------------------------------------------------------
523 void BApplication::DispatchMessage(BMessage* message, BHandler* handler)
524 {
525 	switch (message->what) {
526 		case B_ARGV_RECEIVED:
527 		{
528 			// build the argv vector
529 			status_t error = B_OK;
530 			int32 argc;
531 			char **argv = NULL;
532 			if (message->FindInt32("argc", &argc) == B_OK && argc > 0) {
533 				argv = new char*[argc];
534 				for (int32 i = 0; error == B_OK && i < argc; i++)
535 					argv[i] = NULL;
536 				// copy the arguments
537 				for (int32 i = 0; error == B_OK && i < argc; i++) {
538 					const char *arg = NULL;
539 					error = message->FindString("argv", i, &arg);
540 					if (error == B_OK && arg) {
541 						argv[i] = new(std::nothrow) char[strlen(arg) + 1];
542 						if (argv[i])
543 							strcpy(argv[i], arg);
544 						else
545 							error = B_NO_MEMORY;
546 					}
547 				}
548 			}
549 			// call the hook
550 			if (error == B_OK)
551 				ArgvReceived(argc, argv);
552 			// cleanup
553 			if (argv) {
554 				for (int32 i = 0; i < argc; i++)
555 					delete[] argv[i];
556 				delete[] argv;
557 			}
558 			break;
559 		}
560 		case B_REFS_RECEIVED:
561 			RefsReceived(message);
562 			break;
563 		case B_READY_TO_RUN:
564 			// TODO: Find out, whether to set fReadyToRunCalled before or
565 			// after calling the hook.
566 			ReadyToRun();
567 			fReadyToRunCalled = true;
568 			break;
569 		default:
570 			BLooper::DispatchMessage(message, handler);
571 			break;
572 	}
573 }
574 //------------------------------------------------------------------------------
575 void BApplication::SetPulseRate(bigtime_t rate)
576 {
577 	fPulseRate = rate;
578 }
579 //------------------------------------------------------------------------------
580 status_t BApplication::GetSupportedSuites(BMessage* data)
581 {
582 	status_t err = B_OK;
583 	if (!data)
584 	{
585 		err = B_BAD_VALUE;
586 	}
587 
588 	if (!err)
589 	{
590 		err = data->AddString("Suites", "suite/vnd.Be-application");
591 		if (!err)
592 		{
593 			BPropertyInfo PropertyInfo(gApplicationPropInfo);
594 			err = data->AddFlat("message", &PropertyInfo);
595 			if (!err)
596 			{
597 				err = BHandler::GetSupportedSuites(data);
598 			}
599 		}
600 	}
601 
602 	return err;
603 }
604 //------------------------------------------------------------------------------
605 status_t BApplication::Perform(perform_code d, void* arg)
606 {
607 	return NOT_IMPLEMENTED;
608 }
609 //------------------------------------------------------------------------------
610 BApplication::BApplication(uint32 signature)
611 {
612 }
613 //------------------------------------------------------------------------------
614 BApplication::BApplication(const BApplication& rhs)
615 {
616 }
617 //------------------------------------------------------------------------------
618 BApplication& BApplication::operator=(const BApplication& rhs)
619 {
620 	return *this;
621 }
622 //------------------------------------------------------------------------------
623 void BApplication::_ReservedApplication1()
624 {
625 }
626 //------------------------------------------------------------------------------
627 void BApplication::_ReservedApplication2()
628 {
629 }
630 //------------------------------------------------------------------------------
631 void BApplication::_ReservedApplication3()
632 {
633 }
634 //------------------------------------------------------------------------------
635 void BApplication::_ReservedApplication4()
636 {
637 }
638 //------------------------------------------------------------------------------
639 void BApplication::_ReservedApplication5()
640 {
641 }
642 //------------------------------------------------------------------------------
643 void BApplication::_ReservedApplication6()
644 {
645 }
646 //------------------------------------------------------------------------------
647 void BApplication::_ReservedApplication7()
648 {
649 }
650 //------------------------------------------------------------------------------
651 void BApplication::_ReservedApplication8()
652 {
653 }
654 //------------------------------------------------------------------------------
655 bool BApplication::ScriptReceived(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property)
656 {
657 	return false;	// not implemented
658 }
659 //------------------------------------------------------------------------------
660 void BApplication::run_task()
661 {
662 	task_looper();
663 }
664 //------------------------------------------------------------------------------
665 void BApplication::InitData(const char* signature, status_t* error)
666 {
667 	// check whether there exists already an application
668 	if (be_app)
669 		debugger("2 BApplication objects were created. Only one is allowed.");
670 	// check signature
671 	fInitError = check_app_signature(signature);
672 	fAppName = signature;
673 	bool isRegistrar
674 		= (signature && !strcasecmp(signature, kRegistrarSignature));
675 	// get team and thread
676 	team_id team = Team();
677 	thread_id thread = BPrivate::main_thread_for(team);
678 	// get app executable ref
679 	entry_ref ref;
680 	if (fInitError == B_OK)
681 		fInitError = BPrivate::get_app_ref(&ref);
682 	// get the BAppFileInfo and extract the information we need
683 	uint32 appFlags = B_REG_DEFAULT_APP_FLAGS;
684 	if (fInitError == B_OK) {
685 		BAppFileInfo fileInfo;
686 		BFile file(&ref, B_READ_ONLY);
687 		fInitError = fileInfo.SetTo(&file);
688 		if (fInitError == B_OK) {
689 			fileInfo.GetAppFlags(&appFlags);
690 			char appFileSignature[B_MIME_TYPE_LENGTH + 1];
691 			// compare the file signature and the supplied signature
692 			if (fileInfo.GetSignature(appFileSignature) == B_OK) {
693 				if (strcasecmp(appFileSignature, signature) != 0) {
694 					printf("Signature in rsrc doesn't match constructor arg. "
695 						   "(%s,%s)\n", signature, appFileSignature);
696 				}
697 			}
698 		}
699 	}
700 #ifndef RUN_WITHOUT_REGISTRAR
701 	// check whether be_roster is valid
702 	if (fInitError == B_OK && !isRegistrar
703 		&& !BRoster::Private().IsMessengerValid(false)) {
704 		printf("FATAL: be_roster is not valid. Is the registrar running?\n");
705 		fInitError = B_NO_INIT;
706 	}
707 
708 	// check whether or not we are pre-registered
709 	bool preRegistered = false;
710 	app_info appInfo;
711 	if (fInitError == B_OK && !isRegistrar) {
712 		preRegistered = BRoster::Private().IsAppPreRegistered(&ref, team,
713 															  &appInfo);
714 	}
715 	if (preRegistered) {
716 		// we are pre-registered => the app info has been filled in
717 		// Check whether we need to replace the looper port with a port
718 		// created by the roster.
719 		if (appInfo.port >= 0 && appInfo.port != fMsgPort) {
720 			delete_port(fMsgPort);
721 			fMsgPort = appInfo.port;
722 		} else
723 			appInfo.port = fMsgPort;
724 		// check the signature and correct it, if necessary
725 		if (strcasecmp(appInfo.signature, fAppName))
726 			BRoster::Private().SetSignature(team, fAppName);
727 		// complete the registration
728 		fInitError = BRoster::Private().CompleteRegistration(team, thread,
729 															 appInfo.port);
730 	} else if (fInitError == B_OK) {
731 		// not pre-registered -- try to register the application
732 		team_id otherTeam = -1;
733 		// the registrar must not register
734 		if (!isRegistrar) {
735 			fInitError = BRoster::Private().AddApplication(signature, &ref,
736 				appFlags, team, thread, fMsgPort, true, NULL, &otherTeam);
737 		}
738 		if (fInitError == B_ALREADY_RUNNING) {
739 			// An instance is already running and we asked for
740 			// single/exclusive launch. Send our argv to the running app.
741 			// Do that only, if the app is NOT B_ARGV_ONLY.
742 			if (otherTeam >= 0 && __libc_argc > 1) {
743 				app_info otherAppInfo;
744 				if (be_roster->GetRunningAppInfo(otherTeam, &otherAppInfo)
745 					== B_OK && !(otherAppInfo.flags & B_ARGV_ONLY)) {
746 					// create an B_ARGV_RECEIVED message
747 					BMessage argvMessage(B_ARGV_RECEIVED);
748 					do_argv(&argvMessage);
749 					// replace the first argv string with the path of the
750 					// other application
751 					BPath path;
752 					if (path.SetTo(&otherAppInfo.ref) == B_OK)
753 						argvMessage.ReplaceString("argv", 0, path.Path());
754 					// send the message
755 					BMessenger(NULL, otherTeam).SendMessage(&argvMessage);
756 				}
757 			}
758 		} else if (fInitError == B_OK) {
759 			// the registrations was successful
760 			// Create a B_ARGV_RECEIVED message and send it to ourselves.
761 			// Do that even, if we are B_ARGV_ONLY.
762 			// TODO: When BLooper::AddMessage() is done, use that instead of
763 			// PostMessage().
764 			if (__libc_argc > 1) {
765 				BMessage argvMessage(B_ARGV_RECEIVED);
766 				do_argv(&argvMessage);
767 				PostMessage(&argvMessage, this);
768 			}
769 			// send a B_READY_TO_RUN message as well
770 			PostMessage(B_READY_TO_RUN, this);
771 		} else if (fInitError > B_ERRORS_END) {
772 			// Registrar internal errors shouldn't fall into the user's hands.
773 			fInitError = B_ERROR;
774 		}
775 	}
776 #endif	// ifdef RUN_WITHOUT_REGISTRAR
777 
778 	// TODO: Not completely sure about the order, but this should be close.
779 
780 	// An app_server connection is necessary for a lot of stuff, so get that first.
781 	if (fInitError == B_OK)
782 		connect_to_app_server();
783 	if (fInitError == B_OK)
784 		setup_server_heaps();
785 	if (fInitError == B_OK)
786 		get_scs();
787 
788 
789 	// init be_app and be_app_messenger
790 	if (fInitError == B_OK) {
791 		be_app = this;
792 		be_app_messenger = BMessenger(NULL, this);
793 	}
794 
795 	// Initialize the IK after we have set be_app because of a construction of a
796 	// BAppServerLink (which depends on be_app) nested inside the call to get_menu_info.
797 	if (fInitError == B_OK)
798 		fInitError = _init_interface_kit_();
799 	// set the BHandler's name
800 	if (fInitError == B_OK)
801 		SetName(ref.name);
802 	// create meta MIME
803 	if (fInitError == B_OK) {
804 		BPath path;
805 		if (path.SetTo(&ref) == B_OK)
806 			create_app_meta_mime(path.Path(), false, true, false);
807 	}
808 	// Return the error or exit, if there was an error and no error variable
809 	// has been supplied.
810 	if (error)
811 		*error = fInitError;
812 	else if (fInitError != B_OK)
813 		exit(0);
814 }
815 //------------------------------------------------------------------------------
816 void BApplication::BeginRectTracking(BRect r, bool trackWhole)
817 {
818 	BPrivate::BAppServerLink link;
819 	link.Attach<int32>(AS_BEGIN_RECT_TRACKING);
820 	link.Attach<BRect>(r);
821 	link.Attach<int32>(trackWhole);
822 	link.Flush();
823 }
824 //------------------------------------------------------------------------------
825 void BApplication::EndRectTracking()
826 {
827 	int32 foo=AS_END_RECT_TRACKING;
828 	write_port(fServerTo,AS_END_RECT_TRACKING,&foo,sizeof(int32));
829 }
830 //------------------------------------------------------------------------------
831 void BApplication::get_scs()
832 {
833 	//gPrivateScreen = new BPrivateScreen();
834 }
835 //------------------------------------------------------------------------------
836 void BApplication::setup_server_heaps()
837 {
838 }
839 //------------------------------------------------------------------------------
840 void* BApplication::rw_offs_to_ptr(uint32 offset)
841 {
842 	return NULL;	// not implemented
843 }
844 //------------------------------------------------------------------------------
845 void* BApplication::ro_offs_to_ptr(uint32 offset)
846 {
847 	return NULL;	// not implemented
848 }
849 //------------------------------------------------------------------------------
850 void* BApplication::global_ro_offs_to_ptr(uint32 offset)
851 {
852 	return NULL;	// not implemented
853 }
854 //------------------------------------------------------------------------------
855 void BApplication::connect_to_app_server()
856 {
857 	fServerFrom = find_port(SERVER_PORT_NAME);
858 	if (fServerFrom > 0) {
859 		// Create the port so that the app_server knows where to send messages
860 		fServerTo = create_port(100, "a<fServerTo");
861 		if (fServerTo > 0) {
862 			// AS_CREATE_APP:
863 
864 			// Attach data:
865 			// 1) port_id - receiver port of a regular app
866 			// 2) port_id - looper port for this BApplication
867 			// 3) team_id - team identification field
868 			// 4) int32 - handler ID token of the app
869 			// 5) char * - signature of the regular app
870 			PortLink link(fServerFrom);
871 			PortMessage pmsg;
872 
873 			link.SetOpCode(AS_CREATE_APP);
874 			link.Attach<port_id>(fServerTo);
875 			link.Attach<port_id>(_get_looper_port_(this));
876 			link.Attach<team_id>(Team());
877 			link.Attach<int32>(_get_object_token_(this));
878 			link.AttachString(fAppName);
879 			link.FlushWithReply(&pmsg);
880 
881 			// Reply code: AS_CREATE_APP
882 			// Reply data:
883 			//	1) port_id server-side application port (fServerFrom value)
884 			pmsg.Read<port_id>(&fServerFrom);
885 		}
886 		else
887 			fInitError = fServerTo;
888 	} else
889 		fInitError = fServerFrom;
890 }
891 //------------------------------------------------------------------------------
892 void BApplication::send_drag(BMessage* msg, int32 vs_token, BPoint offset, BRect drag_rect, BHandler* reply_to)
893 {
894 }
895 //------------------------------------------------------------------------------
896 void BApplication::send_drag(BMessage* msg, int32 vs_token, BPoint offset, int32 bitmap_token, drawing_mode dragMode, BHandler* reply_to)
897 {
898 }
899 //------------------------------------------------------------------------------
900 void BApplication::write_drag(_BSession_* session, BMessage* a_message)
901 {
902 }
903 //------------------------------------------------------------------------------
904 bool BApplication::quit_all_windows(bool force)
905 {
906 	return false;	// not implemented
907 }
908 //------------------------------------------------------------------------------
909 bool BApplication::window_quit_loop(bool, bool)
910 {
911 	// TODO: Implement and use in BApplication::QuitRequested()
912 	return false;
913 }
914 //------------------------------------------------------------------------------
915 void BApplication::do_argv(BMessage* message)
916 {
917 	if (message) {
918 		int32 argc = __libc_argc;
919 		const char * const *argv = __libc_argv;
920 		// add argc
921 		message->AddInt32("argc", argc);
922 		// add argv
923 		for (int32 i = 0; i < argc; i++)
924 			message->AddString("argv", argv[i]);
925 		// add current working directory
926 		char cwd[B_PATH_NAME_LENGTH + 1];
927 		if (getcwd(cwd, B_PATH_NAME_LENGTH + 1))
928 			message->AddString("cwd", cwd);
929 	}
930 }
931 //------------------------------------------------------------------------------
932 uint32 BApplication::InitialWorkspace()
933 {
934 	return 0;	// not implemented
935 }
936 //------------------------------------------------------------------------------
937 int32 BApplication::count_windows(bool incl_menus) const
938 {
939 	using namespace BPrivate;
940 
941 	// Windows are BLoopers, so we can just check each BLooper to see if it's
942 	// a BWindow (or BMenuWindow)
943 	int32 count = 0;
944 	BObjectLocker<BLooperList> ListLock(gLooperList);
945 	if (ListLock.IsLocked())
946 	{
947 		BLooper* Looper = NULL;
948 		for (int32 i = 0; i < gLooperList.CountLoopers(); ++i)
949 		{
950 			Looper = gLooperList.LooperAt(i);
951 			if (dynamic_cast<BWindow*>(Looper))
952 			{
953 				if (incl_menus || dynamic_cast<BMenuWindow*>(Looper) == NULL)
954 				{
955 					++count;
956 				}
957 			}
958 		}
959 	}
960 
961 	return count;
962 }
963 //------------------------------------------------------------------------------
964 BWindow* BApplication::window_at(uint32 index, bool incl_menus) const
965 {
966 	using namespace BPrivate;
967 
968 	// Windows are BLoopers, so we can just check each BLooper to see if it's
969 	// a BWindow (or BMenuWindow)
970 	uint32 count = 0;
971 	BWindow* Window = NULL;
972 	BObjectLocker<BLooperList> ListLock(gLooperList);
973 	if (ListLock.IsLocked())
974 	{
975 		BLooper* Looper = NULL;
976 		for (int32 i = 0; i < gLooperList.CountLoopers() && !Window; ++i)
977 		{
978 			Looper = gLooperList.LooperAt(i);
979 			if (dynamic_cast<BWindow*>(Looper))
980 			{
981 				if (incl_menus || dynamic_cast<BMenuWindow*>(Looper) == NULL)
982 				{
983 					if (count == index)
984 					{
985 						Window = dynamic_cast<BWindow*>(Looper);
986 					}
987 					else
988 					{
989 						++count;
990 					}
991 				}
992 			}
993 		}
994 	}
995 
996 	return Window;
997 }
998 //------------------------------------------------------------------------------
999 status_t BApplication::get_window_list(BList* list, bool incl_menus) const
1000 {
1001 	return NOT_IMPLEMENTED;
1002 }
1003 //------------------------------------------------------------------------------
1004 int32 BApplication::async_quit_entry(void* data)
1005 {
1006 	return 0;	// not implemented
1007 }
1008 //------------------------------------------------------------------------------
1009 
1010 // check_app_signature
1011 /*!	\brief Checks whether the supplied string is a valid application signature.
1012 
1013 	An error message is printed, if the string is no valid app signature.
1014 
1015 	\param signature The string to be checked.
1016 	\return
1017 	- \c B_OK: \a signature is a valid app signature.
1018 	- \c B_BAD_VALUE: \a signature is \c NULL or no valid app signature.
1019 */
1020 static
1021 status_t
1022 check_app_signature(const char *signature)
1023 {
1024 	bool isValid = false;
1025 	BMimeType type(signature);
1026 	if (type.IsValid() && !type.IsSupertypeOnly()
1027 		&& BMimeType("application").Contains(&type)) {
1028 		isValid = true;
1029 	}
1030 	if (!isValid) {
1031 		printf("bad signature (%s), must begin with \"application/\" and "
1032 			   "can't conflict with existing registered mime types inside "
1033 			   "the \"application\" media type.\n", signature);
1034 	}
1035 	return (isValid ? B_OK : B_BAD_VALUE);
1036 }
1037 
1038 // looper_name_for
1039 /*!	\brief Returns the looper name for a given signature.
1040 
1041 	Normally this is "AppLooperPort", but in case of the registrar a
1042 	special name.
1043 
1044 	\return The looper name.
1045 */
1046 static
1047 const char*
1048 looper_name_for(const char *signature)
1049 {
1050 	if (signature && !strcasecmp(signature, kRegistrarSignature))
1051 		return kRosterPortName;
1052 	return "AppLooperPort";
1053 }
1054 
1055 
1056 /*
1057  * $Log $
1058  *
1059  * $Id  $
1060  *
1061  */
1062 
1063