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