xref: /haiku/src/kits/app/Application.cpp (revision 85fb3e7df81f8d5b6e47a9a64a53873ea906ea6e)
1 /*
2  * Copyright 2001-2012, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Erik Jaesler (erik@cgsoftware.com)
7  * 		Jerome Duval
8  *		Axel Dörfler, axeld@pinc-software.de
9  */
10 
11 
12 #include <Application.h>
13 
14 #include <new>
15 #include <pthread.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 
21 #include <Alert.h>
22 #include <AppFileInfo.h>
23 #include <Cursor.h>
24 #include <Debug.h>
25 #include <Entry.h>
26 #include <File.h>
27 #include <Locker.h>
28 #include <MessageRunner.h>
29 #include <ObjectList.h>
30 #include <Path.h>
31 #include <PropertyInfo.h>
32 #include <RegistrarDefs.h>
33 #include <Resources.h>
34 #include <Roster.h>
35 #include <Window.h>
36 
37 #include <AppMisc.h>
38 #include <AppServerLink.h>
39 #include <AutoLocker.h>
40 #include <BitmapPrivate.h>
41 #include <DraggerPrivate.h>
42 #include <LooperList.h>
43 #include <MenuWindow.h>
44 #include <PicturePrivate.h>
45 #include <PortLink.h>
46 #include <RosterPrivate.h>
47 #include <ServerMemoryAllocator.h>
48 #include <ServerProtocol.h>
49 
50 
51 using namespace BPrivate;
52 
53 
54 BApplication *be_app = NULL;
55 BMessenger be_app_messenger;
56 
57 pthread_once_t sAppResourcesInitOnce = PTHREAD_ONCE_INIT;
58 BResources *BApplication::sAppResources = NULL;
59 
60 
61 enum {
62 	kWindowByIndex,
63 	kWindowByName,
64 	kLooperByIndex,
65 	kLooperByID,
66 	kLooperByName,
67 	kApplication
68 };
69 
70 static property_info sPropertyInfo[] = {
71 	{
72 		"Window",
73 		{},
74 		{B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER},
75 		NULL, kWindowByIndex,
76 		{},
77 		{},
78 		{}
79 	},
80 	{
81 		"Window",
82 		{},
83 		{B_NAME_SPECIFIER},
84 		NULL, kWindowByName,
85 		{},
86 		{},
87 		{}
88 	},
89 	{
90 		"Looper",
91 		{},
92 		{B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER},
93 		NULL, kLooperByIndex,
94 		{},
95 		{},
96 		{}
97 	},
98 	{
99 		"Looper",
100 		{},
101 		{B_ID_SPECIFIER},
102 		NULL, kLooperByID,
103 		{},
104 		{},
105 		{}
106 	},
107 	{
108 		"Looper",
109 		{},
110 		{B_NAME_SPECIFIER},
111 		NULL, kLooperByName,
112 		{},
113 		{},
114 		{}
115 	},
116 	{
117 		"Name",
118 		{B_GET_PROPERTY},
119 		{B_DIRECT_SPECIFIER},
120 		NULL, kApplication,
121 		{B_STRING_TYPE},
122 		{},
123 		{}
124 	},
125 	{
126 		"Window",
127 		{B_COUNT_PROPERTIES},
128 		{B_DIRECT_SPECIFIER},
129 		NULL, kApplication,
130 		{B_INT32_TYPE},
131 		{},
132 		{}
133 	},
134 	{
135 		"Loopers",
136 		{B_GET_PROPERTY},
137 		{B_DIRECT_SPECIFIER},
138 		NULL, kApplication,
139 		{B_MESSENGER_TYPE},
140 		{},
141 		{}
142 	},
143 	{
144 		"Windows",
145 		{B_GET_PROPERTY},
146 		{B_DIRECT_SPECIFIER},
147 		NULL, kApplication,
148 		{B_MESSENGER_TYPE},
149 		{},
150 		{}
151 	},
152 	{
153 		"Looper",
154 		{B_COUNT_PROPERTIES},
155 		{B_DIRECT_SPECIFIER},
156 		NULL, kApplication,
157 		{B_INT32_TYPE},
158 		{},
159 		{}
160 	},
161 	{}
162 };
163 
164 // argc/argv
165 extern const int __libc_argc;
166 extern const char * const *__libc_argv;
167 
168 
169 // debugging
170 //#define DBG(x) x
171 #define DBG(x)
172 #define OUT	printf
173 
174 
175 // prototypes of helper functions
176 static const char* looper_name_for(const char *signature);
177 static status_t check_app_signature(const char *signature);
178 static void fill_argv_message(BMessage &message);
179 
180 
181 BApplication::BApplication(const char *signature)
182 	: BLooper(looper_name_for(signature))
183 {
184 	_InitData(signature, true, NULL);
185 }
186 
187 
188 BApplication::BApplication(const char *signature, status_t *_error)
189 	: BLooper(looper_name_for(signature))
190 {
191 	_InitData(signature, true, _error);
192 }
193 
194 
195 BApplication::BApplication(const char *signature, bool initGUI,
196 		status_t *_error)
197 	: BLooper(looper_name_for(signature))
198 {
199 	_InitData(signature, initGUI, _error);
200 }
201 
202 
203 BApplication::BApplication(BMessage *data)
204 	// Note: BeOS calls the private BLooper(int32, port_id, const char *)
205 	// constructor here, test if it's needed
206 	: BLooper(looper_name_for(NULL))
207 {
208 	const char *signature = NULL;
209 	data->FindString("mime_sig", &signature);
210 
211 	_InitData(signature, true, NULL);
212 
213 	bigtime_t pulseRate;
214 	if (data->FindInt64("_pulse", &pulseRate) == B_OK)
215 		SetPulseRate(pulseRate);
216 }
217 
218 
219 BApplication::BApplication(uint32 signature)
220 {
221 }
222 
223 
224 BApplication::BApplication(const BApplication &rhs)
225 {
226 }
227 
228 
229 BApplication::~BApplication()
230 {
231 	Lock();
232 
233 	// tell all loopers(usually windows) to quit. Also, wait for them.
234 	_QuitAllWindows(true);
235 
236 	// unregister from the roster
237 	BRoster::Private().RemoveApp(Team());
238 
239 #ifndef RUN_WITHOUT_APP_SERVER
240 	// tell app_server we're quitting...
241 	if (be_app) {
242 		// be_app can be NULL here if the application fails to initialize
243 		// correctly. For example, if it's already running and it's set to
244 		// exclusive launch.
245 		BPrivate::AppServerLink link;
246 		link.StartMessage(B_QUIT_REQUESTED);
247 		link.Flush();
248 	}
249 	delete_port(fServerLink->SenderPort());
250 	delete_port(fServerLink->ReceiverPort());
251 	delete fServerLink;
252 #endif	// RUN_WITHOUT_APP_SERVER
253 
254 	delete fServerAllocator;
255 
256 	// uninitialize be_app, the be_app_messenger is invalidated automatically
257 	be_app = NULL;
258 }
259 
260 
261 BApplication &
262 BApplication::operator=(const BApplication &rhs)
263 {
264 	return *this;
265 }
266 
267 
268 void
269 BApplication::_InitData(const char *signature, bool initGUI, status_t *_error)
270 {
271 	DBG(OUT("BApplication::InitData(`%s', %p)\n", signature, _error));
272 	// check whether there exists already an application
273 	if (be_app)
274 		debugger("2 BApplication objects were created. Only one is allowed.");
275 
276 	fServerLink = new BPrivate::PortLink(-1, -1);
277 	fServerAllocator = NULL;
278 	fInitialWorkspace = 0;
279 	//fDraggedMessage = NULL;
280 	fReadyToRunCalled = false;
281 
282 	// initially, there is no pulse
283 	fPulseRunner = NULL;
284 	fPulseRate = 0;
285 
286 	// check signature
287 	fInitError = check_app_signature(signature);
288 	fAppName = signature;
289 
290 #ifndef RUN_WITHOUT_REGISTRAR
291 	bool isRegistrar = signature
292 		&& !strcasecmp(signature, kRegistrarSignature);
293 	// get team and thread
294 	team_id team = Team();
295 	thread_id thread = BPrivate::main_thread_for(team);
296 #endif
297 
298 	// get app executable ref
299 	entry_ref ref;
300 	if (fInitError == B_OK) {
301 		fInitError = BPrivate::get_app_ref(&ref);
302 		if (fInitError != B_OK) {
303 			DBG(OUT("BApplication::InitData(): Failed to get app ref: %s\n",
304 				strerror(fInitError)));
305 		}
306 	}
307 
308 	// get the BAppFileInfo and extract the information we need
309 	uint32 appFlags = B_REG_DEFAULT_APP_FLAGS;
310 	if (fInitError == B_OK) {
311 		BAppFileInfo fileInfo;
312 		BFile file(&ref, B_READ_ONLY);
313 		fInitError = fileInfo.SetTo(&file);
314 		if (fInitError == B_OK) {
315 			fileInfo.GetAppFlags(&appFlags);
316 			char appFileSignature[B_MIME_TYPE_LENGTH];
317 			// compare the file signature and the supplied signature
318 			if (fileInfo.GetSignature(appFileSignature) == B_OK
319 				&& strcasecmp(appFileSignature, signature) != 0) {
320 				printf("Signature in rsrc doesn't match constructor arg. (%s, %s)\n",
321 					signature, appFileSignature);
322 			}
323 		} else {
324 			DBG(OUT("BApplication::InitData(): Failed to get info from: "
325 				"BAppFileInfo: %s\n", strerror(fInitError)));
326 		}
327 	}
328 
329 #ifndef RUN_WITHOUT_REGISTRAR
330 	// check whether be_roster is valid
331 	if (fInitError == B_OK && !isRegistrar
332 		&& !BRoster::Private().IsMessengerValid(false)) {
333 		printf("FATAL: be_roster is not valid. Is the registrar running?\n");
334 		fInitError = B_NO_INIT;
335 	}
336 
337 	// check whether or not we are pre-registered
338 	bool preRegistered = false;
339 	app_info appInfo;
340 	if (fInitError == B_OK && !isRegistrar) {
341 		if (BRoster::Private().IsAppRegistered(&ref, team, 0, &preRegistered,
342 				&appInfo) != B_OK) {
343 			preRegistered = false;
344 		}
345 	}
346 	if (preRegistered) {
347 		// we are pre-registered => the app info has been filled in
348 		// Check whether we need to replace the looper port with a port
349 		// created by the roster.
350 		if (appInfo.port >= 0 && appInfo.port != fMsgPort) {
351 			delete_port(fMsgPort);
352 			fMsgPort = appInfo.port;
353 		} else
354 			appInfo.port = fMsgPort;
355 		// check the signature and correct it, if necessary, also the case
356 		if (strcmp(appInfo.signature, fAppName))
357 			BRoster::Private().SetSignature(team, fAppName);
358 		// complete the registration
359 		fInitError = BRoster::Private().CompleteRegistration(team, thread,
360 						appInfo.port);
361 	} else if (fInitError == B_OK) {
362 		// not pre-registered -- try to register the application
363 		team_id otherTeam = -1;
364 		// the registrar must not register
365 		if (!isRegistrar) {
366 			fInitError = BRoster::Private().AddApplication(signature, &ref,
367 				appFlags, team, thread, fMsgPort, true, NULL, &otherTeam);
368 			if (fInitError != B_OK) {
369 				DBG(OUT("BApplication::InitData(): Failed to add app: %s\n",
370 					strerror(fInitError)));
371 			}
372 		}
373 		if (fInitError == B_ALREADY_RUNNING) {
374 			// An instance is already running and we asked for
375 			// single/exclusive launch. Send our argv to the running app.
376 			// Do that only, if the app is NOT B_ARGV_ONLY.
377 			if (otherTeam >= 0) {
378 				BMessenger otherApp(NULL, otherTeam);
379 				app_info otherAppInfo;
380 				if (__libc_argc > 1
381 					&& be_roster->GetRunningAppInfo(otherTeam, &otherAppInfo) == B_OK
382 					&& !(otherAppInfo.flags & B_ARGV_ONLY)) {
383 					// create an B_ARGV_RECEIVED message
384 					BMessage argvMessage(B_ARGV_RECEIVED);
385 					fill_argv_message(argvMessage);
386 
387 					// replace the first argv string with the path of the
388 					// other application
389 					BPath path;
390 					if (path.SetTo(&otherAppInfo.ref) == B_OK)
391 						argvMessage.ReplaceString("argv", 0, path.Path());
392 
393 					// send the message
394 					otherApp.SendMessage(&argvMessage);
395 				} else
396 					otherApp.SendMessage(B_SILENT_RELAUNCH);
397 			}
398 		} else if (fInitError == B_OK) {
399 			// the registrations was successful
400 			// Create a B_ARGV_RECEIVED message and send it to ourselves.
401 			// Do that even, if we are B_ARGV_ONLY.
402 			// TODO: When BLooper::AddMessage() is done, use that instead of
403 			// PostMessage().
404 
405 			DBG(OUT("info: BApplication successfully registered.\n"));
406 
407 			if (__libc_argc > 1) {
408 				BMessage argvMessage(B_ARGV_RECEIVED);
409 				fill_argv_message(argvMessage);
410 				PostMessage(&argvMessage, this);
411 			}
412 			// send a B_READY_TO_RUN message as well
413 			PostMessage(B_READY_TO_RUN, this);
414 		} else if (fInitError > B_ERRORS_END) {
415 			// Registrar internal errors shouldn't fall into the user's hands.
416 			fInitError = B_ERROR;
417 		}
418 	}
419 #else
420 	// We need to have ReadyToRun called even when we're not using the registrar
421 	PostMessage(B_READY_TO_RUN, this);
422 #endif	// ifndef RUN_WITHOUT_REGISTRAR
423 
424 	if (fInitError == B_OK) {
425 		// TODO: Not completely sure about the order, but this should be close.
426 
427 		// init be_app and be_app_messenger
428 		be_app = this;
429 		be_app_messenger = BMessenger(NULL, this);
430 
431 		// set the BHandler's name
432 		SetName(ref.name);
433 
434 		// create meta MIME
435 		BPath path;
436 		if (path.SetTo(&ref) == B_OK)
437 			create_app_meta_mime(path.Path(), false, true, false);
438 
439 #ifndef RUN_WITHOUT_APP_SERVER
440 		// app server connection and IK initialization
441 		if (initGUI)
442 			fInitError = _InitGUIContext();
443 #endif	// RUN_WITHOUT_APP_SERVER
444 	}
445 
446 	// Return the error or exit, if there was an error and no error variable
447 	// has been supplied.
448 	if (_error) {
449 		*_error = fInitError;
450 	} else if (fInitError != B_OK) {
451 		DBG(OUT("BApplication::InitData() failed: %s\n", strerror(fInitError)));
452 		exit(0);
453 	}
454 DBG(OUT("BApplication::InitData() done\n"));
455 }
456 
457 
458 BArchivable *
459 BApplication::Instantiate(BMessage *data)
460 {
461 	if (validate_instantiation(data, "BApplication"))
462 		return new BApplication(data);
463 
464 	return NULL;
465 }
466 
467 
468 status_t
469 BApplication::Archive(BMessage *data, bool deep) const
470 {
471 	status_t status = BLooper::Archive(data, deep);
472 	if (status < B_OK)
473 		return status;
474 
475 	app_info info;
476 	status = GetAppInfo(&info);
477 	if (status < B_OK)
478 		return status;
479 
480 	status = data->AddString("mime_sig", info.signature);
481 	if (status < B_OK)
482 		return status;
483 
484 	return data->AddInt64("_pulse", fPulseRate);
485 }
486 
487 
488 status_t
489 BApplication::InitCheck() const
490 {
491 	return fInitError;
492 }
493 
494 
495 thread_id
496 BApplication::Run()
497 {
498 	if (fInitError != B_OK)
499 		return fInitError;
500 
501 	AssertLocked();
502 
503 	if (fRunCalled)
504 		debugger("BApplication::Run was already called. Can only be called once.");
505 
506 	fThread = find_thread(NULL);
507 	fRunCalled = true;
508 
509 	task_looper();
510 
511 	delete fPulseRunner;
512 	return fThread;
513 }
514 
515 
516 void
517 BApplication::Quit()
518 {
519 	bool unlock = false;
520 	if (!IsLocked()) {
521 		const char *name = Name();
522 		if (!name)
523 			name = "no-name";
524 		printf("ERROR - you must Lock the application object before calling "
525 			   "Quit(), team=%ld, looper=%s\n", Team(), name);
526 		unlock = true;
527 		if (!Lock())
528 			return;
529 	}
530 	// Delete the object, if not running only.
531 	if (!fRunCalled) {
532 		delete this;
533 	} else if (find_thread(NULL) != fThread) {
534 // ToDo: why shouldn't we set fTerminating to true directly in this case?
535 		// We are not the looper thread.
536 		// We push a _QUIT_ into the queue.
537 		// TODO: When BLooper::AddMessage() is done, use that instead of
538 		// PostMessage()??? This would overtake messages that are still at
539 		// the port.
540 		// NOTE: We must not unlock here -- otherwise we had to re-lock, which
541 		// may not work. This is bad, since, if the port is full, it
542 		// won't get emptier, as the looper thread needs to lock the object
543 		// before dispatching messages.
544 		while (PostMessage(_QUIT_, this) == B_WOULD_BLOCK)
545 			snooze(10000);
546 	} else {
547 		// We are the looper thread.
548 		// Just set fTerminating to true which makes us fall through the
549 		// message dispatching loop and return from Run().
550 		fTerminating = true;
551 	}
552 	// If we had to lock the object, unlock now.
553 	if (unlock)
554 		Unlock();
555 }
556 
557 
558 bool
559 BApplication::QuitRequested()
560 {
561 	return _QuitAllWindows(false);
562 }
563 
564 
565 void
566 BApplication::Pulse()
567 {
568 	// supposed to be implemented by subclasses
569 }
570 
571 
572 void
573 BApplication::ReadyToRun()
574 {
575 	// supposed to be implemented by subclasses
576 }
577 
578 
579 void
580 BApplication::MessageReceived(BMessage *message)
581 {
582 	switch (message->what) {
583 		case B_COUNT_PROPERTIES:
584 		case B_GET_PROPERTY:
585 		case B_SET_PROPERTY:
586 		{
587 			int32 index;
588 			BMessage specifier;
589 			int32 what;
590 			const char *property = NULL;
591 			if (message->GetCurrentSpecifier(&index, &specifier, &what, &property) < B_OK
592 				|| !ScriptReceived(message, index, &specifier, what, property))
593 				BLooper::MessageReceived(message);
594 			break;
595 		}
596 
597 		case B_SILENT_RELAUNCH:
598 			// Sent to a B_SINGLE_LAUNCH application when it's launched again
599 			// (see _InitData())
600 			be_roster->ActivateApp(Team());
601 			break;
602 
603 		case kMsgAppServerRestarted:
604 			_ReconnectToServer();
605 			break;
606 
607 		case kMsgDeleteServerMemoryArea:
608 		{
609 			int32 serverArea;
610 			if (message->FindInt32("server area", &serverArea) == B_OK) {
611 				// The link is not used, but we currently borrow its lock
612 				BPrivate::AppServerLink link;
613 				fServerAllocator->RemoveArea(serverArea);
614 			}
615 			break;
616 		}
617 
618 		default:
619 			BLooper::MessageReceived(message);
620 			break;
621 	}
622 }
623 
624 
625 void
626 BApplication::ArgvReceived(int32 argc, char **argv)
627 {
628 	// supposed to be implemented by subclasses
629 }
630 
631 
632 void
633 BApplication::AppActivated(bool active)
634 {
635 	// supposed to be implemented by subclasses
636 }
637 
638 
639 void
640 BApplication::RefsReceived(BMessage *message)
641 {
642 	// supposed to be implemented by subclasses
643 }
644 
645 
646 void
647 BApplication::AboutRequested()
648 {
649 	thread_info info;
650 	if (get_thread_info(Thread(), &info) == B_OK) {
651 		BAlert *alert = new BAlert("_about_", info.name, "OK");
652 		alert->Go(NULL);
653 	}
654 }
655 
656 
657 BHandler *
658 BApplication::ResolveSpecifier(BMessage *message, int32 index,
659 	BMessage *specifier, int32 what, const char *property)
660 {
661 	BPropertyInfo propInfo(sPropertyInfo);
662 	status_t err = B_OK;
663 	uint32 data;
664 
665 	if (propInfo.FindMatch(message, 0, specifier, what, property, &data) >= 0) {
666 		switch (data) {
667 			case kWindowByIndex:
668 			{
669 				int32 index;
670 				err = specifier->FindInt32("index", &index);
671 				if (err != B_OK)
672 					break;
673 
674 				if (what == B_REVERSE_INDEX_SPECIFIER)
675 					index = CountWindows() - index;
676 
677 				BWindow *window = WindowAt(index);
678 				if (window != NULL) {
679 					message->PopSpecifier();
680 					BMessenger(window).SendMessage(message);
681 				} else
682 					err = B_BAD_INDEX;
683 				break;
684 			}
685 
686 			case kWindowByName:
687 			{
688 				const char *name;
689 				err = specifier->FindString("name", &name);
690 				if (err != B_OK)
691 					break;
692 
693 				for (int32 i = 0;; i++) {
694 					BWindow *window = WindowAt(i);
695 					if (window == NULL) {
696 						err = B_NAME_NOT_FOUND;
697 						break;
698 					}
699 					if (window->Title() != NULL && !strcmp(window->Title(), name)) {
700 						message->PopSpecifier();
701 						BMessenger(window).SendMessage(message);
702 						break;
703 					}
704 				}
705 				break;
706 			}
707 
708 			case kLooperByIndex:
709 			{
710 				int32 index;
711 				err = specifier->FindInt32("index", &index);
712 				if (err != B_OK)
713 					break;
714 
715 				if (what == B_REVERSE_INDEX_SPECIFIER)
716 					index = CountLoopers() - index;
717 
718 				BLooper *looper = LooperAt(index);
719 				if (looper != NULL) {
720 					message->PopSpecifier();
721 					BMessenger(looper).SendMessage(message);
722 				} else
723 					err = B_BAD_INDEX;
724 				break;
725 			}
726 
727 			case kLooperByID:
728 				// TODO: implement getting looper by ID!
729 				break;
730 
731 			case kLooperByName:
732 			{
733 				const char *name;
734 				err = specifier->FindString("name", &name);
735 				if (err != B_OK)
736 					break;
737 
738 				for (int32 i = 0;; i++) {
739 					BLooper *looper = LooperAt(i);
740 					if (looper == NULL) {
741 						err = B_NAME_NOT_FOUND;
742 						break;
743 					}
744 					if (looper->Name() != NULL && !strcmp(looper->Name(), name)) {
745 						message->PopSpecifier();
746 						BMessenger(looper).SendMessage(message);
747 						break;
748 					}
749 				}
750 				break;
751 			}
752 
753 			case kApplication:
754 				return this;
755 		}
756 	} else {
757 		return BLooper::ResolveSpecifier(message, index, specifier, what,
758 			property);
759 	}
760 
761 	if (err != B_OK) {
762 		BMessage reply(B_MESSAGE_NOT_UNDERSTOOD);
763 		reply.AddInt32("error", err);
764 		reply.AddString("message", strerror(err));
765 		message->SendReply(&reply);
766 	}
767 
768 	return NULL;
769 
770 }
771 
772 
773 void
774 BApplication::ShowCursor()
775 {
776 	BPrivate::AppServerLink link;
777 	link.StartMessage(AS_SHOW_CURSOR);
778 	link.Flush();
779 }
780 
781 
782 void
783 BApplication::HideCursor()
784 {
785 	BPrivate::AppServerLink link;
786 	link.StartMessage(AS_HIDE_CURSOR);
787 	link.Flush();
788 }
789 
790 
791 void
792 BApplication::ObscureCursor()
793 {
794 	BPrivate::AppServerLink link;
795 	link.StartMessage(AS_OBSCURE_CURSOR);
796 	link.Flush();
797 }
798 
799 
800 bool
801 BApplication::IsCursorHidden() const
802 {
803 	BPrivate::AppServerLink link;
804 	int32 status = B_ERROR;
805 	link.StartMessage(AS_QUERY_CURSOR_HIDDEN);
806 	link.FlushWithReply(status);
807 
808 	return status == B_OK;
809 }
810 
811 
812 void
813 BApplication::SetCursor(const void *cursorData)
814 {
815 	BCursor cursor(cursorData);
816 	SetCursor(&cursor, true);
817 		// forces the cursor to be sync'ed
818 }
819 
820 
821 void
822 BApplication::SetCursor(const BCursor *cursor, bool sync)
823 {
824 	BPrivate::AppServerLink link;
825 	link.StartMessage(AS_SET_CURSOR);
826 	link.Attach<bool>(sync);
827 	link.Attach<int32>(cursor->fServerToken);
828 
829 	if (sync) {
830 		int32 code;
831 		link.FlushWithReply(code);
832 	} else
833 		link.Flush();
834 }
835 
836 
837 int32
838 BApplication::CountWindows() const
839 {
840 	return _CountWindows(false);
841 		// we're ignoring menu windows
842 }
843 
844 
845 BWindow *
846 BApplication::WindowAt(int32 index) const
847 {
848 	return _WindowAt(index, false);
849 		// we're ignoring menu windows
850 }
851 
852 
853 int32
854 BApplication::CountLoopers() const
855 {
856 	AutoLocker<BLooperList> ListLock(gLooperList);
857 	if (ListLock.IsLocked())
858 		return gLooperList.CountLoopers();
859 
860 	// Some bad, non-specific thing has happened
861 	return B_ERROR;
862 }
863 
864 
865 BLooper *
866 BApplication::LooperAt(int32 index) const
867 {
868 	BLooper *looper = NULL;
869 	AutoLocker<BLooperList> listLock(gLooperList);
870 	if (listLock.IsLocked())
871 		looper = gLooperList.LooperAt(index);
872 
873 	return looper;
874 }
875 
876 
877 bool
878 BApplication::IsLaunching() const
879 {
880 	return !fReadyToRunCalled;
881 }
882 
883 
884 status_t
885 BApplication::GetAppInfo(app_info *info) const
886 {
887 	if (be_app == NULL || be_roster == NULL)
888 		return B_NO_INIT;
889 	return be_roster->GetRunningAppInfo(be_app->Team(), info);
890 }
891 
892 
893 BResources *
894 BApplication::AppResources()
895 {
896 	if (sAppResources == NULL)
897 		pthread_once(&sAppResourcesInitOnce, &_InitAppResources);
898 
899 	return sAppResources;
900 }
901 
902 
903 void
904 BApplication::DispatchMessage(BMessage *message, BHandler *handler)
905 {
906 	if (handler != this) {
907 		// it's not ours to dispatch
908 		BLooper::DispatchMessage(message, handler);
909 		return;
910 	}
911 
912 	switch (message->what) {
913 		case B_ARGV_RECEIVED:
914 			_ArgvReceived(message);
915 			break;
916 
917 		case B_REFS_RECEIVED:
918 		{
919 			// this adds the refs that are part of this message to the recent
920 			// lists, but only folders and documents are handled here
921 			entry_ref ref;
922 			int32 i = 0;
923 			while (message->FindRef("refs", i++, &ref) == B_OK) {
924 				BEntry entry(&ref, true);
925 				if (entry.InitCheck() != B_OK)
926 					continue;
927 
928 				if (entry.IsDirectory())
929 					BRoster().AddToRecentFolders(&ref);
930 				else {
931 					// filter out applications, we only want to have documents
932 					// in the recent files list
933 					BNode node(&entry);
934 					BNodeInfo info(&node);
935 
936 					char mimeType[B_MIME_TYPE_LENGTH];
937 					if (info.GetType(mimeType) != B_OK
938 						|| strcasecmp(mimeType, B_APP_MIME_TYPE))
939 						BRoster().AddToRecentDocuments(&ref);
940 				}
941 			}
942 
943 			RefsReceived(message);
944 			break;
945 		}
946 
947 		case B_READY_TO_RUN:
948 			if (!fReadyToRunCalled) {
949 				ReadyToRun();
950 				fReadyToRunCalled = true;
951 			}
952 			break;
953 
954 		case B_ABOUT_REQUESTED:
955 			AboutRequested();
956 			break;
957 
958 		case B_PULSE:
959 			Pulse();
960 			break;
961 
962 		case B_APP_ACTIVATED:
963 		{
964 			bool active;
965 			if (message->FindBool("active", &active) == B_OK)
966 				AppActivated(active);
967 			break;
968 		}
969 
970 		case _SHOW_DRAG_HANDLES_:
971 		{
972 			bool show;
973 			if (message->FindBool("show", &show) != B_OK)
974 				break;
975 
976 			BDragger::Private::UpdateShowAllDraggers(show);
977 			break;
978 		}
979 
980 		// TODO: Handle these as well
981 		case _DISPOSE_DRAG_:
982 		case _PING_:
983 			puts("not yet handled message:");
984 			DBG(message->PrintToStream());
985 			break;
986 
987 		default:
988 			BLooper::DispatchMessage(message, handler);
989 			break;
990 	}
991 }
992 
993 
994 void
995 BApplication::SetPulseRate(bigtime_t rate)
996 {
997 	if (rate < 0)
998 		rate = 0;
999 
1000 	// BeBook states that we have only 100,000 microseconds granularity
1001 	rate -= rate % 100000;
1002 
1003 	if (!Lock())
1004 		return;
1005 
1006 	if (rate != 0) {
1007 		// reset existing pulse runner, or create new one
1008 		if (fPulseRunner == NULL) {
1009 			BMessage pulse(B_PULSE);
1010 			fPulseRunner = new BMessageRunner(be_app_messenger, &pulse, rate);
1011 		} else
1012 			fPulseRunner->SetInterval(rate);
1013 	} else {
1014 		// turn off pulse messages
1015 		delete fPulseRunner;
1016 		fPulseRunner = NULL;
1017 	}
1018 
1019 	fPulseRate = rate;
1020 	Unlock();
1021 }
1022 
1023 
1024 status_t
1025 BApplication::GetSupportedSuites(BMessage *data)
1026 {
1027 	if (!data)
1028 		return B_BAD_VALUE;
1029 
1030 	status_t status = data->AddString("suites", "suite/vnd.Be-application");
1031 	if (status == B_OK) {
1032 		BPropertyInfo propertyInfo(sPropertyInfo);
1033 		status = data->AddFlat("messages", &propertyInfo);
1034 		if (status == B_OK)
1035 			status = BLooper::GetSupportedSuites(data);
1036 	}
1037 
1038 	return status;
1039 }
1040 
1041 
1042 status_t
1043 BApplication::Perform(perform_code d, void *arg)
1044 {
1045 	return BLooper::Perform(d, arg);
1046 }
1047 
1048 
1049 void BApplication::_ReservedApplication1() {}
1050 void BApplication::_ReservedApplication2() {}
1051 void BApplication::_ReservedApplication3() {}
1052 void BApplication::_ReservedApplication4() {}
1053 void BApplication::_ReservedApplication5() {}
1054 void BApplication::_ReservedApplication6() {}
1055 void BApplication::_ReservedApplication7() {}
1056 void BApplication::_ReservedApplication8() {}
1057 
1058 
1059 bool
1060 BApplication::ScriptReceived(BMessage *message, int32 index,
1061 	BMessage *specifier, int32 what, const char *property)
1062 {
1063 	BMessage reply(B_REPLY);
1064 	status_t err = B_BAD_SCRIPT_SYNTAX;
1065 
1066 	switch (message->what) {
1067 		case B_GET_PROPERTY:
1068 			if (strcmp("Loopers", property) == 0) {
1069 				int32 count = CountLoopers();
1070 				err = B_OK;
1071 				for (int32 i=0; err == B_OK && i<count; i++) {
1072 					BMessenger messenger(LooperAt(i));
1073 					err = reply.AddMessenger("result", messenger);
1074 				}
1075 			} else if (strcmp("Windows", property) == 0) {
1076 				int32 count = CountWindows();
1077 				err = B_OK;
1078 				for (int32 i=0; err == B_OK && i<count; i++) {
1079 					BMessenger messenger(WindowAt(i));
1080 					err = reply.AddMessenger("result", messenger);
1081 				}
1082 			} else if (strcmp("Window", property) == 0) {
1083 				switch (what) {
1084 					case B_INDEX_SPECIFIER:
1085 					case B_REVERSE_INDEX_SPECIFIER:
1086 					{
1087 						int32 index = -1;
1088 						err = specifier->FindInt32("index", &index);
1089 						if (err != B_OK)
1090 							break;
1091 						if (what == B_REVERSE_INDEX_SPECIFIER)
1092 							index = CountWindows() - index;
1093 						err = B_BAD_INDEX;
1094 						BWindow *win = WindowAt(index);
1095 						if (!win)
1096 							break;
1097 						BMessenger messenger(win);
1098 						err = reply.AddMessenger("result", messenger);
1099 						break;
1100 					}
1101 					case B_NAME_SPECIFIER:
1102 					{
1103 						const char *name;
1104 						err = specifier->FindString("name", &name);
1105 						if (err != B_OK)
1106 							break;
1107 						err = B_NAME_NOT_FOUND;
1108 						for (int32 i = 0; i < CountWindows(); i++) {
1109 							BWindow* window = WindowAt(i);
1110 							if (window && window->Name() != NULL
1111 								&& !strcmp(window->Name(), name)) {
1112 								BMessenger messenger(window);
1113 								err = reply.AddMessenger("result", messenger);
1114 								break;
1115 							}
1116 						}
1117 						break;
1118 					}
1119 				}
1120 			} else if (strcmp("Looper", property) == 0) {
1121 				switch (what) {
1122 					case B_INDEX_SPECIFIER:
1123 					case B_REVERSE_INDEX_SPECIFIER:
1124 					{
1125 						int32 index = -1;
1126 						err = specifier->FindInt32("index", &index);
1127 						if (err != B_OK)
1128 							break;
1129 						if (what == B_REVERSE_INDEX_SPECIFIER)
1130 							index = CountLoopers() - index;
1131 						err = B_BAD_INDEX;
1132 						BLooper *looper = LooperAt(index);
1133 						if (!looper)
1134 							break;
1135 						BMessenger messenger(looper);
1136 						err = reply.AddMessenger("result", messenger);
1137 						break;
1138 					}
1139 					case B_NAME_SPECIFIER:
1140 					{
1141 						const char *name;
1142 						err = specifier->FindString("name", &name);
1143 						if (err != B_OK)
1144 							break;
1145 						err = B_NAME_NOT_FOUND;
1146 						for (int32 i = 0; i < CountLoopers(); i++) {
1147 							BLooper *looper = LooperAt(i);
1148 							if (looper && looper->Name()
1149 								&& !strcmp(looper->Name(), name)) {
1150 								BMessenger messenger(looper);
1151 								err = reply.AddMessenger("result", messenger);
1152 								break;
1153 							}
1154 						}
1155 						break;
1156 					}
1157 					case B_ID_SPECIFIER:
1158 					{
1159 						// TODO
1160 						debug_printf("Looper's ID specifier used but not implemented.\n");
1161 						break;
1162 					}
1163 				}
1164 			} else if (strcmp("Name", property) == 0) {
1165 				err = reply.AddString("result", Name());
1166 			}
1167 			break;
1168 		case B_COUNT_PROPERTIES:
1169 			if (strcmp("Looper", property) == 0) {
1170 				err = reply.AddInt32("result", CountLoopers());
1171 			} else if (strcmp("Window", property) == 0) {
1172 				err = reply.AddInt32("result", CountWindows());
1173 			}
1174 			break;
1175 	}
1176 	if (err == B_BAD_SCRIPT_SYNTAX)
1177 		return false;
1178 
1179 	if (err < B_OK) {
1180 		reply.what = B_MESSAGE_NOT_UNDERSTOOD;
1181 		reply.AddString("message", strerror(err));
1182 	}
1183 	reply.AddInt32("error", err);
1184 	message->SendReply(&reply);
1185 	return true;
1186 }
1187 
1188 
1189 void
1190 BApplication::BeginRectTracking(BRect rect, bool trackWhole)
1191 {
1192 	BPrivate::AppServerLink link;
1193 	link.StartMessage(AS_BEGIN_RECT_TRACKING);
1194 	link.Attach<BRect>(rect);
1195 	link.Attach<int32>(trackWhole);
1196 	link.Flush();
1197 }
1198 
1199 
1200 void
1201 BApplication::EndRectTracking()
1202 {
1203 	BPrivate::AppServerLink link;
1204 	link.StartMessage(AS_END_RECT_TRACKING);
1205 	link.Flush();
1206 }
1207 
1208 
1209 status_t
1210 BApplication::_SetupServerAllocator()
1211 {
1212 	fServerAllocator = new (std::nothrow) BPrivate::ServerMemoryAllocator();
1213 	if (fServerAllocator == NULL)
1214 		return B_NO_MEMORY;
1215 
1216 	return fServerAllocator->InitCheck();
1217 }
1218 
1219 
1220 status_t
1221 BApplication::_InitGUIContext()
1222 {
1223 	// An app_server connection is necessary for a lot of stuff, so get that first.
1224 	status_t error = _ConnectToServer();
1225 	if (error != B_OK)
1226 		return error;
1227 
1228 	// Initialize the IK after we have set be_app because of a construction
1229 	// of a AppServerLink (which depends on be_app) nested inside the call
1230 	// to get_menu_info.
1231 	error = _init_interface_kit_();
1232 	if (error != B_OK)
1233 		return error;
1234 
1235 	// create global system cursors
1236 	B_CURSOR_SYSTEM_DEFAULT = new BCursor(B_HAND_CURSOR);
1237 	B_CURSOR_I_BEAM = new BCursor(B_I_BEAM_CURSOR);
1238 
1239 	// TODO: would be nice to get the workspace at launch time from the registrar
1240 	fInitialWorkspace = current_workspace();
1241 
1242 	return B_OK;
1243 }
1244 
1245 
1246 status_t
1247 BApplication::_ConnectToServer()
1248 {
1249 	status_t status
1250 		= create_desktop_connection(fServerLink, "a<app_server", 100);
1251 	if (status != B_OK)
1252 		return status;
1253 
1254 	// AS_CREATE_APP:
1255 	//
1256 	// Attach data:
1257 	// 1) port_id - receiver port of a regular app
1258 	// 2) port_id - looper port for this BApplication
1259 	// 3) team_id - team identification field
1260 	// 4) int32 - handler ID token of the app
1261 	// 5) char * - signature of the regular app
1262 
1263 	fServerLink->StartMessage(AS_CREATE_APP);
1264 	fServerLink->Attach<port_id>(fServerLink->ReceiverPort());
1265 	fServerLink->Attach<port_id>(_get_looper_port_(this));
1266 	fServerLink->Attach<team_id>(Team());
1267 	fServerLink->Attach<int32>(_get_object_token_(this));
1268 	fServerLink->AttachString(fAppName);
1269 
1270 	area_id sharedReadOnlyArea;
1271 	team_id serverTeam;
1272 	port_id serverPort;
1273 
1274 	int32 code;
1275 	if (fServerLink->FlushWithReply(code) == B_OK
1276 		&& code == B_OK) {
1277 		// We don't need to contact the main app_server anymore
1278 		// directly; we now talk to our server alter ego only.
1279 		fServerLink->Read<port_id>(&serverPort);
1280 		fServerLink->Read<area_id>(&sharedReadOnlyArea);
1281 		fServerLink->Read<team_id>(&serverTeam);
1282 	} else {
1283 		fServerLink->SetSenderPort(-1);
1284 		debugger("BApplication: couldn't obtain new app_server comm port");
1285 		return B_ERROR;
1286 	}
1287 	fServerLink->SetTargetTeam(serverTeam);
1288 	fServerLink->SetSenderPort(serverPort);
1289 
1290 	status = _SetupServerAllocator();
1291 	if (status != B_OK)
1292 		return status;
1293 
1294 	area_id area;
1295 	uint8* base;
1296 	status = fServerAllocator->AddArea(sharedReadOnlyArea, area, base, true);
1297 	if (status < B_OK)
1298 		return status;
1299 
1300 	fServerReadOnlyMemory = base;
1301 	return B_OK;
1302 }
1303 
1304 
1305 void
1306 BApplication::_ReconnectToServer()
1307 {
1308 	delete_port(fServerLink->SenderPort());
1309 	delete_port(fServerLink->ReceiverPort());
1310 	invalidate_server_port();
1311 
1312 	if (_ConnectToServer() != B_OK)
1313 		debugger("Can't reconnect to app server!");
1314 
1315 	AutoLocker<BLooperList> listLock(gLooperList);
1316 	if (!listLock.IsLocked())
1317 		return;
1318 
1319 	uint32 count = gLooperList.CountLoopers();
1320 	for (uint32 i = 0; i < count ; i++) {
1321 		BWindow* window = dynamic_cast<BWindow*>(gLooperList.LooperAt(i));
1322 		if (window == NULL)
1323 			continue;
1324 		BMessenger windowMessenger(window);
1325 		windowMessenger.SendMessage(kMsgAppServerRestarted);
1326 	}
1327 
1328 	reconnect_bitmaps_to_app_server();
1329 	reconnect_pictures_to_app_server();
1330 }
1331 
1332 
1333 #if 0
1334 void
1335 BApplication::send_drag(BMessage *message, int32 vs_token, BPoint offset,
1336 	BRect dragRect, BHandler *replyTo)
1337 {
1338 	// TODO: implement
1339 }
1340 
1341 
1342 void
1343 BApplication::send_drag(BMessage *message, int32 vs_token, BPoint offset,
1344 	int32 bitmapToken, drawing_mode dragMode, BHandler *replyTo)
1345 {
1346 	// TODO: implement
1347 }
1348 
1349 
1350 void
1351 BApplication::write_drag(_BSession_ *session, BMessage *message)
1352 {
1353 	// TODO: implement
1354 }
1355 #endif
1356 
1357 bool
1358 BApplication::_WindowQuitLoop(bool quitFilePanels, bool force)
1359 {
1360 	int32 index = 0;
1361 	while (true) {
1362 		 BWindow *window = WindowAt(index);
1363 		 if (window == NULL)
1364 		 	break;
1365 
1366 		// NOTE: the window pointer might be stale, in case the looper
1367 		// was already quit by quitting an earlier looper... but fortunately,
1368 		// we can still call Lock() on the invalid pointer, and it
1369 		// will return false...
1370 		if (!window->Lock())
1371 			continue;
1372 
1373 		// don't quit file panels if we haven't been asked for it
1374 		if (!quitFilePanels && window->IsFilePanel()) {
1375 			window->Unlock();
1376 			index++;
1377 			continue;
1378 		}
1379 
1380 		if (!force && !window->QuitRequested()
1381 			&& !(quitFilePanels && window->IsFilePanel())) {
1382 			// the window does not want to quit, so we don't either
1383 			window->Unlock();
1384 			return false;
1385 		}
1386 
1387 		// Re-lock, just to make sure that the user hasn't done nasty
1388 		// things in QuitRequested(). Quit() unlocks fully, thus
1389 		// double-locking is harmless.
1390 		if (window->Lock())
1391 			window->Quit();
1392 
1393 		index = 0;
1394 			// we need to continue at the start of the list again - it
1395 			// might have changed
1396 	}
1397 	return true;
1398 }
1399 
1400 
1401 bool
1402 BApplication::_QuitAllWindows(bool force)
1403 {
1404 	AssertLocked();
1405 
1406 	// We need to unlock here because BWindow::QuitRequested() must be
1407 	// allowed to lock the application - which would cause a deadlock
1408 	Unlock();
1409 
1410 	bool quit = _WindowQuitLoop(false, force);
1411 	if (quit)
1412 		quit = _WindowQuitLoop(true, force);
1413 
1414 	Lock();
1415 
1416 	return quit;
1417 }
1418 
1419 
1420 void
1421 BApplication::_ArgvReceived(BMessage *message)
1422 {
1423 	ASSERT(message != NULL);
1424 
1425 	// build the argv vector
1426 	status_t error = B_OK;
1427 	int32 argc = 0;
1428 	char **argv = NULL;
1429 	if (message->FindInt32("argc", &argc) == B_OK && argc > 0) {
1430 		// allocate a NULL terminated array
1431 		argv = new(std::nothrow) char*[argc + 1];
1432 		if (argv == NULL)
1433 			return;
1434 
1435 		// copy the arguments
1436 		for (int32 i = 0; error == B_OK && i < argc; i++) {
1437 			const char *arg = NULL;
1438 			error = message->FindString("argv", i, &arg);
1439 			if (error == B_OK && arg) {
1440 				argv[i] = strdup(arg);
1441 				if (argv[i] == NULL)
1442 					error = B_NO_MEMORY;
1443 			} else
1444 				argc = i;
1445 		}
1446 
1447 		argv[argc] = NULL;
1448 	}
1449 
1450 	// call the hook
1451 	if (error == B_OK && argc > 0)
1452 		ArgvReceived(argc, argv);
1453 
1454 	if (error != B_OK) {
1455 		printf("Error parsing B_ARGV_RECEIVED message. Message:\n");
1456 		message->PrintToStream();
1457 	}
1458 
1459 	// cleanup
1460 	if (argv) {
1461 		for (int32 i = 0; i < argc; i++)
1462 			free(argv[i]);
1463 		delete[] argv;
1464 	}
1465 }
1466 
1467 
1468 uint32
1469 BApplication::InitialWorkspace()
1470 {
1471 	return fInitialWorkspace;
1472 }
1473 
1474 
1475 int32
1476 BApplication::_CountWindows(bool includeMenus) const
1477 {
1478 	uint32 count = 0;
1479 	for (int32 i = 0; i < gLooperList.CountLoopers(); i++) {
1480 		BWindow* window = dynamic_cast<BWindow*>(gLooperList.LooperAt(i));
1481 		if (window != NULL && !window->fOffscreen && (includeMenus
1482 				|| dynamic_cast<BMenuWindow *>(window) == NULL)) {
1483 			count++;
1484 		}
1485 	}
1486 
1487 	return count;
1488 }
1489 
1490 
1491 BWindow *
1492 BApplication::_WindowAt(uint32 index, bool includeMenus) const
1493 {
1494 	AutoLocker<BLooperList> listLock(gLooperList);
1495 	if (!listLock.IsLocked())
1496 		return NULL;
1497 
1498 	uint32 count = gLooperList.CountLoopers();
1499 	for (uint32 i = 0; i < count && index < count; i++) {
1500 		BWindow* window = dynamic_cast<BWindow*>(gLooperList.LooperAt(i));
1501 		if (window == NULL || (window != NULL && window->fOffscreen)
1502 			|| (!includeMenus && dynamic_cast<BMenuWindow *>(window) != NULL)) {
1503 			index++;
1504 			continue;
1505 		}
1506 
1507 		if (i == index)
1508 			return window;
1509 	}
1510 
1511 	return NULL;
1512 }
1513 
1514 
1515 /*static*/ void
1516 BApplication::_InitAppResources()
1517 {
1518 	entry_ref ref;
1519 	bool found = false;
1520 
1521 	// App is already running. Get its entry ref with
1522 	// GetAppInfo()
1523 	app_info appInfo;
1524 	if (be_app && be_app->GetAppInfo(&appInfo) == B_OK) {
1525 		ref = appInfo.ref;
1526 		found = true;
1527 	} else {
1528 		// Run() hasn't been called yet
1529 		found = BPrivate::get_app_ref(&ref) == B_OK;
1530 	}
1531 
1532 	if (!found)
1533 		return;
1534 
1535 	BFile file(&ref, B_READ_ONLY);
1536 	if (file.InitCheck() != B_OK)
1537 		return;
1538 
1539 	BResources* resources = new (std::nothrow) BResources(&file, false);
1540 	if (resources == NULL || resources->InitCheck() != B_OK) {
1541 		delete resources;
1542 		return;
1543 	}
1544 
1545 	sAppResources = resources;
1546 }
1547 
1548 
1549 //	#pragma mark -
1550 
1551 
1552 /*!
1553 	\brief Checks whether the supplied string is a valid application signature.
1554 
1555 	An error message is printed, if the string is no valid app signature.
1556 
1557 	\param signature The string to be checked.
1558 	\return
1559 	- \c B_OK: \a signature is a valid app signature.
1560 	- \c B_BAD_VALUE: \a signature is \c NULL or no valid app signature.
1561 */
1562 static status_t
1563 check_app_signature(const char *signature)
1564 {
1565 	bool isValid = false;
1566 	BMimeType type(signature);
1567 	if (type.IsValid() && !type.IsSupertypeOnly()
1568 		&& BMimeType("application").Contains(&type)) {
1569 		isValid = true;
1570 	}
1571 	if (!isValid) {
1572 		printf("bad signature (%s), must begin with \"application/\" and "
1573 			   "can't conflict with existing registered mime types inside "
1574 			   "the \"application\" media type.\n", signature);
1575 	}
1576 	return (isValid ? B_OK : B_BAD_VALUE);
1577 }
1578 
1579 
1580 /*!
1581 	\brief Returns the looper name for a given signature.
1582 
1583 	Normally this is "AppLooperPort", but in case of the registrar a
1584 	special name.
1585 
1586 	\return The looper name.
1587 */
1588 static const char *
1589 looper_name_for(const char *signature)
1590 {
1591 	if (signature && !strcasecmp(signature, kRegistrarSignature))
1592 		return BPrivate::get_roster_port_name();
1593 	return "AppLooperPort";
1594 }
1595 
1596 
1597 /*!
1598 	\brief Fills the passed BMessage with B_ARGV_RECEIVED infos.
1599 */
1600 static void
1601 fill_argv_message(BMessage &message)
1602 {
1603    	message.what = B_ARGV_RECEIVED;
1604 
1605 	int32 argc = __libc_argc;
1606 	const char * const *argv = __libc_argv;
1607 
1608 	// add argc
1609 	message.AddInt32("argc", argc);
1610 
1611 	// add argv
1612 	for (int32 i = 0; i < argc; i++) {
1613 		if (argv[i] != NULL)
1614 			message.AddString("argv", argv[i]);
1615 	}
1616 
1617 	// add current working directory
1618 	char cwd[B_PATH_NAME_LENGTH];
1619 	if (getcwd(cwd, B_PATH_NAME_LENGTH))
1620 		message.AddString("cwd", cwd);
1621 }
1622 
1623