xref: /haiku/src/kits/app/Application.cpp (revision 6c4a44e36ba846c54467103f884d65dfa13e7fcb)
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->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
653 		alert->Go(NULL);
654 	}
655 }
656 
657 
658 BHandler *
659 BApplication::ResolveSpecifier(BMessage *message, int32 index,
660 	BMessage *specifier, int32 what, const char *property)
661 {
662 	BPropertyInfo propInfo(sPropertyInfo);
663 	status_t err = B_OK;
664 	uint32 data;
665 
666 	if (propInfo.FindMatch(message, 0, specifier, what, property, &data) >= 0) {
667 		switch (data) {
668 			case kWindowByIndex:
669 			{
670 				int32 index;
671 				err = specifier->FindInt32("index", &index);
672 				if (err != B_OK)
673 					break;
674 
675 				if (what == B_REVERSE_INDEX_SPECIFIER)
676 					index = CountWindows() - index;
677 
678 				BWindow *window = WindowAt(index);
679 				if (window != NULL) {
680 					message->PopSpecifier();
681 					BMessenger(window).SendMessage(message);
682 				} else
683 					err = B_BAD_INDEX;
684 				break;
685 			}
686 
687 			case kWindowByName:
688 			{
689 				const char *name;
690 				err = specifier->FindString("name", &name);
691 				if (err != B_OK)
692 					break;
693 
694 				for (int32 i = 0;; i++) {
695 					BWindow *window = WindowAt(i);
696 					if (window == NULL) {
697 						err = B_NAME_NOT_FOUND;
698 						break;
699 					}
700 					if (window->Title() != NULL && !strcmp(window->Title(), name)) {
701 						message->PopSpecifier();
702 						BMessenger(window).SendMessage(message);
703 						break;
704 					}
705 				}
706 				break;
707 			}
708 
709 			case kLooperByIndex:
710 			{
711 				int32 index;
712 				err = specifier->FindInt32("index", &index);
713 				if (err != B_OK)
714 					break;
715 
716 				if (what == B_REVERSE_INDEX_SPECIFIER)
717 					index = CountLoopers() - index;
718 
719 				BLooper *looper = LooperAt(index);
720 				if (looper != NULL) {
721 					message->PopSpecifier();
722 					BMessenger(looper).SendMessage(message);
723 				} else
724 					err = B_BAD_INDEX;
725 				break;
726 			}
727 
728 			case kLooperByID:
729 				// TODO: implement getting looper by ID!
730 				break;
731 
732 			case kLooperByName:
733 			{
734 				const char *name;
735 				err = specifier->FindString("name", &name);
736 				if (err != B_OK)
737 					break;
738 
739 				for (int32 i = 0;; i++) {
740 					BLooper *looper = LooperAt(i);
741 					if (looper == NULL) {
742 						err = B_NAME_NOT_FOUND;
743 						break;
744 					}
745 					if (looper->Name() != NULL && !strcmp(looper->Name(), name)) {
746 						message->PopSpecifier();
747 						BMessenger(looper).SendMessage(message);
748 						break;
749 					}
750 				}
751 				break;
752 			}
753 
754 			case kApplication:
755 				return this;
756 		}
757 	} else {
758 		return BLooper::ResolveSpecifier(message, index, specifier, what,
759 			property);
760 	}
761 
762 	if (err != B_OK) {
763 		BMessage reply(B_MESSAGE_NOT_UNDERSTOOD);
764 		reply.AddInt32("error", err);
765 		reply.AddString("message", strerror(err));
766 		message->SendReply(&reply);
767 	}
768 
769 	return NULL;
770 
771 }
772 
773 
774 void
775 BApplication::ShowCursor()
776 {
777 	BPrivate::AppServerLink link;
778 	link.StartMessage(AS_SHOW_CURSOR);
779 	link.Flush();
780 }
781 
782 
783 void
784 BApplication::HideCursor()
785 {
786 	BPrivate::AppServerLink link;
787 	link.StartMessage(AS_HIDE_CURSOR);
788 	link.Flush();
789 }
790 
791 
792 void
793 BApplication::ObscureCursor()
794 {
795 	BPrivate::AppServerLink link;
796 	link.StartMessage(AS_OBSCURE_CURSOR);
797 	link.Flush();
798 }
799 
800 
801 bool
802 BApplication::IsCursorHidden() const
803 {
804 	BPrivate::AppServerLink link;
805 	int32 status = B_ERROR;
806 	link.StartMessage(AS_QUERY_CURSOR_HIDDEN);
807 	link.FlushWithReply(status);
808 
809 	return status == B_OK;
810 }
811 
812 
813 void
814 BApplication::SetCursor(const void *cursorData)
815 {
816 	BCursor cursor(cursorData);
817 	SetCursor(&cursor, true);
818 		// forces the cursor to be sync'ed
819 }
820 
821 
822 void
823 BApplication::SetCursor(const BCursor *cursor, bool sync)
824 {
825 	BPrivate::AppServerLink link;
826 	link.StartMessage(AS_SET_CURSOR);
827 	link.Attach<bool>(sync);
828 	link.Attach<int32>(cursor->fServerToken);
829 
830 	if (sync) {
831 		int32 code;
832 		link.FlushWithReply(code);
833 	} else
834 		link.Flush();
835 }
836 
837 
838 int32
839 BApplication::CountWindows() const
840 {
841 	return _CountWindows(false);
842 		// we're ignoring menu windows
843 }
844 
845 
846 BWindow *
847 BApplication::WindowAt(int32 index) const
848 {
849 	return _WindowAt(index, false);
850 		// we're ignoring menu windows
851 }
852 
853 
854 int32
855 BApplication::CountLoopers() const
856 {
857 	AutoLocker<BLooperList> ListLock(gLooperList);
858 	if (ListLock.IsLocked())
859 		return gLooperList.CountLoopers();
860 
861 	// Some bad, non-specific thing has happened
862 	return B_ERROR;
863 }
864 
865 
866 BLooper *
867 BApplication::LooperAt(int32 index) const
868 {
869 	BLooper *looper = NULL;
870 	AutoLocker<BLooperList> listLock(gLooperList);
871 	if (listLock.IsLocked())
872 		looper = gLooperList.LooperAt(index);
873 
874 	return looper;
875 }
876 
877 
878 bool
879 BApplication::IsLaunching() const
880 {
881 	return !fReadyToRunCalled;
882 }
883 
884 
885 status_t
886 BApplication::GetAppInfo(app_info *info) const
887 {
888 	if (be_app == NULL || be_roster == NULL)
889 		return B_NO_INIT;
890 	return be_roster->GetRunningAppInfo(be_app->Team(), info);
891 }
892 
893 
894 BResources *
895 BApplication::AppResources()
896 {
897 	if (sAppResources == NULL)
898 		pthread_once(&sAppResourcesInitOnce, &_InitAppResources);
899 
900 	return sAppResources;
901 }
902 
903 
904 void
905 BApplication::DispatchMessage(BMessage *message, BHandler *handler)
906 {
907 	if (handler != this) {
908 		// it's not ours to dispatch
909 		BLooper::DispatchMessage(message, handler);
910 		return;
911 	}
912 
913 	switch (message->what) {
914 		case B_ARGV_RECEIVED:
915 			_ArgvReceived(message);
916 			break;
917 
918 		case B_REFS_RECEIVED:
919 		{
920 			// this adds the refs that are part of this message to the recent
921 			// lists, but only folders and documents are handled here
922 			entry_ref ref;
923 			int32 i = 0;
924 			while (message->FindRef("refs", i++, &ref) == B_OK) {
925 				BEntry entry(&ref, true);
926 				if (entry.InitCheck() != B_OK)
927 					continue;
928 
929 				if (entry.IsDirectory())
930 					BRoster().AddToRecentFolders(&ref);
931 				else {
932 					// filter out applications, we only want to have documents
933 					// in the recent files list
934 					BNode node(&entry);
935 					BNodeInfo info(&node);
936 
937 					char mimeType[B_MIME_TYPE_LENGTH];
938 					if (info.GetType(mimeType) != B_OK
939 						|| strcasecmp(mimeType, B_APP_MIME_TYPE))
940 						BRoster().AddToRecentDocuments(&ref);
941 				}
942 			}
943 
944 			RefsReceived(message);
945 			break;
946 		}
947 
948 		case B_READY_TO_RUN:
949 			if (!fReadyToRunCalled) {
950 				ReadyToRun();
951 				fReadyToRunCalled = true;
952 			}
953 			break;
954 
955 		case B_ABOUT_REQUESTED:
956 			AboutRequested();
957 			break;
958 
959 		case B_PULSE:
960 			Pulse();
961 			break;
962 
963 		case B_APP_ACTIVATED:
964 		{
965 			bool active;
966 			if (message->FindBool("active", &active) == B_OK)
967 				AppActivated(active);
968 			break;
969 		}
970 
971 		case _SHOW_DRAG_HANDLES_:
972 		{
973 			bool show;
974 			if (message->FindBool("show", &show) != B_OK)
975 				break;
976 
977 			BDragger::Private::UpdateShowAllDraggers(show);
978 			break;
979 		}
980 
981 		// TODO: Handle these as well
982 		case _DISPOSE_DRAG_:
983 		case _PING_:
984 			puts("not yet handled message:");
985 			DBG(message->PrintToStream());
986 			break;
987 
988 		default:
989 			BLooper::DispatchMessage(message, handler);
990 			break;
991 	}
992 }
993 
994 
995 void
996 BApplication::SetPulseRate(bigtime_t rate)
997 {
998 	if (rate < 0)
999 		rate = 0;
1000 
1001 	// BeBook states that we have only 100,000 microseconds granularity
1002 	rate -= rate % 100000;
1003 
1004 	if (!Lock())
1005 		return;
1006 
1007 	if (rate != 0) {
1008 		// reset existing pulse runner, or create new one
1009 		if (fPulseRunner == NULL) {
1010 			BMessage pulse(B_PULSE);
1011 			fPulseRunner = new BMessageRunner(be_app_messenger, &pulse, rate);
1012 		} else
1013 			fPulseRunner->SetInterval(rate);
1014 	} else {
1015 		// turn off pulse messages
1016 		delete fPulseRunner;
1017 		fPulseRunner = NULL;
1018 	}
1019 
1020 	fPulseRate = rate;
1021 	Unlock();
1022 }
1023 
1024 
1025 status_t
1026 BApplication::GetSupportedSuites(BMessage *data)
1027 {
1028 	if (!data)
1029 		return B_BAD_VALUE;
1030 
1031 	status_t status = data->AddString("suites", "suite/vnd.Be-application");
1032 	if (status == B_OK) {
1033 		BPropertyInfo propertyInfo(sPropertyInfo);
1034 		status = data->AddFlat("messages", &propertyInfo);
1035 		if (status == B_OK)
1036 			status = BLooper::GetSupportedSuites(data);
1037 	}
1038 
1039 	return status;
1040 }
1041 
1042 
1043 status_t
1044 BApplication::Perform(perform_code d, void *arg)
1045 {
1046 	return BLooper::Perform(d, arg);
1047 }
1048 
1049 
1050 void BApplication::_ReservedApplication1() {}
1051 void BApplication::_ReservedApplication2() {}
1052 void BApplication::_ReservedApplication3() {}
1053 void BApplication::_ReservedApplication4() {}
1054 void BApplication::_ReservedApplication5() {}
1055 void BApplication::_ReservedApplication6() {}
1056 void BApplication::_ReservedApplication7() {}
1057 void BApplication::_ReservedApplication8() {}
1058 
1059 
1060 bool
1061 BApplication::ScriptReceived(BMessage *message, int32 index,
1062 	BMessage *specifier, int32 what, const char *property)
1063 {
1064 	BMessage reply(B_REPLY);
1065 	status_t err = B_BAD_SCRIPT_SYNTAX;
1066 
1067 	switch (message->what) {
1068 		case B_GET_PROPERTY:
1069 			if (strcmp("Loopers", property) == 0) {
1070 				int32 count = CountLoopers();
1071 				err = B_OK;
1072 				for (int32 i=0; err == B_OK && i<count; i++) {
1073 					BMessenger messenger(LooperAt(i));
1074 					err = reply.AddMessenger("result", messenger);
1075 				}
1076 			} else if (strcmp("Windows", property) == 0) {
1077 				int32 count = CountWindows();
1078 				err = B_OK;
1079 				for (int32 i=0; err == B_OK && i<count; i++) {
1080 					BMessenger messenger(WindowAt(i));
1081 					err = reply.AddMessenger("result", messenger);
1082 				}
1083 			} else if (strcmp("Window", property) == 0) {
1084 				switch (what) {
1085 					case B_INDEX_SPECIFIER:
1086 					case B_REVERSE_INDEX_SPECIFIER:
1087 					{
1088 						int32 index = -1;
1089 						err = specifier->FindInt32("index", &index);
1090 						if (err != B_OK)
1091 							break;
1092 						if (what == B_REVERSE_INDEX_SPECIFIER)
1093 							index = CountWindows() - index;
1094 						err = B_BAD_INDEX;
1095 						BWindow *win = WindowAt(index);
1096 						if (!win)
1097 							break;
1098 						BMessenger messenger(win);
1099 						err = reply.AddMessenger("result", messenger);
1100 						break;
1101 					}
1102 					case B_NAME_SPECIFIER:
1103 					{
1104 						const char *name;
1105 						err = specifier->FindString("name", &name);
1106 						if (err != B_OK)
1107 							break;
1108 						err = B_NAME_NOT_FOUND;
1109 						for (int32 i = 0; i < CountWindows(); i++) {
1110 							BWindow* window = WindowAt(i);
1111 							if (window && window->Name() != NULL
1112 								&& !strcmp(window->Name(), name)) {
1113 								BMessenger messenger(window);
1114 								err = reply.AddMessenger("result", messenger);
1115 								break;
1116 							}
1117 						}
1118 						break;
1119 					}
1120 				}
1121 			} else if (strcmp("Looper", property) == 0) {
1122 				switch (what) {
1123 					case B_INDEX_SPECIFIER:
1124 					case B_REVERSE_INDEX_SPECIFIER:
1125 					{
1126 						int32 index = -1;
1127 						err = specifier->FindInt32("index", &index);
1128 						if (err != B_OK)
1129 							break;
1130 						if (what == B_REVERSE_INDEX_SPECIFIER)
1131 							index = CountLoopers() - index;
1132 						err = B_BAD_INDEX;
1133 						BLooper *looper = LooperAt(index);
1134 						if (!looper)
1135 							break;
1136 						BMessenger messenger(looper);
1137 						err = reply.AddMessenger("result", messenger);
1138 						break;
1139 					}
1140 					case B_NAME_SPECIFIER:
1141 					{
1142 						const char *name;
1143 						err = specifier->FindString("name", &name);
1144 						if (err != B_OK)
1145 							break;
1146 						err = B_NAME_NOT_FOUND;
1147 						for (int32 i = 0; i < CountLoopers(); i++) {
1148 							BLooper *looper = LooperAt(i);
1149 							if (looper && looper->Name()
1150 								&& !strcmp(looper->Name(), name)) {
1151 								BMessenger messenger(looper);
1152 								err = reply.AddMessenger("result", messenger);
1153 								break;
1154 							}
1155 						}
1156 						break;
1157 					}
1158 					case B_ID_SPECIFIER:
1159 					{
1160 						// TODO
1161 						debug_printf("Looper's ID specifier used but not implemented.\n");
1162 						break;
1163 					}
1164 				}
1165 			} else if (strcmp("Name", property) == 0) {
1166 				err = reply.AddString("result", Name());
1167 			}
1168 			break;
1169 		case B_COUNT_PROPERTIES:
1170 			if (strcmp("Looper", property) == 0) {
1171 				err = reply.AddInt32("result", CountLoopers());
1172 			} else if (strcmp("Window", property) == 0) {
1173 				err = reply.AddInt32("result", CountWindows());
1174 			}
1175 			break;
1176 	}
1177 	if (err == B_BAD_SCRIPT_SYNTAX)
1178 		return false;
1179 
1180 	if (err < B_OK) {
1181 		reply.what = B_MESSAGE_NOT_UNDERSTOOD;
1182 		reply.AddString("message", strerror(err));
1183 	}
1184 	reply.AddInt32("error", err);
1185 	message->SendReply(&reply);
1186 	return true;
1187 }
1188 
1189 
1190 void
1191 BApplication::BeginRectTracking(BRect rect, bool trackWhole)
1192 {
1193 	BPrivate::AppServerLink link;
1194 	link.StartMessage(AS_BEGIN_RECT_TRACKING);
1195 	link.Attach<BRect>(rect);
1196 	link.Attach<int32>(trackWhole);
1197 	link.Flush();
1198 }
1199 
1200 
1201 void
1202 BApplication::EndRectTracking()
1203 {
1204 	BPrivate::AppServerLink link;
1205 	link.StartMessage(AS_END_RECT_TRACKING);
1206 	link.Flush();
1207 }
1208 
1209 
1210 status_t
1211 BApplication::_SetupServerAllocator()
1212 {
1213 	fServerAllocator = new (std::nothrow) BPrivate::ServerMemoryAllocator();
1214 	if (fServerAllocator == NULL)
1215 		return B_NO_MEMORY;
1216 
1217 	return fServerAllocator->InitCheck();
1218 }
1219 
1220 
1221 status_t
1222 BApplication::_InitGUIContext()
1223 {
1224 	// An app_server connection is necessary for a lot of stuff, so get that first.
1225 	status_t error = _ConnectToServer();
1226 	if (error != B_OK)
1227 		return error;
1228 
1229 	// Initialize the IK after we have set be_app because of a construction
1230 	// of a AppServerLink (which depends on be_app) nested inside the call
1231 	// to get_menu_info.
1232 	error = _init_interface_kit_();
1233 	if (error != B_OK)
1234 		return error;
1235 
1236 	// create global system cursors
1237 	B_CURSOR_SYSTEM_DEFAULT = new BCursor(B_HAND_CURSOR);
1238 	B_CURSOR_I_BEAM = new BCursor(B_I_BEAM_CURSOR);
1239 
1240 	// TODO: would be nice to get the workspace at launch time from the registrar
1241 	fInitialWorkspace = current_workspace();
1242 
1243 	return B_OK;
1244 }
1245 
1246 
1247 status_t
1248 BApplication::_ConnectToServer()
1249 {
1250 	status_t status
1251 		= create_desktop_connection(fServerLink, "a<app_server", 100);
1252 	if (status != B_OK)
1253 		return status;
1254 
1255 	// AS_CREATE_APP:
1256 	//
1257 	// Attach data:
1258 	// 1) port_id - receiver port of a regular app
1259 	// 2) port_id - looper port for this BApplication
1260 	// 3) team_id - team identification field
1261 	// 4) int32 - handler ID token of the app
1262 	// 5) char * - signature of the regular app
1263 
1264 	fServerLink->StartMessage(AS_CREATE_APP);
1265 	fServerLink->Attach<port_id>(fServerLink->ReceiverPort());
1266 	fServerLink->Attach<port_id>(_get_looper_port_(this));
1267 	fServerLink->Attach<team_id>(Team());
1268 	fServerLink->Attach<int32>(_get_object_token_(this));
1269 	fServerLink->AttachString(fAppName);
1270 
1271 	area_id sharedReadOnlyArea;
1272 	team_id serverTeam;
1273 	port_id serverPort;
1274 
1275 	int32 code;
1276 	if (fServerLink->FlushWithReply(code) == B_OK
1277 		&& code == B_OK) {
1278 		// We don't need to contact the main app_server anymore
1279 		// directly; we now talk to our server alter ego only.
1280 		fServerLink->Read<port_id>(&serverPort);
1281 		fServerLink->Read<area_id>(&sharedReadOnlyArea);
1282 		fServerLink->Read<team_id>(&serverTeam);
1283 	} else {
1284 		fServerLink->SetSenderPort(-1);
1285 		debugger("BApplication: couldn't obtain new app_server comm port");
1286 		return B_ERROR;
1287 	}
1288 	fServerLink->SetTargetTeam(serverTeam);
1289 	fServerLink->SetSenderPort(serverPort);
1290 
1291 	status = _SetupServerAllocator();
1292 	if (status != B_OK)
1293 		return status;
1294 
1295 	area_id area;
1296 	uint8* base;
1297 	status = fServerAllocator->AddArea(sharedReadOnlyArea, area, base, true);
1298 	if (status < B_OK)
1299 		return status;
1300 
1301 	fServerReadOnlyMemory = base;
1302 	return B_OK;
1303 }
1304 
1305 
1306 void
1307 BApplication::_ReconnectToServer()
1308 {
1309 	delete_port(fServerLink->SenderPort());
1310 	delete_port(fServerLink->ReceiverPort());
1311 	invalidate_server_port();
1312 
1313 	if (_ConnectToServer() != B_OK)
1314 		debugger("Can't reconnect to app server!");
1315 
1316 	AutoLocker<BLooperList> listLock(gLooperList);
1317 	if (!listLock.IsLocked())
1318 		return;
1319 
1320 	uint32 count = gLooperList.CountLoopers();
1321 	for (uint32 i = 0; i < count ; i++) {
1322 		BWindow* window = dynamic_cast<BWindow*>(gLooperList.LooperAt(i));
1323 		if (window == NULL)
1324 			continue;
1325 		BMessenger windowMessenger(window);
1326 		windowMessenger.SendMessage(kMsgAppServerRestarted);
1327 	}
1328 
1329 	reconnect_bitmaps_to_app_server();
1330 	reconnect_pictures_to_app_server();
1331 }
1332 
1333 
1334 #if 0
1335 void
1336 BApplication::send_drag(BMessage *message, int32 vs_token, BPoint offset,
1337 	BRect dragRect, BHandler *replyTo)
1338 {
1339 	// TODO: implement
1340 }
1341 
1342 
1343 void
1344 BApplication::send_drag(BMessage *message, int32 vs_token, BPoint offset,
1345 	int32 bitmapToken, drawing_mode dragMode, BHandler *replyTo)
1346 {
1347 	// TODO: implement
1348 }
1349 
1350 
1351 void
1352 BApplication::write_drag(_BSession_ *session, BMessage *message)
1353 {
1354 	// TODO: implement
1355 }
1356 #endif
1357 
1358 bool
1359 BApplication::_WindowQuitLoop(bool quitFilePanels, bool force)
1360 {
1361 	int32 index = 0;
1362 	while (true) {
1363 		 BWindow *window = WindowAt(index);
1364 		 if (window == NULL)
1365 		 	break;
1366 
1367 		// NOTE: the window pointer might be stale, in case the looper
1368 		// was already quit by quitting an earlier looper... but fortunately,
1369 		// we can still call Lock() on the invalid pointer, and it
1370 		// will return false...
1371 		if (!window->Lock())
1372 			continue;
1373 
1374 		// don't quit file panels if we haven't been asked for it
1375 		if (!quitFilePanels && window->IsFilePanel()) {
1376 			window->Unlock();
1377 			index++;
1378 			continue;
1379 		}
1380 
1381 		if (!force && !window->QuitRequested()
1382 			&& !(quitFilePanels && window->IsFilePanel())) {
1383 			// the window does not want to quit, so we don't either
1384 			window->Unlock();
1385 			return false;
1386 		}
1387 
1388 		// Re-lock, just to make sure that the user hasn't done nasty
1389 		// things in QuitRequested(). Quit() unlocks fully, thus
1390 		// double-locking is harmless.
1391 		if (window->Lock())
1392 			window->Quit();
1393 
1394 		index = 0;
1395 			// we need to continue at the start of the list again - it
1396 			// might have changed
1397 	}
1398 	return true;
1399 }
1400 
1401 
1402 bool
1403 BApplication::_QuitAllWindows(bool force)
1404 {
1405 	AssertLocked();
1406 
1407 	// We need to unlock here because BWindow::QuitRequested() must be
1408 	// allowed to lock the application - which would cause a deadlock
1409 	Unlock();
1410 
1411 	bool quit = _WindowQuitLoop(false, force);
1412 	if (quit)
1413 		quit = _WindowQuitLoop(true, force);
1414 
1415 	Lock();
1416 
1417 	return quit;
1418 }
1419 
1420 
1421 void
1422 BApplication::_ArgvReceived(BMessage *message)
1423 {
1424 	ASSERT(message != NULL);
1425 
1426 	// build the argv vector
1427 	status_t error = B_OK;
1428 	int32 argc = 0;
1429 	char **argv = NULL;
1430 	if (message->FindInt32("argc", &argc) == B_OK && argc > 0) {
1431 		// allocate a NULL terminated array
1432 		argv = new(std::nothrow) char*[argc + 1];
1433 		if (argv == NULL)
1434 			return;
1435 
1436 		// copy the arguments
1437 		for (int32 i = 0; error == B_OK && i < argc; i++) {
1438 			const char *arg = NULL;
1439 			error = message->FindString("argv", i, &arg);
1440 			if (error == B_OK && arg) {
1441 				argv[i] = strdup(arg);
1442 				if (argv[i] == NULL)
1443 					error = B_NO_MEMORY;
1444 			} else
1445 				argc = i;
1446 		}
1447 
1448 		argv[argc] = NULL;
1449 	}
1450 
1451 	// call the hook
1452 	if (error == B_OK && argc > 0)
1453 		ArgvReceived(argc, argv);
1454 
1455 	if (error != B_OK) {
1456 		printf("Error parsing B_ARGV_RECEIVED message. Message:\n");
1457 		message->PrintToStream();
1458 	}
1459 
1460 	// cleanup
1461 	if (argv) {
1462 		for (int32 i = 0; i < argc; i++)
1463 			free(argv[i]);
1464 		delete[] argv;
1465 	}
1466 }
1467 
1468 
1469 uint32
1470 BApplication::InitialWorkspace()
1471 {
1472 	return fInitialWorkspace;
1473 }
1474 
1475 
1476 int32
1477 BApplication::_CountWindows(bool includeMenus) const
1478 {
1479 	uint32 count = 0;
1480 	for (int32 i = 0; i < gLooperList.CountLoopers(); i++) {
1481 		BWindow* window = dynamic_cast<BWindow*>(gLooperList.LooperAt(i));
1482 		if (window != NULL && !window->fOffscreen && (includeMenus
1483 				|| dynamic_cast<BMenuWindow *>(window) == NULL)) {
1484 			count++;
1485 		}
1486 	}
1487 
1488 	return count;
1489 }
1490 
1491 
1492 BWindow *
1493 BApplication::_WindowAt(uint32 index, bool includeMenus) const
1494 {
1495 	AutoLocker<BLooperList> listLock(gLooperList);
1496 	if (!listLock.IsLocked())
1497 		return NULL;
1498 
1499 	uint32 count = gLooperList.CountLoopers();
1500 	for (uint32 i = 0; i < count && index < count; i++) {
1501 		BWindow* window = dynamic_cast<BWindow*>(gLooperList.LooperAt(i));
1502 		if (window == NULL || (window != NULL && window->fOffscreen)
1503 			|| (!includeMenus && dynamic_cast<BMenuWindow *>(window) != NULL)) {
1504 			index++;
1505 			continue;
1506 		}
1507 
1508 		if (i == index)
1509 			return window;
1510 	}
1511 
1512 	return NULL;
1513 }
1514 
1515 
1516 /*static*/ void
1517 BApplication::_InitAppResources()
1518 {
1519 	entry_ref ref;
1520 	bool found = false;
1521 
1522 	// App is already running. Get its entry ref with
1523 	// GetAppInfo()
1524 	app_info appInfo;
1525 	if (be_app && be_app->GetAppInfo(&appInfo) == B_OK) {
1526 		ref = appInfo.ref;
1527 		found = true;
1528 	} else {
1529 		// Run() hasn't been called yet
1530 		found = BPrivate::get_app_ref(&ref) == B_OK;
1531 	}
1532 
1533 	if (!found)
1534 		return;
1535 
1536 	BFile file(&ref, B_READ_ONLY);
1537 	if (file.InitCheck() != B_OK)
1538 		return;
1539 
1540 	BResources* resources = new (std::nothrow) BResources(&file, false);
1541 	if (resources == NULL || resources->InitCheck() != B_OK) {
1542 		delete resources;
1543 		return;
1544 	}
1545 
1546 	sAppResources = resources;
1547 }
1548 
1549 
1550 //	#pragma mark -
1551 
1552 
1553 /*!
1554 	\brief Checks whether the supplied string is a valid application signature.
1555 
1556 	An error message is printed, if the string is no valid app signature.
1557 
1558 	\param signature The string to be checked.
1559 	\return
1560 	- \c B_OK: \a signature is a valid app signature.
1561 	- \c B_BAD_VALUE: \a signature is \c NULL or no valid app signature.
1562 */
1563 static status_t
1564 check_app_signature(const char *signature)
1565 {
1566 	bool isValid = false;
1567 	BMimeType type(signature);
1568 	if (type.IsValid() && !type.IsSupertypeOnly()
1569 		&& BMimeType("application").Contains(&type)) {
1570 		isValid = true;
1571 	}
1572 	if (!isValid) {
1573 		printf("bad signature (%s), must begin with \"application/\" and "
1574 			   "can't conflict with existing registered mime types inside "
1575 			   "the \"application\" media type.\n", signature);
1576 	}
1577 	return (isValid ? B_OK : B_BAD_VALUE);
1578 }
1579 
1580 
1581 /*!
1582 	\brief Returns the looper name for a given signature.
1583 
1584 	Normally this is "AppLooperPort", but in case of the registrar a
1585 	special name.
1586 
1587 	\return The looper name.
1588 */
1589 static const char *
1590 looper_name_for(const char *signature)
1591 {
1592 	if (signature && !strcasecmp(signature, kRegistrarSignature))
1593 		return BPrivate::get_roster_port_name();
1594 	return "AppLooperPort";
1595 }
1596 
1597 
1598 /*!
1599 	\brief Fills the passed BMessage with B_ARGV_RECEIVED infos.
1600 */
1601 static void
1602 fill_argv_message(BMessage &message)
1603 {
1604    	message.what = B_ARGV_RECEIVED;
1605 
1606 	int32 argc = __libc_argc;
1607 	const char * const *argv = __libc_argv;
1608 
1609 	// add argc
1610 	message.AddInt32("argc", argc);
1611 
1612 	// add argv
1613 	for (int32 i = 0; i < argc; i++) {
1614 		if (argv[i] != NULL)
1615 			message.AddString("argv", argv[i]);
1616 	}
1617 
1618 	// add current working directory
1619 	char cwd[B_PATH_NAME_LENGTH];
1620 	if (getcwd(cwd, B_PATH_NAME_LENGTH))
1621 		message.AddString("cwd", cwd);
1622 }
1623 
1624