* Implemented InitData(), which should now be complete with respect to
what we need for the roster.
* B_{ARGV,REFS}_RECEIVED and B_READY_TO_RUN messages are dispatched now.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@457 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+266
-18
@@ -27,12 +27,19 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Standard Includes -----------------------------------------------------------
|
// Standard Includes -----------------------------------------------------------
|
||||||
|
#include <new>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
// System Includes -------------------------------------------------------------
|
// System Includes -------------------------------------------------------------
|
||||||
|
#include <AppFileInfo.h>
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
#include <Cursor.h>
|
#include <Cursor.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <File.h>
|
||||||
#include <Locker.h>
|
#include <Locker.h>
|
||||||
|
#include <Path.h>
|
||||||
#include <RegistrarDefs.h>
|
#include <RegistrarDefs.h>
|
||||||
#include <Roster.h>
|
#include <Roster.h>
|
||||||
|
|
||||||
@@ -49,6 +56,9 @@ BMessenger be_app_messenger;
|
|||||||
BResources* BApplication::_app_resources = NULL;
|
BResources* BApplication::_app_resources = NULL;
|
||||||
BLocker BApplication::_app_resources_lock("_app_resources_lock");
|
BLocker BApplication::_app_resources_lock("_app_resources_lock");
|
||||||
|
|
||||||
|
// argc/argv
|
||||||
|
extern const int __libc_argc;
|
||||||
|
extern const char * const *__libc_argv;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -61,17 +71,12 @@ enum {
|
|||||||
NOT_IMPLEMENTED = B_ERROR,
|
NOT_IMPLEMENTED = B_ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// prototypes of helper functions
|
||||||
|
static const char* looper_name_for(const char *signature);
|
||||||
|
static void assert_app_signature(const char *signature);
|
||||||
|
static status_t get_app_path(char *buffer);
|
||||||
|
static thread_id main_thread_for(team_id team);
|
||||||
|
|
||||||
// Returns the looper name for a given signature: Normally "AppLooperPort",
|
|
||||||
// but in case of the registrar a special name.
|
|
||||||
static
|
|
||||||
const char*
|
|
||||||
looper_name_for(const char *signature)
|
|
||||||
{
|
|
||||||
if (signature && !strcmp(signature, kRegistrarSignature))
|
|
||||||
return kRosterPortName;
|
|
||||||
return "AppLooperPort";
|
|
||||||
}
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
BApplication::BApplication(const char* signature)
|
BApplication::BApplication(const char* signature)
|
||||||
: BLooper(looper_name_for(signature)),
|
: BLooper(looper_name_for(signature)),
|
||||||
@@ -107,6 +112,8 @@ BApplication::BApplication(const char* signature, status_t* error)
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
BApplication::~BApplication()
|
BApplication::~BApplication()
|
||||||
{
|
{
|
||||||
|
// unregister from the roster
|
||||||
|
be_roster->RemoveApp(Team());
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
BApplication::BApplication(BMessage* data)
|
BApplication::BApplication(BMessage* data)
|
||||||
@@ -188,6 +195,8 @@ void BApplication::Quit()
|
|||||||
// BLooper::Quit() handles that gracefully.
|
// BLooper::Quit() handles that gracefully.
|
||||||
else if (find_thread(NULL) != fTaskID)
|
else if (find_thread(NULL) != fTaskID)
|
||||||
BLooper::Quit();
|
BLooper::Quit();
|
||||||
|
// prevent the BLooper destructor from killing the main thread
|
||||||
|
fTaskID = -1;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
bool BApplication::QuitRequested()
|
bool BApplication::QuitRequested()
|
||||||
@@ -314,9 +323,56 @@ BResources* BApplication::AppResources()
|
|||||||
return NULL; // not implemented
|
return NULL; // not implemented
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void BApplication::DispatchMessage(BMessage* an_event, BHandler* handler)
|
void BApplication::DispatchMessage(BMessage* message, BHandler* handler)
|
||||||
{
|
{
|
||||||
BLooper::DispatchMessage(an_event, handler);
|
switch (message->what) {
|
||||||
|
case B_ARGV_RECEIVED:
|
||||||
|
{
|
||||||
|
// build the argv vector
|
||||||
|
status_t error = B_OK;
|
||||||
|
int32 argc;
|
||||||
|
char **argv = NULL;
|
||||||
|
if (message->FindInt32("argc", &argc) == B_OK && argc > 0) {
|
||||||
|
argv = new char*[argc];
|
||||||
|
for (int32 i = 0; error == B_OK && i < argc; i++)
|
||||||
|
argv[i] = NULL;
|
||||||
|
// copy the arguments
|
||||||
|
for (int32 i = 0; error == B_OK && i < argc; i++) {
|
||||||
|
const char *arg = NULL;
|
||||||
|
error = message->FindString("argv", i, &arg);
|
||||||
|
if (error == B_OK && arg) {
|
||||||
|
argv[i] = new(nothrow) char[strlen(arg) + 1];
|
||||||
|
if (argv[i])
|
||||||
|
strcpy(argv[i], arg);
|
||||||
|
else
|
||||||
|
error = B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// call the hook
|
||||||
|
if (error == B_OK)
|
||||||
|
ArgvReceived(argc, argv);
|
||||||
|
// cleanup
|
||||||
|
if (argv) {
|
||||||
|
for (int32 i = 0; i < argc; i++)
|
||||||
|
delete[] argv[i];
|
||||||
|
delete[] argv;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case B_REFS_RECEIVED:
|
||||||
|
RefsReceived(message);
|
||||||
|
break;
|
||||||
|
case B_READY_TO_RUN:
|
||||||
|
// TODO: Find out, whether to set fReadyToRunCalled before or
|
||||||
|
// after calling the hook.
|
||||||
|
ReadyToRun();
|
||||||
|
fReadyToRunCalled = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLooper::DispatchMessage(message, handler);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void BApplication::SetPulseRate(bigtime_t rate)
|
void BApplication::SetPulseRate(bigtime_t rate)
|
||||||
@@ -392,12 +448,110 @@ void BApplication::run_task()
|
|||||||
void BApplication::InitData(const char* signature, status_t* error)
|
void BApplication::InitData(const char* signature, status_t* error)
|
||||||
{
|
{
|
||||||
// check signature
|
// check signature
|
||||||
|
assert_app_signature(signature);
|
||||||
fAppName = signature;
|
fAppName = signature;
|
||||||
// ...
|
bool isRegistrar = (signature && !strcmp(signature, kRegistrarSignature));
|
||||||
// check the looper
|
// get team and thread
|
||||||
// ...
|
team_id team = Team();
|
||||||
// everything went fine
|
thread_id thread = main_thread_for(team);
|
||||||
fInitError = B_OK;
|
// get app executable ref
|
||||||
|
entry_ref ref;
|
||||||
|
char appFilePath[B_PATH_NAME_LENGTH + 1];
|
||||||
|
fInitError = get_app_path(appFilePath);
|
||||||
|
if (fInitError == B_OK) {
|
||||||
|
BEntry entry(appFilePath, true);
|
||||||
|
fInitError = entry.GetRef(&ref);
|
||||||
|
}
|
||||||
|
// get the BAppFileInfo and extract the information we need
|
||||||
|
uint32 appFlags = B_REG_DEFAULT_APP_FLAGS;
|
||||||
|
if (fInitError == B_OK) {
|
||||||
|
BAppFileInfo fileInfo;
|
||||||
|
BFile file(&ref, B_READ_ONLY);
|
||||||
|
fInitError = fileInfo.SetTo(&file);
|
||||||
|
if (fInitError == B_OK) {
|
||||||
|
fileInfo.GetAppFlags(&appFlags);
|
||||||
|
char appFileSignature[B_MIME_TYPE_LENGTH + 1];
|
||||||
|
// compare the file signature and the supplied signature
|
||||||
|
if (fileInfo.GetSignature(appFileSignature) == B_OK) {
|
||||||
|
if (strcmp(appFileSignature, signature) != 0) {
|
||||||
|
printf("Signature in rsrc doesn't match constructor arg. "
|
||||||
|
"(%s,%s)\n", signature, appFileSignature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check whether or not we are pre-registered
|
||||||
|
bool preRegistered = false;
|
||||||
|
app_info appInfo;
|
||||||
|
if (fInitError == B_OK && !isRegistrar)
|
||||||
|
preRegistered = be_roster->IsAppPreRegistered(&ref, team, &appInfo);
|
||||||
|
if (preRegistered) {
|
||||||
|
// we are pre-registered => the app info has been filled in
|
||||||
|
// Check whether we need to replace the looper port with a port
|
||||||
|
// created by the roster.
|
||||||
|
if (appInfo.port >= 0 && appInfo.port != fMsgPort) {
|
||||||
|
delete_port(fMsgPort);
|
||||||
|
fMsgPort = appInfo.port;
|
||||||
|
} else
|
||||||
|
appInfo.port = fMsgPort;
|
||||||
|
// Create a B_ARGV_RECEIVED message and send it to ourselves.
|
||||||
|
// TODO: When BLooper::AddMessage() is done, use that instead of
|
||||||
|
// PostMessage().
|
||||||
|
if (!(appFlags & B_ARGV_ONLY) && __libc_argc > 1) {
|
||||||
|
BMessage argvMessage(B_ARGV_RECEIVED);
|
||||||
|
do_argv(&argvMessage);
|
||||||
|
PostMessage(&argvMessage, this);
|
||||||
|
}
|
||||||
|
// complete the registration
|
||||||
|
fInitError = be_roster->CompleteRegistration(team, thread,
|
||||||
|
appInfo.port);
|
||||||
|
} else if (fInitError == B_OK) {
|
||||||
|
// not pre-registered -- try to register the application
|
||||||
|
team_id otherTeam = -1;
|
||||||
|
status_t regError = B_OK;
|
||||||
|
// the registrar must not register
|
||||||
|
if (!isRegistrar) {
|
||||||
|
regError = be_roster->AddApplication(signature, &ref, appFlags,
|
||||||
|
team, thread, fMsgPort, true, NULL, &otherTeam);
|
||||||
|
}
|
||||||
|
if (regError == B_ALREADY_RUNNING) {
|
||||||
|
// An instance is already running and we asked for
|
||||||
|
// single/exclusive launch. Send our argv to the running app and
|
||||||
|
// exit.
|
||||||
|
if (!(appFlags & B_ARGV_ONLY) && otherTeam >= 0
|
||||||
|
&& __libc_argc > 1) {
|
||||||
|
BMessage argvMessage(B_ARGV_RECEIVED);
|
||||||
|
do_argv(&argvMessage);
|
||||||
|
// We need to replace the first argv string with the path
|
||||||
|
// of the respective application.
|
||||||
|
app_info otherAppInfo;
|
||||||
|
if (be_roster->GetRunningAppInfo(otherTeam, &otherAppInfo)
|
||||||
|
== B_OK) {
|
||||||
|
BPath path;
|
||||||
|
if (path.SetTo(&otherAppInfo.ref) == B_OK)
|
||||||
|
argvMessage.ReplaceString("argv", 0, path.Path());
|
||||||
|
}
|
||||||
|
BMessenger(NULL, otherTeam).SendMessage(&argvMessage);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if (regError == B_OK) {
|
||||||
|
// the registrations was successful
|
||||||
|
// Create a B_ARGV_RECEIVED message and send it to ourselves.
|
||||||
|
// TODO: When BLooper::AddMessage() is done, use that instead of
|
||||||
|
// PostMessage().
|
||||||
|
if (!(appFlags & B_ARGV_ONLY) && __libc_argc > 1) {
|
||||||
|
BMessage argvMessage(B_ARGV_RECEIVED);
|
||||||
|
do_argv(&argvMessage);
|
||||||
|
PostMessage(&argvMessage, this);
|
||||||
|
}
|
||||||
|
// send a B_READY_TO_RUN message as well
|
||||||
|
PostMessage(B_READY_TO_RUN, this);
|
||||||
|
} else
|
||||||
|
fInitError = regError;
|
||||||
|
}
|
||||||
|
// TODO: SetName()
|
||||||
|
// return the error
|
||||||
if (error)
|
if (error)
|
||||||
*error = fInitError;
|
*error = fInitError;
|
||||||
}
|
}
|
||||||
@@ -459,8 +613,21 @@ bool BApplication::window_quit_loop(bool, bool)
|
|||||||
return false; // not implemented
|
return false; // not implemented
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void BApplication::do_argv(BMessage* msg)
|
void BApplication::do_argv(BMessage* message)
|
||||||
{
|
{
|
||||||
|
if (message) {
|
||||||
|
int32 argc = __libc_argc;
|
||||||
|
const char * const *argv = __libc_argv;
|
||||||
|
// add argc
|
||||||
|
message->AddInt32("argc", argc);
|
||||||
|
// add argv
|
||||||
|
for (int32 i = 0; i < argc; i++)
|
||||||
|
message->AddString("argv", argv[i]);
|
||||||
|
// add current working directory
|
||||||
|
char cwd[B_PATH_NAME_LENGTH + 1];
|
||||||
|
if (getcwd(cwd, B_PATH_NAME_LENGTH + 1))
|
||||||
|
message->AddString("cwd", cwd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
uint32 BApplication::InitialWorkspace()
|
uint32 BApplication::InitialWorkspace()
|
||||||
@@ -489,6 +656,87 @@ int32 BApplication::async_quit_entry(void* data)
|
|||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// assert_app_signature
|
||||||
|
//
|
||||||
|
// Terminates with and error message, when the supplied signature is not a
|
||||||
|
// valid application signature.
|
||||||
|
static
|
||||||
|
void
|
||||||
|
assert_app_signature(const char *signature)
|
||||||
|
{
|
||||||
|
bool isValid = false;
|
||||||
|
BMimeType type(signature);
|
||||||
|
if (type.IsValid() && !type.IsSupertypeOnly()
|
||||||
|
&& BMimeType("application").Contains(&type)) {
|
||||||
|
isValid = true;
|
||||||
|
}
|
||||||
|
if (!isValid) {
|
||||||
|
printf("bad signature (%s), must begin with \"application/\" and "
|
||||||
|
"can't conflict with existing registered mime types inside "
|
||||||
|
"the \"application\" media type.\n", signature);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// looper_name_for
|
||||||
|
//
|
||||||
|
// Returns the looper name for a given signature: Normally "AppLooperPort",
|
||||||
|
// but in case of the registrar a special name.
|
||||||
|
static
|
||||||
|
const char*
|
||||||
|
looper_name_for(const char *signature)
|
||||||
|
{
|
||||||
|
if (signature && !strcmp(signature, kRegistrarSignature))
|
||||||
|
return kRosterPortName;
|
||||||
|
return "AppLooperPort";
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_app_path
|
||||||
|
//
|
||||||
|
// Returns the path of the application. buffer must be of length
|
||||||
|
// B_PATH_NAME_LENGTH + 1.
|
||||||
|
static
|
||||||
|
status_t
|
||||||
|
get_app_path(char *buffer)
|
||||||
|
{
|
||||||
|
status_t error = (buffer ? B_OK : B_BAD_VALUE);
|
||||||
|
image_info info;
|
||||||
|
int32 cookie = 0;
|
||||||
|
bool found = false;
|
||||||
|
if (error == B_OK) {
|
||||||
|
while (!found && get_next_image_info(0, &cookie, &info) == B_OK) {
|
||||||
|
if (info.type == B_APP_IMAGE) {
|
||||||
|
strncpy(buffer, info.name, B_PATH_NAME_LENGTH);
|
||||||
|
buffer[B_PATH_NAME_LENGTH] = 0;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (error == B_OK && !found)
|
||||||
|
error = B_ENTRY_NOT_FOUND;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// main_thread_for
|
||||||
|
//
|
||||||
|
// Returns the ID of the supplied team's main thread.
|
||||||
|
static
|
||||||
|
thread_id
|
||||||
|
main_thread_for(team_id team)
|
||||||
|
{
|
||||||
|
// For I can't find any trace of how to explicitly get the main thread,
|
||||||
|
// I assume the main thread is the one with the least thread ID.
|
||||||
|
thread_id thread = -1;
|
||||||
|
int32 cookie = 0;
|
||||||
|
thread_info info;
|
||||||
|
while (get_next_thread_info(team, &cookie, &info) == B_OK) {
|
||||||
|
if (thread < 0 || info.thread < thread)
|
||||||
|
thread = info.thread;
|
||||||
|
}
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Log $
|
* $Log $
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user