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