Rewrote how the app_server and ServerApp's quit. As a side effect, the server

can now quit instantly.
AppServer must no longer call ServerApp's destructor once it's running - it now
has to call Quit() in this case. The ServerApp is now destructed in its own thread.
Some cleanup (like renaming ServerApp::MonitorThreadID() to Thread()).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13238 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2005-06-23 17:40:35 +00:00
parent 014ddc8724
commit fcb006dcf5
8 changed files with 526 additions and 533 deletions

View File

@ -2,8 +2,12 @@
* Copyright (c) 2001-2005, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Author: DarkWyrm <bpmagic@columbus.rr.com>
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Axel Dörfler, axeld@pinc-software.de
*/
#include <Accelerant.h>
#include <AppDefs.h>
#include <Directory.h>
@ -52,6 +56,10 @@
# define STRACE(x) ;
#endif
static const uint32 kMsgShutdownServer = 'shuT';
// Globals
Desktop *gDesktop;
@ -92,10 +100,9 @@ AppServer::AppServer(void) :
if (fServerInputPort == B_NO_MORE_PORTS)
debugger("app_server could not create input port");
fAppList = new BList();
fQuittingServer = false;
fQuitting = false;
sAppServer = this;
// Create the font server and scan the proper directories.
fontserver = new FontServer;
fontserver->Lock();
@ -228,19 +235,25 @@ AppServer::~AppServer(void)
int32
AppServer::PicassoThread(void *data)
{
for (;;) {
while (!sAppServer->fQuitting) {
acquire_sem(sAppServer->fAppListLock);
for (int32 i = 0;;) {
ServerApp *app = (ServerApp *)sAppServer->fAppList->ItemAt(i++);
ServerApp *app = (ServerApp *)sAppServer->fAppList.ItemAt(i++);
if (!app)
break;
app->PingTarget();
}
release_sem(sAppServer->fAppListLock);
// we do this every other second so as not to suck *too* many CPU cycles
release_sem(sAppServer->fAppListLock);
// we do this every second so as not to suck *too* many CPU cycles
snooze(1000000);
}
// app_server is about to quit
// wait some more, and then make sure it'll shutdown everything
snooze(2000000);
sAppServer->PostMessage(kMsgShutdownServer);
return 0;
}
@ -257,13 +270,13 @@ AppServer::LaunchInputServer()
fISThreadID = B_ERROR;
while (!BRoster::Private().IsMessengerValid(false) && !fQuittingServer) {
while (!BRoster::Private().IsMessengerValid(false) && !fQuitting) {
snooze(250000);
BRoster::Private::DeleteBeRoster();
BRoster::Private::InitBeRoster();
}
if (fQuittingServer)
if (fQuitting)
return;
// we use an area for cursor data communication with input_server
@ -323,18 +336,15 @@ AppServer::LaunchCursorThread()
int32
AppServer::CursorThread(void* data)
{
AppServer *app = (AppServer *)data;
AppServer *server = (AppServer *)data;
BPoint p;
app->LaunchInputServer();
server->LaunchInputServer();
do {
while (acquire_sem(app->fCursorSem) == B_OK) {
p.y = *app->fCursorAddr & 0x7fff;
p.x = *app->fCursorAddr >> 15 & 0x7fff;
while (acquire_sem(server->fCursorSem) == B_OK) {
BPoint p;
p.y = *server->fCursorAddr & 0x7fff;
p.x = *server->fCursorAddr >> 15 & 0x7fff;
gDesktop->GetDisplayDriver()->MoveCursorTo(p.x, p.y);
STRACE(("CursorThread : %f, %f\n", p.x, p.y));
@ -342,12 +352,25 @@ AppServer::CursorThread(void* data)
snooze(100000);
} while (!app->fQuittingServer);
} while (!server->fQuitting);
return B_OK;
}
/*!
\brief Send a message to the AppServer with no attachments
\param code ID code of the message to post
*/
void
AppServer::PostMessage(int32 code)
{
BPrivate::LinkSender link(fMessagePort);
link.StartMessage(code);
link.Flush();
}
/*!
\brief The call that starts it all...
\return Always 0
@ -365,38 +388,19 @@ AppServer::Run(void)
void
AppServer::MainLoop(void)
{
BPrivate::PortLink pmsg(-1, fMessagePort);
BPrivate::PortLink link(-1, fMessagePort);
while (1) {
STRACE(("info: AppServer::MainLoop listening on port %ld.\n", fMessagePort));
int32 code;
status_t err = pmsg.GetNextMessage(code);
status_t err = link.GetNextMessage(code);
if (err < B_OK) {
STRACE(("MainLoop:pmsg.GetNextMessage() failed\n"));
STRACE(("MainLoop:link.GetNextMessage() failed\n"));
continue;
}
switch (code) {
case B_QUIT_REQUESTED:
case AS_CREATE_APP:
case AS_DELETE_APP:
case AS_UPDATED_CLIENT_FONTLIST:
case AS_QUERY_FONTS_CHANGED:
case AS_SET_UI_COLORS:
case AS_GET_UI_COLOR:
case AS_SET_DECORATOR:
case AS_GET_DECORATOR:
case AS_R5_SET_DECORATOR:
DispatchMessage(code, pmsg);
break;
default:
{
STRACE(("Server::MainLoop received unexpected code %ld (offset %ld)\n",
code, code - SERVER_TRUE));
break;
}
}
DispatchMessage(code, link);
}
}
@ -413,7 +417,7 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
case AS_CREATE_APP:
{
// Create the ServerApp to node monitor a new BApplication
// Attached data:
// 1) port_id - receiver port of a regular app
// 2) port_id - client looper port - for send messages to the client
@ -435,39 +439,29 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
if (msg.ReadString(&appSignature) != B_OK)
break;
port_id serverListen = create_port(DEFAULT_MONITOR_PORT_SIZE, appSignature);
if (serverListen < B_OK) {
printf("No more ports left. Time to crash. Have a nice day! :)\n");
break;
}
// we let the application own the port, so that we get aware when it's gone
if (set_port_owner(serverListen, clientTeamID) < B_OK) {
delete_port(serverListen);
printf("Could not transfer port ownership to client %ld!\n", clientTeamID);
break;
}
// Create the ServerApp subthread for this app
acquire_sem(fAppListLock);
ServerApp *app = new ServerApp(clientReplyPort, serverListen, clientLooperPort,
ServerApp *app = new ServerApp(clientReplyPort, clientLooperPort,
clientTeamID, htoken, appSignature);
if (app->InitCheck() == B_OK
&& app->Run()) {
// add the new ServerApp to the known list of ServerApps
acquire_sem(fAppListLock);
fAppList.AddItem(app);
release_sem(fAppListLock);
} else {
delete app;
// add the new ServerApp to the known list of ServerApps
fAppList->AddItem(app);
release_sem(fAppListLock);
BPrivate::PortLink replylink(clientReplyPort);
replylink.StartMessage(SERVER_TRUE);
replylink.Attach<int32>(serverListen);
replylink.Flush();
// if everything went well, ServerApp::Run() will notify
// the client - but since it didn't, we do it here
BPrivate::LinkSender reply(clientReplyPort);
reply.StartMessage(SERVER_FALSE);
reply.Flush();
}
// This is necessary because BPortLink::ReadString allocates memory
free(appSignature);
break;
}
case AS_DELETE_APP:
{
// Delete a ServerApp. Received only from the respective ServerApp when a
@ -476,41 +470,45 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
// Attached Data:
// 1) thread_id - thread ID of the ServerApp to be deleted
int32 i = 0, appnum = fAppList->CountItems();
ServerApp *srvapp = NULL;
thread_id srvapp_id = -1;
if (msg.Read<thread_id>(&srvapp_id) < B_OK)
thread_id thread = -1;
if (msg.Read<thread_id>(&thread) < B_OK)
break;
acquire_sem(fAppListLock);
// Run through the list of apps and nuke the proper one
for (i = 0; i < appnum; i++) {
srvapp = (ServerApp *)fAppList->ItemAt(i);
if (srvapp != NULL && srvapp->MonitorThreadID() == srvapp_id) {
srvapp = (ServerApp *)fAppList->RemoveItem(i);
if (srvapp) {
delete srvapp;
srvapp = NULL;
}
break; // jump out of our for() loop
int32 count = fAppList.CountItems();
ServerApp *removeApp = NULL;
for (int32 i = 0; i < count; i++) {
ServerApp *app = (ServerApp *)fAppList.ItemAt(i);
if (app != NULL && app->Thread() == thread) {
fAppList.RemoveItem(i);
removeApp = app;
break;
}
}
release_sem(fAppListLock);
if (removeApp != NULL)
removeApp->Quit();
if (fQuitting && count <= 1)
PostMessage(kMsgShutdownServer);
break;
}
case AS_UPDATED_CLIENT_FONTLIST:
{
// received when the client-side global font list has been
// refreshed
fontserver->Lock();
fontserver->FontsUpdated();
fontserver->Unlock();
break;
}
case AS_QUERY_FONTS_CHANGED:
{
// Client application is asking if the font list has changed since
@ -531,50 +529,34 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
BPrivate::PortLink replylink(replyport);
replylink.StartMessage(needs_update ? SERVER_TRUE : SERVER_FALSE);
replylink.Flush();
break;
}
case B_QUIT_REQUESTED:
{
#if TEST_MODE
// Attached Data:
// none
case B_QUIT_REQUESTED:
// We've been asked to quit, so (for now) broadcast to all
// test apps to quit. This situation will occur only when the server
// is compiled as a regular Be application.
fQuitting = true;
BroadcastToAllApps(AS_QUIT_APP);
// we have to wait until *all* threads have finished!
ServerApp *app;
// We now need to process the remaining AS_DELETE_APP messages and
// wait for the kMsgShutdownServer message.
// If an application does not quit as asked, the picasso thread
// will send us this message in 2-3 seconds.
break;
case kMsgShutdownServer:
// let's kill all remaining applications
acquire_sem(fAppListLock);
thread_info tinfo;
for (int32 i = 0; i < fAppList->CountItems(); i++) {
app = (ServerApp*)fAppList->ItemAt(i);
if (!app)
continue;
// Instead of calling wait_for_thread, we will wait a bit, check for the
// thread_id. We will only wait so long, because then the app is probably crashed
// or hung. Seeing that being the case, we'll kill its BApp team and fake the
// quit message
if (get_thread_info(app->MonitorThreadID(), &tinfo)==B_OK) {
bool killteam = true;
for (int32 i = 0; i < fAppList.CountItems(); i++) {
ServerApp *app = (ServerApp*)fAppList.ItemAt(i);
for (int32 j = 0; j < 5; j++) {
snooze(500000); // wait half a second for it to quit
if (get_thread_info(app->MonitorThreadID(), &tinfo) != B_OK) {
killteam = false;
break;
}
}
if (killteam) {
kill_team(app->ClientTeamID());
app->PostMessage(B_QUIT_REQUESTED);
}
}
kill_thread(app->Thread());
kill_team(app->ClientTeam());
}
kill_thread(fPicassoThreadID);
@ -582,15 +564,14 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
release_sem(fAppListLock);
delete gDesktop;
delete fAppList;
delete bitmapmanager;
delete fontserver;
// we are now clear to exit
exit_thread(0);
#endif
break;
}
#endif
case AS_SET_SYSCURSOR_DEFAULTS:
{
// although this isn't pretty, ATM we only have RootLayer.
@ -599,8 +580,10 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
gDesktop->ActiveRootLayer()->GetCursorManager().SetDefaults();
break;
}
default:
// we should never get here.
STRACE(("Server::MainLoop received unexpected code %ld (offset %ld)\n",
code, code - SERVER_TRUE));
break;
}
}
@ -614,31 +597,31 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
while it does its searching.
*/
ServerApp *
AppServer::FindApp(const char *sig)
AppServer::FindApp(const char *signature)
{
if (!sig)
if (!signature)
return NULL;
ServerApp *foundapp=NULL;
acquire_sem(fAppListLock);
for(int32 i=0; i<fAppList->CountItems();i++)
{
foundapp=(ServerApp*)fAppList->ItemAt(i);
if(foundapp && foundapp->Title() == sig)
{
release_sem(fAppListLock);
return foundapp;
ServerApp *foundApp = NULL;
for (int32 i = 0; i < fAppList.CountItems(); i++) {
ServerApp *app = (ServerApp*)fAppList.ItemAt(i);
if (app && !strcasecmp(app->Signature(), signature)) {
foundApp = app;
break;
}
}
release_sem(fAppListLock);
// couldn't find a match
return NULL;
return foundApp;
}
// #pragma mark -
/*!
\brief Send a quick (no attachments) message to all applications
@ -650,18 +633,19 @@ BroadcastToAllApps(const int32 &code)
{
acquire_sem(sAppServer->fAppListLock);
for (int32 i = 0; i < sAppServer->fAppList->CountItems(); i++) {
ServerApp *app = (ServerApp *)sAppServer->fAppList->ItemAt(i);
for (int32 i = 0; i < sAppServer->fAppList.CountItems(); i++) {
ServerApp *app = (ServerApp *)sAppServer->fAppList.ItemAt(i);
if (!app)
{ printf("PANIC in Broadcast()\n"); continue; }
if (!app) {
printf("PANIC in Broadcast()\n");
continue;
}
app->PostMessage(code);
}
release_sem(sAppServer->fAppListLock);
}
// #pragma mark -
/*!
\brief Entry function to run the entire server
@ -677,7 +661,9 @@ main(int argc, char** argv)
return -1;
srand(real_time_clock_usecs());
AppServer app_server;
app_server.Run();
AppServer server;
server.Run();
return 0;
}

View File

@ -51,7 +51,8 @@ public:
static int32 PicassoThread(void *data);
thread_id Run(void);
void MainLoop(void);
void PostMessage(int32 code);
void DispatchMessage(int32 code, BPrivate::PortLink &link);
ServerApp* FindApp(const char *sig);
@ -64,10 +65,10 @@ private:
port_id fMessagePort;
port_id fServerInputPort;
volatile bool fQuittingServer;
BList *fAppList;
volatile bool fQuitting;
BList fAppList;
thread_id fPicassoThreadID;
thread_id fISThreadID;

View File

@ -268,7 +268,7 @@ Desktop::AddWinBorder(WinBorder *winBorder)
for (int32 i = 0; i < count; i++) {
wb = (WinBorder *)fWinBorderList.ItemAt(i);
if (wb->App()->ClientTeamID() == winBorder->App()->ClientTeamID()
if (wb->App()->ClientTeam() == winBorder->App()->ClientTeam()
&& wb->Feel() == feelToLookFor) {
// R2: RootLayer comparison is needed.
feel == B_NORMAL_WINDOW_FEEL ?
@ -322,7 +322,7 @@ Desktop::RemoveWinBorder(WinBorder *winBorder)
wb = (WinBorder*)fWinBorderList.ItemAt(i);
if (wb->Feel() == B_NORMAL_WINDOW_FEEL
&& wb->App()->ClientTeamID() == winBorder->App()->ClientTeamID()) {
&& wb->App()->ClientTeam() == winBorder->App()->ClientTeam()) {
// R2: RootLayer comparison is needed. We'll see.
wb->fSubWindowList.RemoveItem(winBorder);
}
@ -368,7 +368,7 @@ Desktop::AddWinBorderToSubset(WinBorder *winBorder, WinBorder *toWinBorder)
if ((winBorder->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL
|| winBorder->Feel() == B_MODAL_SUBSET_WINDOW_FEEL)
&& toWinBorder->Feel() == B_NORMAL_WINDOW_FEEL
&& toWinBorder->App()->ClientTeamID() == winBorder->App()->ClientTeamID()
&& toWinBorder->App()->ClientTeam() == winBorder->App()->ClientTeam()
&& !toWinBorder->fSubWindowList.HasItem(winBorder)) {
// add to normal_window's list
toWinBorder->fSubWindowList.AddWinBorder(winBorder);
@ -442,7 +442,7 @@ Desktop::FindWinBorderByServerWindowTokenAndTeamID(int32 token, team_id teamID)
Lock();
for (int32 i = 0; (wb = (WinBorder *)fWinBorderList.ItemAt(i)); i++) {
if (wb->Window()->ClientToken() == token
&& wb->Window()->ClientTeamID() == teamID)
&& wb->Window()->ClientTeam() == teamID)
break;
}
Unlock();

View File

@ -63,6 +63,10 @@
# define FTRACE(x) ;
#endif
static const uint32 kMsgAppQuit = 'appQ';
/*!
\brief Constructor
\param sendport port ID for the BApplication which will receive the ServerApp's messages
@ -70,21 +74,17 @@
\param fSignature NULL-terminated string which contains the BApplication's
MIME fSignature.
*/
ServerApp::ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort,
team_id clientTeamID, int32 handlerID, const char* signature)
ServerApp::ServerApp(port_id clientReplyPort, port_id clientLooperPort,
team_id clientTeam, int32 handlerID, const char* signature)
:
fClientAppPort(sendport),
fMessagePort(rcvport),
fLockSem(-1),
fClientReplyPort(clientReplyPort),
fMessagePort(-1),
fClientLooperPort(clientLooperPort),
fSignature(signature),
fMonitorThreadID(-1),
fClientTeamID(clientTeamID),
fLink(fClientAppPort, fMessagePort),
fSWindowList(new BList()),
fBitmapList(new BList()),
fPictureList(new BList()),
fThread(-1),
fClientTeam(clientTeam),
fAppCursor(NULL),
fLockSem(create_sem(1, "ServerApp sem")),
fCursorHidden(false),
fIsActive(false),
//fHandlerToken(handlerID),
@ -92,7 +92,25 @@ ServerApp::ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort
fQuitting(false)
{
if (fSignature == "")
fSignature = "application/x-vnd.NULL-application-signature";
fSignature = "application/no-signature";
fLockSem = create_sem(1, Signature());
if (fLockSem < B_OK)
return;
fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, Signature());
if (fMessagePort < B_OK)
return;
fLink.SetSenderPort(fClientReplyPort);
fLink.SetReceiverPort(fMessagePort);
// we let the application own the port, so that we get aware when it's gone
if (set_port_owner(fMessagePort, clientTeam) < B_OK) {
delete_port(fMessagePort);
fMessagePort = -1;
return;
}
// although this isn't pretty, ATM we have only one RootLayer.
// there should be a way that this ServerApp be attached to a particular
@ -102,13 +120,11 @@ ServerApp::ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort
if (defaultCursor) {
fAppCursor = new ServerCursor(defaultCursor);
fAppCursor->SetOwningTeam(fClientTeamID);
fAppCursor->SetOwningTeam(fClientTeam);
}
Run();
STRACE(("ServerApp %s:\n", fSignature.String()));
STRACE(("\tBApp port: %ld\n", fClientAppPort));
STRACE(("\tBApp port: %ld\n", fClientReplyPort));
STRACE(("\tReceiver port: %ld\n", fMessagePort));
}
@ -117,67 +133,119 @@ ServerApp::ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort
ServerApp::~ServerApp(void)
{
STRACE(("*ServerApp %s:~ServerApp()\n",fSignature.String()));
fQuitting = true;
for (int32 i = 0; i< fBitmapList->CountItems(); i++) {
delete static_cast<ServerBitmap *>(fBitmapList->ItemAt(i));
}
delete fBitmapList;
for (int32 i = 0; i < fPictureList->CountItems(); i++) {
delete static_cast<ServerPicture *>(fPictureList->ItemAt(i));
if (!fQuitting)
CRITICAL("ServerApp: destructor called after Run()!\n");
// first, make sure our monitor thread doesn't
for (int32 i = 0; i < fBitmapList.CountItems(); i++) {
delete static_cast<ServerBitmap *>(fBitmapList.ItemAt(i));
}
for (int32 i = 0; i < fPictureList.CountItems(); i++) {
delete static_cast<ServerPicture *>(fPictureList.ItemAt(i));
}
delete fPictureList;
// This shouldn't be necessary -- all cursors owned by the app
// should be cleaned up by RemoveAppCursors
// if(fAppCursor)
// delete fAppCursor;
// delete fAppCursor;
// although this isn't pretty, ATM we have only one RootLayer.
// there should be a way that this ServerApp be attached to a particular
// RootLayer to know which RootLayer's cursor to modify.
gDesktop->ActiveRootLayer()->GetCursorManager().RemoveAppCursors(fClientTeamID);
gDesktop->ActiveRootLayer()->GetCursorManager().RemoveAppCursors(fClientTeam);
delete_sem(fLockSem);
STRACE(("#ServerApp %s:~ServerApp()\n", fSignature.String()));
// TODO: Is this the right place for this ?
// From what I've understood, this is the port created by
// the BApplication (?), but if I delete it in there, GetNextMessage()
// in the MonitorApp thread never returns. Cleanup.
delete_port(fMessagePort);
status_t dummyStatus;
wait_for_thread(fMonitorThreadID, &dummyStatus);
delete fSharedMem;
STRACE(("ServerApp %s::~ServerApp(): Exiting\n", fSignature.String()));
}
/*!
\brief Checks if the application was initialized correctly
*/
status_t
ServerApp::InitCheck()
{
if (fMessagePort < B_OK)
return fMessagePort;
if (fClientReplyPort < B_OK)
return fClientReplyPort;
if (fLockSem < B_OK)
return fLockSem;
return B_OK;
}
/*!
\brief Starts the ServerApp monitoring for messages
\return false if the application couldn't start, true if everything went OK.
*/
bool
ServerApp::Run(void)
ServerApp::Run()
{
fQuitting = false;
// Unlike a BApplication, a ServerApp is *supposed* to return immediately
// when its Run() function is called.
fMonitorThreadID = spawn_thread(MonitorApp, fSignature.String(), B_NORMAL_PRIORITY, this);
if (fMonitorThreadID < B_OK)
fThread = spawn_thread(_message_thread, fSignature.String(), B_NORMAL_PRIORITY, this);
if (fThread < B_OK)
return false;
return resume_thread(fMonitorThreadID) == B_OK;
// Let's tell the client how to talk with us
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<int32>(fMessagePort);
fLink.Flush();
if (resume_thread(fThread) != B_OK) {
fQuitting = true;
kill_thread(fThread);
fThread = -1;
return false;
}
return true;
}
/*!
\brief This quits the application and deletes it. You're not supposed
to call its destructor directly.
At the point you're calling this method, the application should already
be removed from the application list.
*/
void
ServerApp::Quit()
{
if (fThread < B_OK) {
delete this;
return;
}
// execute application deletion in the message looper thread
fQuitting = true;
BPrivate::LinkSender link(fMessagePort);
link.StartMessage(kMsgAppQuit);
link.Flush();
send_data(fThread, 'QUIT', NULL, 0);
}
/*!
\brief Pings the target app to make sure it's still working
\return true if target is still "alive" and false if "He's dead, Jim."
"But that's impossible..."
This function is called by the app_server thread to ensure that
the target app still exists. We do this not by sending a message
but by calling get_port_info. We don't want to send ping messages
@ -187,13 +255,13 @@ ServerApp::Run(void)
tell the app_server to delete the respective ServerApp.
*/
bool
ServerApp::PingTarget(void)
ServerApp::PingTarget()
{
team_info tinfo;
if (get_team_info(fClientTeamID, &tinfo) == B_BAD_TEAM_ID) {
team_info info;
if (get_team_info(fClientTeam, &info) != B_OK) {
BPrivate::LinkSender link(gAppServerPort);
link.StartMessage(AS_DELETE_APP);
link.Attach(&fMonitorThreadID, sizeof(thread_id));
link.Attach(&fThread, sizeof(thread_id));
link.Flush();
return false;
}
@ -260,34 +328,50 @@ ServerApp::SetAppCursor(void)
/*!
\brief The thread function ServerApps use to monitor messages
\param data Pointer to the thread's ServerApp object
\return Throwaway value - always 0
*/
int32
ServerApp::MonitorApp(void *data)
ServerApp::_message_thread(void *_app)
{
ServerApp *app = (ServerApp *)_app;
app->_MessageLooper();
return 0;
}
/*!
\brief The thread function ServerApps use to monitor messages
*/
void
ServerApp::_MessageLooper()
{
// Message-dispatching loop for the ServerApp
ServerApp *app = (ServerApp *)data;
BPrivate::LinkReceiver &reader = app->fLink.Receiver();
BPrivate::LinkReceiver &receiver = fLink.Receiver();
int32 code;
status_t err = B_OK;
while (!app->fQuitting) {
STRACE(("info: ServerApp::MonitorApp listening on port %ld.\n", app->fMessagePort));
err = reader.GetNextMessage(code, B_INFINITE_TIMEOUT);
if (err < B_OK) {
STRACE(("ServerApp::MonitorApp(): GetNextMessage returned %s\n", strerror(err)));
while (!fQuitting) {
STRACE(("info: ServerApp::_MessageLooper() listening on port %ld.\n", fMessagePort));
err = receiver.GetNextMessage(code, B_INFINITE_TIMEOUT);
if (err < B_OK || code == B_QUIT_REQUESTED) {
STRACE(("ServerApp: application seems to be gone...\n"));
// ToDo: this should kill the app, but it doesn't work
// Tell the app_server to quit us
BPrivate::LinkSender link(gAppServerPort);
link.StartMessage(AS_DELETE_APP);
link.Attach(&app->fMonitorThreadID, sizeof(thread_id));
link.Attach<thread_id>(Thread());
link.Flush();
break;
}
switch (code) {
case kMsgAppQuit:
// we receive this from our destructor on quit
fQuitting = true;
break;
case AS_CREATE_WINDOW:
{
// Create the ServerWindow to node monitor a new OBWindow
@ -312,22 +396,21 @@ ServerApp::MonitorApp(void *data)
port_id looperPort = -1;
char *title = NULL;
reader.Read<BRect>(&frame);
reader.Read<uint32>(&look);
reader.Read<uint32>(&feel);
reader.Read<uint32>(&flags);
reader.Read<uint32>(&wkspaces);
reader.Read<int32>(&token);
reader.Read<port_id>(&sendPort);
reader.Read<port_id>(&looperPort);
if (reader.ReadString(&title) != B_OK)
receiver.Read<BRect>(&frame);
receiver.Read<uint32>(&look);
receiver.Read<uint32>(&feel);
receiver.Read<uint32>(&flags);
receiver.Read<uint32>(&wkspaces);
receiver.Read<int32>(&token);
receiver.Read<port_id>(&sendPort);
receiver.Read<port_id>(&looperPort);
if (receiver.ReadString(&title) != B_OK)
break;
STRACE(("ServerApp %s: Got 'New Window' message, trying to do smething...\n",app->fSignature.String()));
STRACE(("ServerApp %s: Got 'New Window' message, trying to do smething...\n", Signature()));
// ServerWindow constructor will reply with port_id of a newly created port
ServerWindow *sw = NULL;
sw = new ServerWindow(title, app, sendPort, looperPort, token);
ServerWindow *sw = new ServerWindow(title, this, sendPort, looperPort, token);
sw->Init(frame, look, feel, flags, wkspaces);
STRACE(("\nServerApp %s: New Window %s (%.1f,%.1f,%.1f,%.1f)\n",
@ -337,46 +420,38 @@ ServerApp::MonitorApp(void *data)
free(title);
break;
}
case AS_QUIT_APP:
{
// This message is received only when the app_server is asked to shut down in
// test/debug mode. Of course, if we are testing while using AccelerantDriver, we do
// NOT want to shut down client applications. The server can be quit o in this fashion
// through the driver's interface, such as closing the ViewDriver's window.
STRACE(("ServerApp %s:Server shutdown notification received\n",
app->fSignature.String()));
STRACE(("ServerApp %s:Server shutdown notification received\n", Signature()));
// If we are using the real, accelerated version of the
// DisplayDriver, we do NOT want the user to be able shut down
// the server. The results would NOT be pretty
#if TEST_MODE
BMessage pleaseQuit(B_QUIT_REQUESTED);
app->SendMessageToClient(&pleaseQuit);
SendMessageToClient(&pleaseQuit);
#endif
break;
}
case B_QUIT_REQUESTED:
{
STRACE(("ServerApp %s: B_QUIT_REQUESTED\n",app->fSignature.String()));
// Our BApplication sent us this message when it quit.
// We need to ask the app_server to delete ourself.
BPrivate::LinkSender sender(gAppServerPort);
sender.StartMessage(AS_DELETE_APP);
sender.Attach(&app->fMonitorThreadID, sizeof(thread_id));
sender.Flush();
break;
}
default:
STRACE(("ServerApp %s: Got a Message to dispatch\n", app->fSignature.String()));
app->DispatchMessage(code, reader);
STRACE(("ServerApp %s: Got a Message to dispatch\n", Signature()));
_DispatchMessage(code, receiver);
break;
}
}
return 0;
// Quit() will send us a message; we're handling the exiting procedure
thread_id sender;
receive_data(&sender, NULL, 0);
delete this;
}
@ -390,7 +465,7 @@ ServerApp::MonitorApp(void *data)
matter of casting and incrementing an index variable to access them.
*/
void
ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
{
LayerData ld;
@ -404,9 +479,8 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
ServerWindow *win;
BMessage msg(_COLORS_UPDATED);
for(int32 i=0; i<fSWindowList->CountItems(); i++)
{
win=(ServerWindow*)fSWindowList->ItemAt(i);
for(int32 i = 0; i < fWindowList.CountItems(); i++) {
win=(ServerWindow*)fWindowList.ItemAt(i);
win->GetWinBorder()->UpdateColors();
win->SendMessageToClient(AS_UPDATE_COLORS, msg);
}
@ -444,25 +518,24 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
size_t msgsize;
area_info ai;
int8 *msgpointer;
link.Read<area_id>(&area);
link.Read<size_t>(&offset);
link.Read<size_t>(&msgsize);
// Part sanity check, part get base pointer :)
if (get_area_info(area, &ai) < B_OK)
break;
msgpointer = (int8*)ai.address + offset;
RAMLinkMsgReader mlink(msgpointer);
DispatchMessage(mlink.Code(), mlink);
_DispatchMessage(mlink.Code(), mlink);
// This is a very special case in the sense that when ServerMemIO is used for this
// purpose, it will be set to NOT automatically free the memory which it had
// requested. This is the server's job once the message has been dispatched.
fSharedMem->ReleaseBuffer(msgpointer);
break;
}
case AS_ACQUIRE_SERVERMEM:
@ -536,14 +609,11 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
{
STRACE(("ServerApp %s: Received decorator update notification\n",fSignature.String()));
ServerWindow *win;
for(int32 i = 0; i < fSWindowList->CountItems(); i++)
{
win = (ServerWindow*)fSWindowList->ItemAt(i);
win->Lock();
const_cast<WinBorder *>(win->GetWinBorder())->UpdateDecorator();
win->Unlock();
for (int32 i = 0; i < fWindowList.CountItems(); i++) {
ServerWindow *window = (ServerWindow*)fWindowList.ItemAt(i);
window->Lock();
const_cast<WinBorder *>(window->GetWinBorder())->UpdateDecorator();
window->Unlock();
}
break;
}
@ -652,7 +722,7 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
fSignature.String(), frame.Width(), frame.Height()));
if (bitmap) {
fBitmapList->AddItem(bitmap);
fBitmapList.AddItem(bitmap);
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<int32>(bitmap->Token());
fLink.Attach<int32>(bitmap->Area());
@ -683,7 +753,7 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
if (bitmap) {
STRACE(("ServerApp %s: Deleting Bitmap %ld\n", fSignature.String(), id));
fBitmapList->RemoveItem(bitmap);
fBitmapList.RemoveItem(bitmap);
bitmapmanager->DeleteBitmap(bitmap);
fLink.StartMessage(SERVER_TRUE);
} else
@ -814,7 +884,7 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
gDesktop->ActiveRootLayer()->GetCursorManager().DeleteCursor(fAppCursor->ID());
fAppCursor = new ServerCursor(cdata);
fAppCursor->SetOwningTeam(fClientTeamID);
fAppCursor->SetOwningTeam(fClientTeam);
fAppCursor->SetAppSignature(fSignature.String());
gDesktop->ActiveRootLayer()->GetCursorManager().AddCursor(fAppCursor);
// although this isn't pretty, ATM we have only one RootLayer.
@ -862,7 +932,7 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
link.Read(cursorData, sizeof(cursorData));
fAppCursor = new ServerCursor(cursorData);
fAppCursor->SetOwningTeam(fClientTeamID);
fAppCursor->SetOwningTeam(fClientTeam);
fAppCursor->SetAppSignature(fSignature.String());
// although this isn't pretty, ATM we have only one RootLayer.
// there should be a way that this ServerApp be attached to a particular
@ -1849,7 +1919,7 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
int32
ServerApp::CountBitmaps() const
{
return fBitmapList ? fBitmapList->CountItems() : 0;
return fBitmapList.CountItems();
}
@ -1861,13 +1931,12 @@ ServerApp::CountBitmaps() const
ServerBitmap *
ServerApp::FindBitmap(int32 token) const
{
ServerBitmap *bitmap;
for (int32 i = 0; i < fBitmapList->CountItems(); i++) {
bitmap = static_cast<ServerBitmap *>(fBitmapList->ItemAt(i));
for (int32 i = 0; i < fBitmapList.CountItems(); i++) {
ServerBitmap *bitmap = static_cast<ServerBitmap *>(fBitmapList.ItemAt(i));
if (bitmap && bitmap->Token() == token)
return bitmap;
}
return NULL;
}
@ -1875,16 +1944,15 @@ ServerApp::FindBitmap(int32 token) const
int32
ServerApp::CountPictures() const
{
return fPictureList ? fPictureList->CountItems() : 0;
return fPictureList.CountItems();
}
ServerPicture *
ServerApp::FindPicture(int32 token) const
{
ServerPicture *picture;
for (int32 i = 0; i < fPictureList->CountItems(); i++) {
picture = static_cast<ServerPicture *>(fPictureList->ItemAt(i));
for (int32 i = 0; i < fPictureList.CountItems(); i++) {
ServerPicture *picture = static_cast<ServerPicture *>(fPictureList.ItemAt(i));
if (picture && picture->GetToken() == token)
return picture;
}
@ -1894,15 +1962,15 @@ ServerApp::FindPicture(int32 token) const
team_id
ServerApp::ClientTeamID() const
ServerApp::ClientTeam() const
{
return fClientTeamID;
return fClientTeam;
}
thread_id
ServerApp::MonitorThreadID() const
ServerApp::Thread() const
{
return fMonitorThreadID;
return fThread;
}

View File

@ -1,33 +1,18 @@
//------------------------------------------------------------------------------
// Copyright (c) 2001-2005, Haiku, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: ServerApp.h
// Author: DarkWyrm <bpmagic@columbus.rr.com>
// Adi Oanca <adioanca@myrealbox.com>
// Description: Server-side BApplication counterpart
//
//------------------------------------------------------------------------------
/*
* Copyright 2001-2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Adrian Oanca <adioanca@cotty.iren.ro>
* Stephan Aßmus <superstippi@gmx.de>
* Stefano Ceccherini (burton666@libero.it)
* Axel Dörfler, axeld@pinc-software.de
*/
#ifndef _SERVERAPP_H_
#define _SERVERAPP_H_
#include <OS.h>
#include <String.h>
#include <PortLink.h>
@ -52,11 +37,14 @@ namespace BPrivate {
*/
class ServerApp {
public:
ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort,
ServerApp(port_id clientAppPort, port_id clientLooperPort,
team_id clientTeamID, int32 handlerID, const char* signature);
virtual ~ServerApp(void);
bool Run(void);
~ServerApp();
status_t InitCheck();
bool Run();
void Quit();
/*
TODO: These aren't even implemented...
void Lock(void);
@ -69,19 +57,19 @@ public:
*/
bool IsActive(void) const { return fIsActive; }
void Activate(bool value);
bool PingTarget(void);
void PostMessage(int32 code);
void SendMessageToClient( const BMessage* msg ) const;
void SetAppCursor(void);
team_id ClientTeamID() const;
thread_id MonitorThreadID() const;
const char *Title() const { return fSignature.String(); }
team_id ClientTeam() const;
thread_id Thread() const;
const char *Signature() const { return fSignature.String(); }
int32 CountBitmaps() const;
ServerBitmap *FindBitmap(int32 token) const;
@ -93,12 +81,16 @@ public:
SubWindowList fAppSubWindowList;
private:
void DispatchMessage(int32 code, BPrivate::LinkReceiver &link);
void _DispatchMessage(int32 code, BPrivate::LinkReceiver &link);
void _MessageLooper();
static int32 MonitorApp(void *data);
static int32 _message_thread(void *data);
// TODO: Not used.
sem_id fLockSem;
// our BApplication's event port
port_id fClientAppPort;
port_id fClientReplyPort;
// port we receive messages from our BApplication
port_id fMessagePort;
// TODO: find out why there is both the app port and the looper port. Do
@ -109,23 +101,20 @@ private:
BString fSignature;
thread_id fMonitorThreadID;
team_id fClientTeamID;
thread_id fThread;
team_id fClientTeam;
BPrivate::PortLink fLink;
// TODO:
// - Are really Bitmaps and Pictures stored per application and not globally ?
// - As we reference these stuff by token, what about putting them in hash tables ?
BList *fSWindowList,
*fBitmapList,
*fPictureList;
BList fWindowList;
BList fBitmapList;
BList fPictureList;
ServerCursor *fAppCursor;
// TODO: Not used.
sem_id fLockSem;
bool fCursorHidden;
bool fIsActive;

View File

@ -1,31 +1,15 @@
//------------------------------------------------------------------------------
// Copyright (c) 2001-2005, Haiku, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: ServerWindow.cpp
// Author: DarkWyrm <bpmagic@columbus.rr.com>
// Adi Oanca <adioanca@cotty.iren.ro>
// Stephan Aßmus <superstippi@gmx.de>
// Description: Shadow BWindow class
//
//------------------------------------------------------------------------------
/*
* Copyright 2001-2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Adrian Oanca <adioanca@cotty.iren.ro>
* Stephan Aßmus <superstippi@gmx.de>
* Stefano Ceccherini (burton666@libero.it)
* Axel Dörfler, axeld@pinc-software.de
*/
#include <AppDefs.h>
#include <Rect.h>
@ -75,7 +59,6 @@
# define DTRACE(x) ;
#endif
// #pragma mark -
/*!
\brief Constructor
@ -83,11 +66,11 @@
Does a lot of stuff to set up for the window - new decorator, new winborder, spawn a
monitor thread.
*/
ServerWindow::ServerWindow(const char *string, ServerApp *winapp,
port_id winport, port_id looperPort, int32 handlerID)
: fServerApp(winapp),
// fClientWinPort is the port to which the app awaits messages from the server
fClientWinPort(winport),
ServerWindow::ServerWindow(const char *string, ServerApp *app,
port_id clientPort, port_id looperPort, int32 handlerID)
:
fServerApp(app),
fClientReplyPort(clientPort),
fClientLooperPort(looperPort),
fClientViewsWithInvalidCoords(B_VIEW_RESIZED),
fHandlerToken(handlerID)
@ -100,14 +83,14 @@ ServerWindow::ServerWindow(const char *string, ServerApp *winapp,
} else
strcpy(fName, "Unnamed Window");
fClientTeamID = winapp->ClientTeamID();
fClientTeam = app->ClientTeam();
fWinBorder = NULL;
fCurrentLayer = NULL;
// fMessagePort is the port to which the app sends messages for the server
fMessagePort = create_port(30, fName);
fMsgSender = new BPrivate::LinkSender(fClientWinPort);
fMsgSender = new BPrivate::LinkSender(fClientReplyPort);
fMsgReceiver = new BPrivate::LinkReceiver(fMessagePort);
// Send a reply to our window - it is expecting fMessagePort port.
@ -124,15 +107,15 @@ ServerWindow::Init(BRect frame, uint32 wlook,
uint32 wfeel, uint32 wflags, uint32 wwksindex)
{
char name[60];
snprintf(name, sizeof(name), "%ld: %s", fClientTeamID, fName);
snprintf(name, sizeof(name), "%ld: %s", fClientTeam, fName);
fWinBorder = new WinBorder(frame, name, wlook, wfeel, wflags,
wwksindex, this, gDesktop->GetDisplayDriver());
// Spawn our message-monitoring thread
fMonitorThreadID = spawn_thread(MonitorWin, fName, B_NORMAL_PRIORITY, this);
if (fMonitorThreadID >= B_OK)
resume_thread(fMonitorThreadID);
fThread = spawn_thread(MonitorWin, fName, B_NORMAL_PRIORITY, this);
if (fThread >= B_OK)
resume_thread(fThread);
}

View File

@ -1,29 +1,14 @@
//------------------------------------------------------------------------------
// Copyright (c) 2001-2005, Haiku, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: ServerWindow.h
// Author: DarkWyrm <bpmagic@columbus.rr.com>
// Description: Shadow BWindow class
//
//------------------------------------------------------------------------------
/*
* Copyright 2001-2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Adrian Oanca <adioanca@cotty.iren.ro>
* Stephan Aßmus <superstippi@gmx.de>
* Stefano Ceccherini (burton666@libero.it)
* Axel Dörfler, axeld@pinc-software.de
*/
#ifndef _SERVERWIN_H_
#define _SERVERWIN_H_
@ -103,16 +88,16 @@ public:
{ return fClientViewsWithInvalidCoords; };
// to who we belong. who do we own. our title.
inline ServerApp* App(void) const { return fServerApp; }
inline const WinBorder* GetWinBorder(void) const { return fWinBorder; }
inline const char* Title(void) const { return fName; }
inline ServerApp* App() const { return fServerApp; }
inline const WinBorder* GetWinBorder() const { return fWinBorder; }
inline const char* Title() const { return fName; }
// related thread/team_id(s).
inline team_id ClientTeamID(void) const { return fClientTeamID; }
inline thread_id ThreadID(void) const { return fMonitorThreadID;}
inline team_id ClientTeam() const { return fClientTeam; }
inline thread_id Thread() const { return fThread; }
// server "private" - try not to use.
inline int32 ClientToken(void) const { return fHandlerToken; }
inline int32 ClientToken() const { return fHandlerToken; }
// ToDo: public??
SubWindowList fSubWindowList;
@ -143,15 +128,15 @@ private:
bool inverse,
BPoint where);
char fName[50];
ServerApp* fServerApp;
WinBorder* fWinBorder;
team_id fClientTeamID;
thread_id fMonitorThreadID;
team_id fClientTeam;
thread_id fThread;
port_id fMessagePort;
port_id fClientWinPort;
port_id fClientReplyPort;
port_id fClientLooperPort;
BPrivate::LinkReceiver* fMsgReceiver;

View File

@ -369,41 +369,35 @@ STRACE(("Wks(%ld)::MoveToBack(%s) \n", fID, newLast? newLast->GetName(): "NULL")
return false;
// this is a modal app
if (newLast->App()->fAppSubWindowList.HasItem(newLast))
{
ListData *before;
if (newLast->App()->fAppSubWindowList.HasItem(newLast)) {
ListData* before;
// remove now to properly place later
RemoveItem(newLastItem);
while (cursor)
{
while (cursor) {
if (!cursor->layerPtr->IsHidden()
&& cursor->layerPtr->Level() > B_SYSTEM_LAST
&& cursor->layerPtr->App()->ClientTeamID() == newLast->App()->ClientTeamID())
{
&& cursor->layerPtr->App()->ClientTeam() == newLast->App()->ClientTeam())
break;
}
cursor = cursor->upperItem;
}
if (cursor)
before = cursor->lowerItem;
else
before = fTopItem;
InsertItem(newLastItem, before);
}
// this is a modal subset
else
{
} else {
// this is a modal subset
// this subset modal is visible, it means its main window must be visible. search for it.
ListData *mainWindowItem, *before;
int32 indexThis = 0, indexCursor;
// search by going deep
while(cursor)
{
while (cursor) {
if (cursor->layerPtr->Level() == B_NORMAL && !cursor->layerPtr->IsHidden()
&& (indexThis = cursor->layerPtr->fSubWindowList.IndexOf(newLast)) >= 0)
break;
@ -416,14 +410,13 @@ STRACE(("Wks(%ld)::MoveToBack(%s) \n", fID, newLast? newLast->GetName(): "NULL")
RemoveItem(newLastItem);
// good. found our main window. now go up and properly place.
mainWindowItem = cursor;
before = cursor->lowerItem;
mainWindowItem = cursor;
before = cursor->lowerItem;
cursor = cursor->lowerItem;
while(cursor)
{
cursor = cursor->lowerItem;
while (cursor) {
if (cursor->layerPtr->Level() == B_MODAL_APP && !cursor->layerPtr->IsHidden()
&& cursor->layerPtr->App()->ClientTeamID() == newLast->App()->ClientTeamID())
&& cursor->layerPtr->App()->ClientTeam() == newLast->App()->ClientTeam())
{
indexCursor = mainWindowItem->layerPtr->fSubWindowList.IndexOf(cursor->layerPtr);
if (indexCursor >= 0)
@ -810,7 +803,7 @@ STRACE(("W(%ld)::ShowWinBorder(%s) \n", fID, winBorder? winBorder->GetName(): "N
// take only application's modals
tempList.AddList(&winBorder->App()->fAppSubWindowList);
if (fFrontItem
&& fFrontItem->layerPtr->App()->ClientTeamID() == winBorder->App()->ClientTeamID())
&& fFrontItem->layerPtr->App()->ClientTeam() == winBorder->App()->ClientTeam())
userBusy = false;
}
// SUBSET modal
@ -1217,47 +1210,46 @@ void Workspace::PrintItem(ListData *item) const
/*
Insert item in the top-bottom direction.
*/
void Workspace::InsertItem(ListData *item, ListData *before)
void
Workspace::InsertItem(ListData *item, ListData *before)
{
// insert before one other item;
if(before)
{
if(before->upperItem)
before->upperItem->lowerItem = item;
item->upperItem = before->upperItem;
item->lowerItem = before;
before->upperItem = item;
if (before) {
if (before->upperItem)
before->upperItem->lowerItem = item;
if(fTopItem == before)
item->upperItem = before->upperItem;
item->lowerItem = before;
before->upperItem = item;
if (fTopItem == before)
fTopItem = item;
}
else
{
} else {
// insert item at the end.
item->upperItem = fBottomItem;
if(fBottomItem)
item->upperItem = fBottomItem;
if (fBottomItem)
fBottomItem->lowerItem = item;
fBottomItem = item;
fBottomItem = item;
if(!fTopItem)
fTopItem = item;
if (!fTopItem)
fTopItem = item;
}
}
//----------------------------------------------------------------------------------
void Workspace::RemoveItem(ListData *item)
void
Workspace::RemoveItem(ListData *item)
{
if(!item)
if (!item)
return;
if(fBottomItem == item)
if (fBottomItem == item)
fBottomItem = item->upperItem;
else
item->lowerItem->upperItem = item->upperItem;
if(fTopItem == item)
if (fTopItem == item)
fTopItem = item->lowerItem;
else
item->upperItem->lowerItem = item->lowerItem;
@ -1267,23 +1259,22 @@ void Workspace::RemoveItem(ListData *item)
item->upperItem = NULL;
item->lowerItem = NULL;
if(fFocusItem == item)
if (fFocusItem == item)
fFocusItem = NULL;
if(fFrontItem == item)
if (fFrontItem == item)
fFrontItem = NULL;
}
//----------------------------------------------------------------------------------
ListData *Workspace::HasItem(const ListData *item, int32 *index) const
ListData*
Workspace::HasItem(const ListData *item, int32 *index) const
{
int32 idx = 0;
ListData *itemX;
int32 idx = 0;
ListData* itemX;
for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem)
{
if(item == itemX)
for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) {
if (item == itemX)
break;
idx++;
@ -1295,16 +1286,15 @@ ListData *Workspace::HasItem(const ListData *item, int32 *index) const
return itemX;
}
//----------------------------------------------------------------------------------
ListData* Workspace::HasItem(const WinBorder *layer, int32 *index) const
ListData*
Workspace::HasItem(const WinBorder *layer, int32 *index) const
{
int32 idx = 0;
ListData *itemX;
for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem)
{
if(layer == itemX->layerPtr)
for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) {
if (layer == itemX->layerPtr)
break;
idx++;
@ -1316,62 +1306,58 @@ ListData* Workspace::HasItem(const WinBorder *layer, int32 *index) const
return itemX;
}
//----------------------------------------------------------------------------------
/*!
\brief Returns the index of the specified item starting from the back-most window.
*/
int32 Workspace::IndexOf(const ListData *item) const
int32
Workspace::IndexOf(const ListData *item) const
{
if (!item)
return -1;
int32 index = 0;
for (ListData *itemX = fTopItem; itemX != NULL; itemX = itemX->lowerItem)
{
if(itemX->layerPtr == item->layerPtr)
int32 index = 0;
for (ListData *itemX = fTopItem; itemX != NULL; itemX = itemX->lowerItem) {
if (itemX->layerPtr == item->layerPtr)
return index;
index++;
}
return -1;
}
inline
bool Workspace::placeToBack(ListData *newLast)
{
int32 level = newLast->layerPtr->Level();
ListData *cursor = newLast->upperItem;
switch(level)
{
inline bool
Workspace::placeToBack(ListData *newLast)
{
int32 level = newLast->layerPtr->Level();
ListData* cursor = newLast->upperItem;
switch (level) {
case B_FLOATING_ALL:
case B_FLOATING_APP:
{
int32 count = 0;
while (cursor && cursor->layerPtr->Level() == level)
{
int32 count = 0;
while (cursor && cursor->layerPtr->Level() == level) {
if (!cursor->layerPtr->IsHidden())
count++;
cursor = cursor->upperItem;
cursor = cursor->upperItem;
}
// we're already the last floating window
if (count == 0)
return false;
else
{
bool changeFocus = false;
else {
bool changeFocus = false;
if (fFocusItem == newLast)
changeFocus = true;
if (changeFocus)
{
ListData *cursor = newLast->upperItem;
while ( cursor
&& ( cursor->layerPtr->IsHidden()
|| cursor->layerPtr->WindowFlags() & B_AVOID_FOCUS)
&& cursor->layerPtr->Level() == level)
{
if (changeFocus) {
ListData* cursor = newLast->upperItem;
while (cursor
&& (cursor->layerPtr->IsHidden()
|| cursor->layerPtr->WindowFlags() & B_AVOID_FOCUS)
&& cursor->layerPtr->Level() == level) {
cursor = cursor->upperItem;
}
@ -1386,24 +1372,21 @@ bool Workspace::placeToBack(ListData *newLast)
return true;
}
break;
}
break;
case B_NORMAL:
{
int32 count = 0;
int32 cursorLevel;
while(cursor)
{
int32 count = 0;
int32 cursorLevel;
while (cursor) {
cursorLevel = cursor->layerPtr->Level();
if (cursorLevel == B_MODAL_APP)
cursorLevel = B_NORMAL;
if (cursorLevel < level)
{
if (cursorLevel < level) {
break;
}
else
{
} else {
count++;
cursor = cursor->upperItem;
}
@ -1412,16 +1395,15 @@ bool Workspace::placeToBack(ListData *newLast)
// we're already the last normal window
if (count == 0)
return false;
else
{
else {
RemoveItem(newLast);
InsertItem(newLast, cursor? cursor->lowerItem: fTopItem);
return true;
}
break;
}
break;
}
return false;
}
@ -1429,7 +1411,8 @@ bool Workspace::placeToBack(ListData *newLast)
/*!
\brief Based on it's WinBorder type, places this item in front as it is possible.
*/
void Workspace::placeInFront(ListData *item, const bool userBusy)
void
Workspace::placeInFront(ListData *item, const bool userBusy)
{
if (!item)
return;
@ -1483,11 +1466,10 @@ void Workspace::placeInFront(ListData *item, const bool userBusy)
}
inline
bool Workspace::removeAndPlaceBefore(ListData *item, ListData *beforeItem)
inline bool
Workspace::removeAndPlaceBefore(ListData *item, ListData *beforeItem)
{
if (item && item != beforeItem)
{
if (item && item != beforeItem) {
RemoveItem(item);
// insert into proper place.
InsertItem(item, beforeItem);
@ -1501,40 +1483,39 @@ bool Workspace::removeAndPlaceBefore(ListData *item, ListData *beforeItem)
specified WinBorder in Workspace's list an remove it.
\resolution: private
*/
inline
bool Workspace::removeAndPlaceBefore(const WinBorder *wb, ListData *beforeItem)
inline bool
Workspace::removeAndPlaceBefore(const WinBorder *wb, ListData *beforeItem)
{
return removeAndPlaceBefore(HasItem(wb), beforeItem);
}
inline
WinBorder* Workspace::searchANormalWindow(WinBorder *wb) const
{
ListData *listItem = fBottomItem;
while (listItem)
{
if (listItem->layerPtr->Level() == B_NORMAL && !listItem->layerPtr->IsHidden()
&& listItem->layerPtr->App()->ClientTeamID() == wb->App()->ClientTeamID())
return listItem->layerPtr;
listItem = listItem->upperItem;
inline WinBorder*
Workspace::searchANormalWindow(WinBorder *wb) const
{
ListData* listItem = fBottomItem;
while (listItem) {
if (listItem->layerPtr->Level() == B_NORMAL && !listItem->layerPtr->IsHidden()
&& listItem->layerPtr->App()->ClientTeam() == wb->App()->ClientTeam())
return listItem->layerPtr;
listItem = listItem->upperItem;
}
return NULL;
}
inline
WinBorder* Workspace::searchFirstMainWindow(WinBorder *wb) const
inline WinBorder*
Workspace::searchFirstMainWindow(WinBorder *wb) const
{
ListData *listItem = fBottomItem;
while (listItem)
{
ListData* listItem = fBottomItem;
while (listItem) {
if (listItem->layerPtr->Level() == B_NORMAL && !listItem->layerPtr->IsHidden()
&& listItem->layerPtr->App()->ClientTeamID() == wb->App()->ClientTeamID()
&& listItem->layerPtr->App()->ClientTeam() == wb->App()->ClientTeam()
&& listItem->layerPtr->fSubWindowList.HasItem(wb))
return listItem->layerPtr;
return listItem->layerPtr;
listItem = listItem->upperItem;
listItem = listItem->upperItem;
}
return NULL;
}