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