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