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
+129 -143
View File
@@ -2,8 +2,12 @@
* Copyright (c) 2001-2005, Haiku, Inc. * Copyright (c) 2001-2005, Haiku, Inc.
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Author: DarkWyrm <[email protected]> * Authors:
* DarkWyrm <[email protected]>
* Axel Dörfler, [email protected]
*/ */
#include <Accelerant.h> #include <Accelerant.h>
#include <AppDefs.h> #include <AppDefs.h>
#include <Directory.h> #include <Directory.h>
@@ -52,6 +56,10 @@
# define STRACE(x) ; # define STRACE(x) ;
#endif #endif
static const uint32 kMsgShutdownServer = 'shuT';
// Globals // Globals
Desktop *gDesktop; Desktop *gDesktop;
@@ -92,10 +100,9 @@ AppServer::AppServer(void) :
if (fServerInputPort == B_NO_MORE_PORTS) if (fServerInputPort == B_NO_MORE_PORTS)
debugger("app_server could not create input port"); debugger("app_server could not create input port");
fAppList = new BList(); fQuitting = false;
fQuittingServer = false;
sAppServer = this; sAppServer = this;
// Create the font server and scan the proper directories. // Create the font server and scan the proper directories.
fontserver = new FontServer; fontserver = new FontServer;
fontserver->Lock(); fontserver->Lock();
@@ -228,19 +235,25 @@ AppServer::~AppServer(void)
int32 int32
AppServer::PicassoThread(void *data) AppServer::PicassoThread(void *data)
{ {
for (;;) { while (!sAppServer->fQuitting) {
acquire_sem(sAppServer->fAppListLock); acquire_sem(sAppServer->fAppListLock);
for (int32 i = 0;;) { for (int32 i = 0;;) {
ServerApp *app = (ServerApp *)sAppServer->fAppList->ItemAt(i++); ServerApp *app = (ServerApp *)sAppServer->fAppList.ItemAt(i++);
if (!app) if (!app)
break; break;
app->PingTarget(); app->PingTarget();
} }
release_sem(sAppServer->fAppListLock); release_sem(sAppServer->fAppListLock);
// we do this every other second so as not to suck *too* many CPU cycles // we do this every second so as not to suck *too* many CPU cycles
snooze(1000000); 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; return 0;
} }
@@ -257,13 +270,13 @@ AppServer::LaunchInputServer()
fISThreadID = B_ERROR; fISThreadID = B_ERROR;
while (!BRoster::Private().IsMessengerValid(false) && !fQuittingServer) { while (!BRoster::Private().IsMessengerValid(false) && !fQuitting) {
snooze(250000); snooze(250000);
BRoster::Private::DeleteBeRoster(); BRoster::Private::DeleteBeRoster();
BRoster::Private::InitBeRoster(); BRoster::Private::InitBeRoster();
} }
if (fQuittingServer) if (fQuitting)
return; return;
// we use an area for cursor data communication with input_server // we use an area for cursor data communication with input_server
@@ -323,18 +336,15 @@ AppServer::LaunchCursorThread()
int32 int32
AppServer::CursorThread(void* data) AppServer::CursorThread(void* data)
{ {
AppServer *app = (AppServer *)data; AppServer *server = (AppServer *)data;
BPoint p; server->LaunchInputServer();
app->LaunchInputServer();
do { do {
while (acquire_sem(server->fCursorSem) == B_OK) {
while (acquire_sem(app->fCursorSem) == B_OK) { BPoint p;
p.y = *server->fCursorAddr & 0x7fff;
p.y = *app->fCursorAddr & 0x7fff; p.x = *server->fCursorAddr >> 15 & 0x7fff;
p.x = *app->fCursorAddr >> 15 & 0x7fff;
gDesktop->GetDisplayDriver()->MoveCursorTo(p.x, p.y); gDesktop->GetDisplayDriver()->MoveCursorTo(p.x, p.y);
STRACE(("CursorThread : %f, %f\n", p.x, p.y)); STRACE(("CursorThread : %f, %f\n", p.x, p.y));
@@ -342,12 +352,25 @@ AppServer::CursorThread(void* data)
snooze(100000); snooze(100000);
} while (!app->fQuittingServer); } while (!server->fQuitting);
return B_OK; 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... \brief The call that starts it all...
\return Always 0 \return Always 0
@@ -365,38 +388,19 @@ AppServer::Run(void)
void void
AppServer::MainLoop(void) AppServer::MainLoop(void)
{ {
BPrivate::PortLink pmsg(-1, fMessagePort); BPrivate::PortLink link(-1, fMessagePort);
while (1) { while (1) {
STRACE(("info: AppServer::MainLoop listening on port %ld.\n", fMessagePort)); STRACE(("info: AppServer::MainLoop listening on port %ld.\n", fMessagePort));
int32 code; int32 code;
status_t err = pmsg.GetNextMessage(code); status_t err = link.GetNextMessage(code);
if (err < B_OK) { if (err < B_OK) {
STRACE(("MainLoop:pmsg.GetNextMessage() failed\n")); STRACE(("MainLoop:link.GetNextMessage() failed\n"));
continue; continue;
} }
switch (code) { DispatchMessage(code, link);
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;
}
}
} }
} }
@@ -413,7 +417,7 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
case AS_CREATE_APP: case AS_CREATE_APP:
{ {
// Create the ServerApp to node monitor a new BApplication // Create the ServerApp to node monitor a new BApplication
// Attached data: // Attached data:
// 1) port_id - receiver port of a regular app // 1) port_id - receiver port of a regular app
// 2) port_id - client looper port - for send messages to the client // 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) if (msg.ReadString(&appSignature) != B_OK)
break; break;
port_id serverListen = create_port(DEFAULT_MONITOR_PORT_SIZE, appSignature); ServerApp *app = new ServerApp(clientReplyPort, clientLooperPort,
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,
clientTeamID, htoken, appSignature); 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 // if everything went well, ServerApp::Run() will notify
fAppList->AddItem(app); // the client - but since it didn't, we do it here
BPrivate::LinkSender reply(clientReplyPort);
release_sem(fAppListLock); reply.StartMessage(SERVER_FALSE);
reply.Flush();
BPrivate::PortLink replylink(clientReplyPort); }
replylink.StartMessage(SERVER_TRUE);
replylink.Attach<int32>(serverListen);
replylink.Flush();
// This is necessary because BPortLink::ReadString allocates memory // This is necessary because BPortLink::ReadString allocates memory
free(appSignature); free(appSignature);
break; break;
} }
case AS_DELETE_APP: case AS_DELETE_APP:
{ {
// Delete a ServerApp. Received only from the respective ServerApp when a // Delete a ServerApp. Received only from the respective ServerApp when a
@@ -476,41 +470,45 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
// Attached Data: // Attached Data:
// 1) thread_id - thread ID of the ServerApp to be deleted // 1) thread_id - thread ID of the ServerApp to be deleted
int32 i = 0, appnum = fAppList->CountItems(); thread_id thread = -1;
ServerApp *srvapp = NULL; if (msg.Read<thread_id>(&thread) < B_OK)
thread_id srvapp_id = -1;
if (msg.Read<thread_id>(&srvapp_id) < B_OK)
break; break;
acquire_sem(fAppListLock); acquire_sem(fAppListLock);
// Run through the list of apps and nuke the proper one // 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) { int32 count = fAppList.CountItems();
srvapp = (ServerApp *)fAppList->RemoveItem(i); ServerApp *removeApp = NULL;
if (srvapp) {
delete srvapp; for (int32 i = 0; i < count; i++) {
srvapp = NULL; ServerApp *app = (ServerApp *)fAppList.ItemAt(i);
}
break; // jump out of our for() loop if (app != NULL && app->Thread() == thread) {
fAppList.RemoveItem(i);
removeApp = app;
break;
} }
} }
release_sem(fAppListLock); release_sem(fAppListLock);
if (removeApp != NULL)
removeApp->Quit();
if (fQuitting && count <= 1)
PostMessage(kMsgShutdownServer);
break; break;
} }
case AS_UPDATED_CLIENT_FONTLIST: case AS_UPDATED_CLIENT_FONTLIST:
{
// received when the client-side global font list has been // received when the client-side global font list has been
// refreshed // refreshed
fontserver->Lock(); fontserver->Lock();
fontserver->FontsUpdated(); fontserver->FontsUpdated();
fontserver->Unlock(); fontserver->Unlock();
break; break;
}
case AS_QUERY_FONTS_CHANGED: case AS_QUERY_FONTS_CHANGED:
{ {
// Client application is asking if the font list has changed since // 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); BPrivate::PortLink replylink(replyport);
replylink.StartMessage(needs_update ? SERVER_TRUE : SERVER_FALSE); replylink.StartMessage(needs_update ? SERVER_TRUE : SERVER_FALSE);
replylink.Flush(); replylink.Flush();
break; break;
} }
case B_QUIT_REQUESTED:
{
#if TEST_MODE #if TEST_MODE
// Attached Data: case B_QUIT_REQUESTED:
// none
// We've been asked to quit, so (for now) broadcast to all // We've been asked to quit, so (for now) broadcast to all
// test apps to quit. This situation will occur only when the server // test apps to quit. This situation will occur only when the server
// is compiled as a regular Be application. // is compiled as a regular Be application.
fQuitting = true;
BroadcastToAllApps(AS_QUIT_APP); BroadcastToAllApps(AS_QUIT_APP);
// we have to wait until *all* threads have finished! // We now need to process the remaining AS_DELETE_APP messages and
ServerApp *app; // 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); 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 for (int32 i = 0; i < fAppList.CountItems(); i++) {
// thread_id. We will only wait so long, because then the app is probably crashed ServerApp *app = (ServerApp*)fAppList.ItemAt(i);
// 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 j = 0; j < 5; j++) { kill_thread(app->Thread());
snooze(500000); // wait half a second for it to quit kill_team(app->ClientTeam());
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(fPicassoThreadID); kill_thread(fPicassoThreadID);
@@ -582,15 +564,14 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
release_sem(fAppListLock); release_sem(fAppListLock);
delete gDesktop; delete gDesktop;
delete fAppList;
delete bitmapmanager; delete bitmapmanager;
delete fontserver; delete fontserver;
// we are now clear to exit // we are now clear to exit
exit_thread(0); exit_thread(0);
#endif
break; break;
} #endif
case AS_SET_SYSCURSOR_DEFAULTS: case AS_SET_SYSCURSOR_DEFAULTS:
{ {
// although this isn't pretty, ATM we only have RootLayer. // 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(); gDesktop->ActiveRootLayer()->GetCursorManager().SetDefaults();
break; break;
} }
default: default:
// we should never get here. STRACE(("Server::MainLoop received unexpected code %ld (offset %ld)\n",
code, code - SERVER_TRUE));
break; break;
} }
} }
@@ -614,31 +597,31 @@ AppServer::DispatchMessage(int32 code, BPrivate::PortLink &msg)
while it does its searching. while it does its searching.
*/ */
ServerApp * ServerApp *
AppServer::FindApp(const char *sig) AppServer::FindApp(const char *signature)
{ {
if (!sig) if (!signature)
return NULL; return NULL;
ServerApp *foundapp=NULL;
acquire_sem(fAppListLock); acquire_sem(fAppListLock);
for(int32 i=0; i<fAppList->CountItems();i++) ServerApp *foundApp = NULL;
{ for (int32 i = 0; i < fAppList.CountItems(); i++) {
foundapp=(ServerApp*)fAppList->ItemAt(i); ServerApp *app = (ServerApp*)fAppList.ItemAt(i);
if(foundapp && foundapp->Title() == sig) if (app && !strcasecmp(app->Signature(), signature)) {
{ foundApp = app;
release_sem(fAppListLock); break;
return foundapp;
} }
} }
release_sem(fAppListLock); release_sem(fAppListLock);
// couldn't find a match return foundApp;
return NULL;
} }
// #pragma mark -
/*! /*!
\brief Send a quick (no attachments) message to all applications \brief Send a quick (no attachments) message to all applications
@@ -650,18 +633,19 @@ BroadcastToAllApps(const int32 &code)
{ {
acquire_sem(sAppServer->fAppListLock); acquire_sem(sAppServer->fAppListLock);
for (int32 i = 0; i < sAppServer->fAppList->CountItems(); i++) { for (int32 i = 0; i < sAppServer->fAppList.CountItems(); i++) {
ServerApp *app = (ServerApp *)sAppServer->fAppList->ItemAt(i); ServerApp *app = (ServerApp *)sAppServer->fAppList.ItemAt(i);
if (!app) if (!app) {
{ printf("PANIC in Broadcast()\n"); continue; } printf("PANIC in Broadcast()\n");
continue;
}
app->PostMessage(code); app->PostMessage(code);
} }
release_sem(sAppServer->fAppListLock); release_sem(sAppServer->fAppListLock);
} }
// #pragma mark -
/*! /*!
\brief Entry function to run the entire server \brief Entry function to run the entire server
@@ -677,7 +661,9 @@ main(int argc, char** argv)
return -1; return -1;
srand(real_time_clock_usecs()); srand(real_time_clock_usecs());
AppServer app_server;
app_server.Run(); AppServer server;
server.Run();
return 0; return 0;
} }
+6 -5
View File
@@ -51,7 +51,8 @@ public:
static int32 PicassoThread(void *data); static int32 PicassoThread(void *data);
thread_id Run(void); thread_id Run(void);
void MainLoop(void); void MainLoop(void);
void PostMessage(int32 code);
void DispatchMessage(int32 code, BPrivate::PortLink &link); void DispatchMessage(int32 code, BPrivate::PortLink &link);
ServerApp* FindApp(const char *sig); ServerApp* FindApp(const char *sig);
@@ -64,10 +65,10 @@ private:
port_id fMessagePort; port_id fMessagePort;
port_id fServerInputPort; port_id fServerInputPort;
volatile bool fQuittingServer; volatile bool fQuitting;
BList *fAppList; BList fAppList;
thread_id fPicassoThreadID; thread_id fPicassoThreadID;
thread_id fISThreadID; thread_id fISThreadID;
+4 -4
View File
@@ -268,7 +268,7 @@ Desktop::AddWinBorder(WinBorder *winBorder)
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
wb = (WinBorder *)fWinBorderList.ItemAt(i); wb = (WinBorder *)fWinBorderList.ItemAt(i);
if (wb->App()->ClientTeamID() == winBorder->App()->ClientTeamID() if (wb->App()->ClientTeam() == winBorder->App()->ClientTeam()
&& wb->Feel() == feelToLookFor) { && wb->Feel() == feelToLookFor) {
// R2: RootLayer comparison is needed. // R2: RootLayer comparison is needed.
feel == B_NORMAL_WINDOW_FEEL ? feel == B_NORMAL_WINDOW_FEEL ?
@@ -322,7 +322,7 @@ Desktop::RemoveWinBorder(WinBorder *winBorder)
wb = (WinBorder*)fWinBorderList.ItemAt(i); wb = (WinBorder*)fWinBorderList.ItemAt(i);
if (wb->Feel() == B_NORMAL_WINDOW_FEEL 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. // R2: RootLayer comparison is needed. We'll see.
wb->fSubWindowList.RemoveItem(winBorder); wb->fSubWindowList.RemoveItem(winBorder);
} }
@@ -368,7 +368,7 @@ Desktop::AddWinBorderToSubset(WinBorder *winBorder, WinBorder *toWinBorder)
if ((winBorder->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL if ((winBorder->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL
|| winBorder->Feel() == B_MODAL_SUBSET_WINDOW_FEEL) || winBorder->Feel() == B_MODAL_SUBSET_WINDOW_FEEL)
&& toWinBorder->Feel() == B_NORMAL_WINDOW_FEEL && toWinBorder->Feel() == B_NORMAL_WINDOW_FEEL
&& toWinBorder->App()->ClientTeamID() == winBorder->App()->ClientTeamID() && toWinBorder->App()->ClientTeam() == winBorder->App()->ClientTeam()
&& !toWinBorder->fSubWindowList.HasItem(winBorder)) { && !toWinBorder->fSubWindowList.HasItem(winBorder)) {
// add to normal_window's list // add to normal_window's list
toWinBorder->fSubWindowList.AddWinBorder(winBorder); toWinBorder->fSubWindowList.AddWinBorder(winBorder);
@@ -442,7 +442,7 @@ Desktop::FindWinBorderByServerWindowTokenAndTeamID(int32 token, team_id teamID)
Lock(); Lock();
for (int32 i = 0; (wb = (WinBorder *)fWinBorderList.ItemAt(i)); i++) { for (int32 i = 0; (wb = (WinBorder *)fWinBorderList.ItemAt(i)); i++) {
if (wb->Window()->ClientToken() == token if (wb->Window()->ClientToken() == token
&& wb->Window()->ClientTeamID() == teamID) && wb->Window()->ClientTeam() == teamID)
break; break;
} }
Unlock(); Unlock();
+193 -125
View File
@@ -63,6 +63,10 @@
# define FTRACE(x) ; # define FTRACE(x) ;
#endif #endif
static const uint32 kMsgAppQuit = 'appQ';
/*! /*!
\brief Constructor \brief Constructor
\param sendport port ID for the BApplication which will receive the ServerApp's messages \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 \param fSignature NULL-terminated string which contains the BApplication's
MIME fSignature. MIME fSignature.
*/ */
ServerApp::ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort, ServerApp::ServerApp(port_id clientReplyPort, port_id clientLooperPort,
team_id clientTeamID, int32 handlerID, const char* signature) team_id clientTeam, int32 handlerID, const char* signature)
: :
fClientAppPort(sendport), fLockSem(-1),
fMessagePort(rcvport), fClientReplyPort(clientReplyPort),
fMessagePort(-1),
fClientLooperPort(clientLooperPort), fClientLooperPort(clientLooperPort),
fSignature(signature), fSignature(signature),
fMonitorThreadID(-1), fThread(-1),
fClientTeamID(clientTeamID), fClientTeam(clientTeam),
fLink(fClientAppPort, fMessagePort),
fSWindowList(new BList()),
fBitmapList(new BList()),
fPictureList(new BList()),
fAppCursor(NULL), fAppCursor(NULL),
fLockSem(create_sem(1, "ServerApp sem")),
fCursorHidden(false), fCursorHidden(false),
fIsActive(false), fIsActive(false),
//fHandlerToken(handlerID), //fHandlerToken(handlerID),
@@ -92,7 +92,25 @@ ServerApp::ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort
fQuitting(false) fQuitting(false)
{ {
if (fSignature == "") 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. // although this isn't pretty, ATM we have only one RootLayer.
// there should be a way that this ServerApp be attached to a particular // 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) { if (defaultCursor) {
fAppCursor = new ServerCursor(defaultCursor); fAppCursor = new ServerCursor(defaultCursor);
fAppCursor->SetOwningTeam(fClientTeamID); fAppCursor->SetOwningTeam(fClientTeam);
} }
Run();
STRACE(("ServerApp %s:\n", fSignature.String())); STRACE(("ServerApp %s:\n", fSignature.String()));
STRACE(("\tBApp port: %ld\n", fClientAppPort)); STRACE(("\tBApp port: %ld\n", fClientReplyPort));
STRACE(("\tReceiver port: %ld\n", fMessagePort)); STRACE(("\tReceiver port: %ld\n", fMessagePort));
} }
@@ -117,67 +133,119 @@ ServerApp::ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort
ServerApp::~ServerApp(void) ServerApp::~ServerApp(void)
{ {
STRACE(("*ServerApp %s:~ServerApp()\n",fSignature.String())); 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++) { if (!fQuitting)
delete static_cast<ServerPicture *>(fPictureList->ItemAt(i)); 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 // This shouldn't be necessary -- all cursors owned by the app
// should be cleaned up by RemoveAppCursors // should be cleaned up by RemoveAppCursors
// if(fAppCursor) // delete fAppCursor;
// delete fAppCursor;
// although this isn't pretty, ATM we have only one RootLayer. // although this isn't pretty, ATM we have only one RootLayer.
// there should be a way that this ServerApp be attached to a particular // there should be a way that this ServerApp be attached to a particular
// RootLayer to know which RootLayer's cursor to modify. // RootLayer to know which RootLayer's cursor to modify.
gDesktop->ActiveRootLayer()->GetCursorManager().RemoveAppCursors(fClientTeamID); gDesktop->ActiveRootLayer()->GetCursorManager().RemoveAppCursors(fClientTeam);
delete_sem(fLockSem); delete_sem(fLockSem);
STRACE(("#ServerApp %s:~ServerApp()\n", fSignature.String())); 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; delete fSharedMem;
STRACE(("ServerApp %s::~ServerApp(): Exiting\n", fSignature.String())); 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 \brief Starts the ServerApp monitoring for messages
\return false if the application couldn't start, true if everything went OK. \return false if the application couldn't start, true if everything went OK.
*/ */
bool bool
ServerApp::Run(void) ServerApp::Run()
{ {
fQuitting = false;
// Unlike a BApplication, a ServerApp is *supposed* to return immediately // Unlike a BApplication, a ServerApp is *supposed* to return immediately
// when its Run() function is called. // when its Run() function is called.
fMonitorThreadID = spawn_thread(MonitorApp, fSignature.String(), B_NORMAL_PRIORITY, this); fThread = spawn_thread(_message_thread, fSignature.String(), B_NORMAL_PRIORITY, this);
if (fMonitorThreadID < B_OK) if (fThread < B_OK)
return false; 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 \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." \return true if target is still "alive" and false if "He's dead, Jim."
"But that's impossible..." "But that's impossible..."
This function is called by the app_server thread to ensure that 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 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 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. tell the app_server to delete the respective ServerApp.
*/ */
bool bool
ServerApp::PingTarget(void) ServerApp::PingTarget()
{ {
team_info tinfo; team_info info;
if (get_team_info(fClientTeamID, &tinfo) == B_BAD_TEAM_ID) { if (get_team_info(fClientTeam, &info) != B_OK) {
BPrivate::LinkSender link(gAppServerPort); BPrivate::LinkSender link(gAppServerPort);
link.StartMessage(AS_DELETE_APP); link.StartMessage(AS_DELETE_APP);
link.Attach(&fMonitorThreadID, sizeof(thread_id)); link.Attach(&fThread, sizeof(thread_id));
link.Flush(); link.Flush();
return false; return false;
} }
@@ -260,34 +328,50 @@ ServerApp::SetAppCursor(void)
/*! /*!
\brief The thread function ServerApps use to monitor messages \brief The thread function ServerApps use to monitor messages
\param data Pointer to the thread's ServerApp object \param data Pointer to the thread's ServerApp object
\return Throwaway value - always 0
*/ */
int32 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 // Message-dispatching loop for the ServerApp
ServerApp *app = (ServerApp *)data; BPrivate::LinkReceiver &receiver = fLink.Receiver();
BPrivate::LinkReceiver &reader = app->fLink.Receiver();
int32 code; int32 code;
status_t err = B_OK; status_t err = B_OK;
while (!app->fQuitting) { while (!fQuitting) {
STRACE(("info: ServerApp::MonitorApp listening on port %ld.\n", app->fMessagePort)); STRACE(("info: ServerApp::_MessageLooper() listening on port %ld.\n", fMessagePort));
err = reader.GetNextMessage(code, B_INFINITE_TIMEOUT); err = receiver.GetNextMessage(code, B_INFINITE_TIMEOUT);
if (err < B_OK) { if (err < B_OK || code == B_QUIT_REQUESTED) {
STRACE(("ServerApp::MonitorApp(): GetNextMessage returned %s\n", strerror(err))); 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); BPrivate::LinkSender link(gAppServerPort);
link.StartMessage(AS_DELETE_APP); link.StartMessage(AS_DELETE_APP);
link.Attach(&app->fMonitorThreadID, sizeof(thread_id)); link.Attach<thread_id>(Thread());
link.Flush(); link.Flush();
break; break;
} }
switch (code) { switch (code) {
case kMsgAppQuit:
// we receive this from our destructor on quit
fQuitting = true;
break;
case AS_CREATE_WINDOW: case AS_CREATE_WINDOW:
{ {
// Create the ServerWindow to node monitor a new OBWindow // Create the ServerWindow to node monitor a new OBWindow
@@ -312,22 +396,21 @@ ServerApp::MonitorApp(void *data)
port_id looperPort = -1; port_id looperPort = -1;
char *title = NULL; char *title = NULL;
reader.Read<BRect>(&frame); receiver.Read<BRect>(&frame);
reader.Read<uint32>(&look); receiver.Read<uint32>(&look);
reader.Read<uint32>(&feel); receiver.Read<uint32>(&feel);
reader.Read<uint32>(&flags); receiver.Read<uint32>(&flags);
reader.Read<uint32>(&wkspaces); receiver.Read<uint32>(&wkspaces);
reader.Read<int32>(&token); receiver.Read<int32>(&token);
reader.Read<port_id>(&sendPort); receiver.Read<port_id>(&sendPort);
reader.Read<port_id>(&looperPort); receiver.Read<port_id>(&looperPort);
if (reader.ReadString(&title) != B_OK) if (receiver.ReadString(&title) != B_OK)
break; 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 constructor will reply with port_id of a newly created port
ServerWindow *sw = NULL; ServerWindow *sw = new ServerWindow(title, this, sendPort, looperPort, token);
sw = new ServerWindow(title, app, sendPort, looperPort, token);
sw->Init(frame, look, feel, flags, wkspaces); sw->Init(frame, look, feel, flags, wkspaces);
STRACE(("\nServerApp %s: New Window %s (%.1f,%.1f,%.1f,%.1f)\n", STRACE(("\nServerApp %s: New Window %s (%.1f,%.1f,%.1f,%.1f)\n",
@@ -337,46 +420,38 @@ ServerApp::MonitorApp(void *data)
free(title); free(title);
break; break;
} }
case AS_QUIT_APP: case AS_QUIT_APP:
{ {
// This message is received only when the app_server is asked to shut down in // 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 // 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 // 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. // through the driver's interface, such as closing the ViewDriver's window.
STRACE(("ServerApp %s:Server shutdown notification received\n", STRACE(("ServerApp %s:Server shutdown notification received\n", Signature()));
app->fSignature.String()));
// If we are using the real, accelerated version of the // If we are using the real, accelerated version of the
// DisplayDriver, we do NOT want the user to be able shut down // DisplayDriver, we do NOT want the user to be able shut down
// the server. The results would NOT be pretty // the server. The results would NOT be pretty
#if TEST_MODE #if TEST_MODE
BMessage pleaseQuit(B_QUIT_REQUESTED); BMessage pleaseQuit(B_QUIT_REQUESTED);
app->SendMessageToClient(&pleaseQuit); SendMessageToClient(&pleaseQuit);
#endif #endif
break; 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: default:
STRACE(("ServerApp %s: Got a Message to dispatch\n", app->fSignature.String())); STRACE(("ServerApp %s: Got a Message to dispatch\n", Signature()));
app->DispatchMessage(code, reader); _DispatchMessage(code, receiver);
break; 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. matter of casting and incrementing an index variable to access them.
*/ */
void void
ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link) ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
{ {
LayerData ld; LayerData ld;
@@ -404,9 +479,8 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
ServerWindow *win; ServerWindow *win;
BMessage msg(_COLORS_UPDATED); BMessage msg(_COLORS_UPDATED);
for(int32 i=0; i<fSWindowList->CountItems(); i++) for(int32 i = 0; i < fWindowList.CountItems(); i++) {
{ win=(ServerWindow*)fWindowList.ItemAt(i);
win=(ServerWindow*)fSWindowList->ItemAt(i);
win->GetWinBorder()->UpdateColors(); win->GetWinBorder()->UpdateColors();
win->SendMessageToClient(AS_UPDATE_COLORS, msg); win->SendMessageToClient(AS_UPDATE_COLORS, msg);
} }
@@ -444,25 +518,24 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
size_t msgsize; size_t msgsize;
area_info ai; area_info ai;
int8 *msgpointer; int8 *msgpointer;
link.Read<area_id>(&area); link.Read<area_id>(&area);
link.Read<size_t>(&offset); link.Read<size_t>(&offset);
link.Read<size_t>(&msgsize); link.Read<size_t>(&msgsize);
// Part sanity check, part get base pointer :) // Part sanity check, part get base pointer :)
if (get_area_info(area, &ai) < B_OK) if (get_area_info(area, &ai) < B_OK)
break; break;
msgpointer = (int8*)ai.address + offset; msgpointer = (int8*)ai.address + offset;
RAMLinkMsgReader mlink(msgpointer); 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 // 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 // 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. // requested. This is the server's job once the message has been dispatched.
fSharedMem->ReleaseBuffer(msgpointer); fSharedMem->ReleaseBuffer(msgpointer);
break; break;
} }
case AS_ACQUIRE_SERVERMEM: 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())); STRACE(("ServerApp %s: Received decorator update notification\n",fSignature.String()));
ServerWindow *win; for (int32 i = 0; i < fWindowList.CountItems(); i++) {
ServerWindow *window = (ServerWindow*)fWindowList.ItemAt(i);
for(int32 i = 0; i < fSWindowList->CountItems(); i++) window->Lock();
{ const_cast<WinBorder *>(window->GetWinBorder())->UpdateDecorator();
win = (ServerWindow*)fSWindowList->ItemAt(i); window->Unlock();
win->Lock();
const_cast<WinBorder *>(win->GetWinBorder())->UpdateDecorator();
win->Unlock();
} }
break; break;
} }
@@ -652,7 +722,7 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
fSignature.String(), frame.Width(), frame.Height())); fSignature.String(), frame.Width(), frame.Height()));
if (bitmap) { if (bitmap) {
fBitmapList->AddItem(bitmap); fBitmapList.AddItem(bitmap);
fLink.StartMessage(SERVER_TRUE); fLink.StartMessage(SERVER_TRUE);
fLink.Attach<int32>(bitmap->Token()); fLink.Attach<int32>(bitmap->Token());
fLink.Attach<int32>(bitmap->Area()); fLink.Attach<int32>(bitmap->Area());
@@ -683,7 +753,7 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
if (bitmap) { if (bitmap) {
STRACE(("ServerApp %s: Deleting Bitmap %ld\n", fSignature.String(), id)); STRACE(("ServerApp %s: Deleting Bitmap %ld\n", fSignature.String(), id));
fBitmapList->RemoveItem(bitmap); fBitmapList.RemoveItem(bitmap);
bitmapmanager->DeleteBitmap(bitmap); bitmapmanager->DeleteBitmap(bitmap);
fLink.StartMessage(SERVER_TRUE); fLink.StartMessage(SERVER_TRUE);
} else } else
@@ -814,7 +884,7 @@ ServerApp::DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
gDesktop->ActiveRootLayer()->GetCursorManager().DeleteCursor(fAppCursor->ID()); gDesktop->ActiveRootLayer()->GetCursorManager().DeleteCursor(fAppCursor->ID());
fAppCursor = new ServerCursor(cdata); fAppCursor = new ServerCursor(cdata);
fAppCursor->SetOwningTeam(fClientTeamID); fAppCursor->SetOwningTeam(fClientTeam);
fAppCursor->SetAppSignature(fSignature.String()); fAppCursor->SetAppSignature(fSignature.String());
gDesktop->ActiveRootLayer()->GetCursorManager().AddCursor(fAppCursor); gDesktop->ActiveRootLayer()->GetCursorManager().AddCursor(fAppCursor);
// although this isn't pretty, ATM we have only one RootLayer. // 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)); link.Read(cursorData, sizeof(cursorData));
fAppCursor = new ServerCursor(cursorData); fAppCursor = new ServerCursor(cursorData);
fAppCursor->SetOwningTeam(fClientTeamID); fAppCursor->SetOwningTeam(fClientTeam);
fAppCursor->SetAppSignature(fSignature.String()); fAppCursor->SetAppSignature(fSignature.String());
// although this isn't pretty, ATM we have only one RootLayer. // although this isn't pretty, ATM we have only one RootLayer.
// there should be a way that this ServerApp be attached to a particular // 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 int32
ServerApp::CountBitmaps() const ServerApp::CountBitmaps() const
{ {
return fBitmapList ? fBitmapList->CountItems() : 0; return fBitmapList.CountItems();
} }
@@ -1861,13 +1931,12 @@ ServerApp::CountBitmaps() const
ServerBitmap * ServerBitmap *
ServerApp::FindBitmap(int32 token) const ServerApp::FindBitmap(int32 token) const
{ {
ServerBitmap *bitmap; for (int32 i = 0; i < fBitmapList.CountItems(); i++) {
for (int32 i = 0; i < fBitmapList->CountItems(); i++) { ServerBitmap *bitmap = static_cast<ServerBitmap *>(fBitmapList.ItemAt(i));
bitmap = static_cast<ServerBitmap *>(fBitmapList->ItemAt(i));
if (bitmap && bitmap->Token() == token) if (bitmap && bitmap->Token() == token)
return bitmap; return bitmap;
} }
return NULL; return NULL;
} }
@@ -1875,16 +1944,15 @@ ServerApp::FindBitmap(int32 token) const
int32 int32
ServerApp::CountPictures() const ServerApp::CountPictures() const
{ {
return fPictureList ? fPictureList->CountItems() : 0; return fPictureList.CountItems();
} }
ServerPicture * ServerPicture *
ServerApp::FindPicture(int32 token) const ServerApp::FindPicture(int32 token) const
{ {
ServerPicture *picture; for (int32 i = 0; i < fPictureList.CountItems(); i++) {
for (int32 i = 0; i < fPictureList->CountItems(); i++) { ServerPicture *picture = static_cast<ServerPicture *>(fPictureList.ItemAt(i));
picture = static_cast<ServerPicture *>(fPictureList->ItemAt(i));
if (picture && picture->GetToken() == token) if (picture && picture->GetToken() == token)
return picture; return picture;
} }
@@ -1894,15 +1962,15 @@ ServerApp::FindPicture(int32 token) const
team_id team_id
ServerApp::ClientTeamID() const ServerApp::ClientTeam() const
{ {
return fClientTeamID; return fClientTeam;
} }
thread_id thread_id
ServerApp::MonitorThreadID() const ServerApp::Thread() const
{ {
return fMonitorThreadID; return fThread;
} }
+42 -53
View File
@@ -1,33 +1,18 @@
//------------------------------------------------------------------------------ /*
// Copyright (c) 2001-2005, Haiku, Inc. * Copyright 2001-2005, Haiku.
// * Distributed under the terms of the MIT License.
// Permission is hereby granted, free of charge, to any person obtaining a *
// copy of this software and associated documentation files (the "Software"), * Authors:
// to deal in the Software without restriction, including without limitation * DarkWyrm <[email protected]>
// the rights to use, copy, modify, merge, publish, distribute, sublicense, * Adrian Oanca <[email protected]>
// and/or sell copies of the Software, and to permit persons to whom the * Stephan Aßmus <[email protected]>
// Software is furnished to do so, subject to the following conditions: * Stefano Ceccherini ([email protected])
// * Axel Dörfler, [email protected]
// 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 <[email protected]>
// Adi Oanca <[email protected]>
// Description: Server-side BApplication counterpart
//
//------------------------------------------------------------------------------
#ifndef _SERVERAPP_H_ #ifndef _SERVERAPP_H_
#define _SERVERAPP_H_ #define _SERVERAPP_H_
#include <OS.h> #include <OS.h>
#include <String.h> #include <String.h>
#include <PortLink.h> #include <PortLink.h>
@@ -52,11 +37,14 @@ namespace BPrivate {
*/ */
class ServerApp { class ServerApp {
public: 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); team_id clientTeamID, int32 handlerID, const char* signature);
virtual ~ServerApp(void); ~ServerApp();
bool Run(void); status_t InitCheck();
bool Run();
void Quit();
/* /*
TODO: These aren't even implemented... TODO: These aren't even implemented...
void Lock(void); void Lock(void);
@@ -69,19 +57,19 @@ public:
*/ */
bool IsActive(void) const { return fIsActive; } bool IsActive(void) const { return fIsActive; }
void Activate(bool value); void Activate(bool value);
bool PingTarget(void); bool PingTarget(void);
void PostMessage(int32 code); void PostMessage(int32 code);
void SendMessageToClient( const BMessage* msg ) const; void SendMessageToClient( const BMessage* msg ) const;
void SetAppCursor(void); void SetAppCursor(void);
team_id ClientTeamID() const; team_id ClientTeam() const;
thread_id MonitorThreadID() const; thread_id Thread() const;
const char *Title() const { return fSignature.String(); } const char *Signature() const { return fSignature.String(); }
int32 CountBitmaps() const; int32 CountBitmaps() const;
ServerBitmap *FindBitmap(int32 token) const; ServerBitmap *FindBitmap(int32 token) const;
@@ -93,12 +81,16 @@ public:
SubWindowList fAppSubWindowList; SubWindowList fAppSubWindowList;
private: 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 // our BApplication's event port
port_id fClientAppPort; port_id fClientReplyPort;
// port we receive messages from our BApplication // port we receive messages from our BApplication
port_id fMessagePort; port_id fMessagePort;
// TODO: find out why there is both the app port and the looper port. Do // TODO: find out why there is both the app port and the looper port. Do
@@ -109,23 +101,20 @@ private:
BString fSignature; BString fSignature;
thread_id fMonitorThreadID; thread_id fThread;
team_id fClientTeamID; team_id fClientTeam;
BPrivate::PortLink fLink; BPrivate::PortLink fLink;
// TODO: // TODO:
// - Are really Bitmaps and Pictures stored per application and not globally ? // - 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 ? // - As we reference these stuff by token, what about putting them in hash tables ?
BList *fSWindowList, BList fWindowList;
*fBitmapList, BList fBitmapList;
*fPictureList; BList fPictureList;
ServerCursor *fAppCursor; ServerCursor *fAppCursor;
// TODO: Not used.
sem_id fLockSem;
bool fCursorHidden; bool fCursorHidden;
bool fIsActive; bool fIsActive;
+23 -40
View File
@@ -1,31 +1,15 @@
//------------------------------------------------------------------------------ /*
// Copyright (c) 2001-2005, Haiku, Inc. * Copyright 2001-2005, Haiku.
// * Distributed under the terms of the MIT License.
// Permission is hereby granted, free of charge, to any person obtaining a *
// copy of this software and associated documentation files (the "Software"), * Authors:
// to deal in the Software without restriction, including without limitation * DarkWyrm <[email protected]>
// the rights to use, copy, modify, merge, publish, distribute, sublicense, * Adrian Oanca <[email protected]>
// and/or sell copies of the Software, and to permit persons to whom the * Stephan Aßmus <[email protected]>
// Software is furnished to do so, subject to the following conditions: * Stefano Ceccherini ([email protected])
// * Axel Dörfler, [email protected]
// 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 <[email protected]>
// Adi Oanca <[email protected]>
// Stephan Aßmus <[email protected]>
// Description: Shadow BWindow class
//
//------------------------------------------------------------------------------
#include <AppDefs.h> #include <AppDefs.h>
#include <Rect.h> #include <Rect.h>
@@ -75,7 +59,6 @@
# define DTRACE(x) ; # define DTRACE(x) ;
#endif #endif
// #pragma mark -
/*! /*!
\brief Constructor \brief Constructor
@@ -83,11 +66,11 @@
Does a lot of stuff to set up for the window - new decorator, new winborder, spawn a Does a lot of stuff to set up for the window - new decorator, new winborder, spawn a
monitor thread. monitor thread.
*/ */
ServerWindow::ServerWindow(const char *string, ServerApp *winapp, ServerWindow::ServerWindow(const char *string, ServerApp *app,
port_id winport, port_id looperPort, int32 handlerID) port_id clientPort, port_id looperPort, int32 handlerID)
: fServerApp(winapp), :
// fClientWinPort is the port to which the app awaits messages from the server fServerApp(app),
fClientWinPort(winport), fClientReplyPort(clientPort),
fClientLooperPort(looperPort), fClientLooperPort(looperPort),
fClientViewsWithInvalidCoords(B_VIEW_RESIZED), fClientViewsWithInvalidCoords(B_VIEW_RESIZED),
fHandlerToken(handlerID) fHandlerToken(handlerID)
@@ -100,14 +83,14 @@ ServerWindow::ServerWindow(const char *string, ServerApp *winapp,
} else } else
strcpy(fName, "Unnamed Window"); strcpy(fName, "Unnamed Window");
fClientTeamID = winapp->ClientTeamID(); fClientTeam = app->ClientTeam();
fWinBorder = NULL; fWinBorder = NULL;
fCurrentLayer = NULL; fCurrentLayer = NULL;
// fMessagePort is the port to which the app sends messages for the server // fMessagePort is the port to which the app sends messages for the server
fMessagePort = create_port(30, fName); fMessagePort = create_port(30, fName);
fMsgSender = new BPrivate::LinkSender(fClientWinPort); fMsgSender = new BPrivate::LinkSender(fClientReplyPort);
fMsgReceiver = new BPrivate::LinkReceiver(fMessagePort); fMsgReceiver = new BPrivate::LinkReceiver(fMessagePort);
// Send a reply to our window - it is expecting fMessagePort port. // 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) uint32 wfeel, uint32 wflags, uint32 wwksindex)
{ {
char name[60]; 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, fWinBorder = new WinBorder(frame, name, wlook, wfeel, wflags,
wwksindex, this, gDesktop->GetDisplayDriver()); wwksindex, this, gDesktop->GetDisplayDriver());
// Spawn our message-monitoring thread // Spawn our message-monitoring thread
fMonitorThreadID = spawn_thread(MonitorWin, fName, B_NORMAL_PRIORITY, this); fThread = spawn_thread(MonitorWin, fName, B_NORMAL_PRIORITY, this);
if (fMonitorThreadID >= B_OK) if (fThread >= B_OK)
resume_thread(fMonitorThreadID); resume_thread(fThread);
} }
+23 -38
View File
@@ -1,29 +1,14 @@
//------------------------------------------------------------------------------ /*
// Copyright (c) 2001-2005, Haiku, Inc. * Copyright 2001-2005, Haiku.
// * Distributed under the terms of the MIT License.
// Permission is hereby granted, free of charge, to any person obtaining a *
// copy of this software and associated documentation files (the "Software"), * Authors:
// to deal in the Software without restriction, including without limitation * DarkWyrm <bpmagic@columbus.rr.com>
// the rights to use, copy, modify, merge, publish, distribute, sublicense, * Adrian Oanca <adioanca@cotty.iren.ro>
// and/or sell copies of the Software, and to permit persons to whom the * Stephan Aßmus <superstippi@gmx.de>
// Software is furnished to do so, subject to the following conditions: * Stefano Ceccherini (burton666@libero.it)
// * Axel Dörfler, axeld@pinc-software.de
// 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 <[email protected]>
// Description: Shadow BWindow class
//
//------------------------------------------------------------------------------
#ifndef _SERVERWIN_H_ #ifndef _SERVERWIN_H_
#define _SERVERWIN_H_ #define _SERVERWIN_H_
@@ -103,16 +88,16 @@ public:
{ return fClientViewsWithInvalidCoords; }; { return fClientViewsWithInvalidCoords; };
// to who we belong. who do we own. our title. // to who we belong. who do we own. our title.
inline ServerApp* App(void) const { return fServerApp; } inline ServerApp* App() const { return fServerApp; }
inline const WinBorder* GetWinBorder(void) const { return fWinBorder; } inline const WinBorder* GetWinBorder() const { return fWinBorder; }
inline const char* Title(void) const { return fName; } inline const char* Title() const { return fName; }
// related thread/team_id(s). // related thread/team_id(s).
inline team_id ClientTeamID(void) const { return fClientTeamID; } inline team_id ClientTeam() const { return fClientTeam; }
inline thread_id ThreadID(void) const { return fMonitorThreadID;} inline thread_id Thread() const { return fThread; }
// server "private" - try not to use. // server "private" - try not to use.
inline int32 ClientToken(void) const { return fHandlerToken; } inline int32 ClientToken() const { return fHandlerToken; }
// ToDo: public?? // ToDo: public??
SubWindowList fSubWindowList; SubWindowList fSubWindowList;
@@ -143,15 +128,15 @@ private:
bool inverse, bool inverse,
BPoint where); BPoint where);
char fName[50]; char fName[50];
ServerApp* fServerApp; ServerApp* fServerApp;
WinBorder* fWinBorder; WinBorder* fWinBorder;
team_id fClientTeamID; team_id fClientTeam;
thread_id fMonitorThreadID; thread_id fThread;
port_id fMessagePort; port_id fMessagePort;
port_id fClientWinPort; port_id fClientReplyPort;
port_id fClientLooperPort; port_id fClientLooperPort;
BPrivate::LinkReceiver* fMsgReceiver; BPrivate::LinkReceiver* fMsgReceiver;
+106 -125
View File
@@ -369,41 +369,35 @@ STRACE(("Wks(%ld)::MoveToBack(%s) \n", fID, newLast? newLast->GetName(): "NULL")
return false; return false;
// this is a modal app // this is a modal app
if (newLast->App()->fAppSubWindowList.HasItem(newLast)) if (newLast->App()->fAppSubWindowList.HasItem(newLast)) {
{ ListData* before;
ListData *before;
// remove now to properly place later // remove now to properly place later
RemoveItem(newLastItem); RemoveItem(newLastItem);
while (cursor) while (cursor) {
{
if (!cursor->layerPtr->IsHidden() if (!cursor->layerPtr->IsHidden()
&& cursor->layerPtr->Level() > B_SYSTEM_LAST && cursor->layerPtr->Level() > B_SYSTEM_LAST
&& cursor->layerPtr->App()->ClientTeamID() == newLast->App()->ClientTeamID()) && cursor->layerPtr->App()->ClientTeam() == newLast->App()->ClientTeam())
{
break; break;
}
cursor = cursor->upperItem; cursor = cursor->upperItem;
} }
if (cursor) if (cursor)
before = cursor->lowerItem; before = cursor->lowerItem;
else else
before = fTopItem; before = fTopItem;
InsertItem(newLastItem, before); InsertItem(newLastItem, before);
} } else {
// this is a modal subset // this is a modal subset
else
{
// this subset modal is visible, it means its main window must be visible. search for it. // this subset modal is visible, it means its main window must be visible. search for it.
ListData *mainWindowItem, *before; ListData *mainWindowItem, *before;
int32 indexThis = 0, indexCursor; int32 indexThis = 0, indexCursor;
// search by going deep // search by going deep
while(cursor) while (cursor) {
{
if (cursor->layerPtr->Level() == B_NORMAL && !cursor->layerPtr->IsHidden() if (cursor->layerPtr->Level() == B_NORMAL && !cursor->layerPtr->IsHidden()
&& (indexThis = cursor->layerPtr->fSubWindowList.IndexOf(newLast)) >= 0) && (indexThis = cursor->layerPtr->fSubWindowList.IndexOf(newLast)) >= 0)
break; break;
@@ -416,14 +410,13 @@ STRACE(("Wks(%ld)::MoveToBack(%s) \n", fID, newLast? newLast->GetName(): "NULL")
RemoveItem(newLastItem); RemoveItem(newLastItem);
// good. found our main window. now go up and properly place. // good. found our main window. now go up and properly place.
mainWindowItem = cursor; mainWindowItem = cursor;
before = cursor->lowerItem; before = cursor->lowerItem;
cursor = cursor->lowerItem; cursor = cursor->lowerItem;
while(cursor) while (cursor) {
{
if (cursor->layerPtr->Level() == B_MODAL_APP && !cursor->layerPtr->IsHidden() 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); indexCursor = mainWindowItem->layerPtr->fSubWindowList.IndexOf(cursor->layerPtr);
if (indexCursor >= 0) if (indexCursor >= 0)
@@ -810,7 +803,7 @@ STRACE(("W(%ld)::ShowWinBorder(%s) \n", fID, winBorder? winBorder->GetName(): "N
// take only application's modals // take only application's modals
tempList.AddList(&winBorder->App()->fAppSubWindowList); tempList.AddList(&winBorder->App()->fAppSubWindowList);
if (fFrontItem if (fFrontItem
&& fFrontItem->layerPtr->App()->ClientTeamID() == winBorder->App()->ClientTeamID()) && fFrontItem->layerPtr->App()->ClientTeam() == winBorder->App()->ClientTeam())
userBusy = false; userBusy = false;
} }
// SUBSET modal // SUBSET modal
@@ -1217,47 +1210,46 @@ void Workspace::PrintItem(ListData *item) const
/* /*
Insert item in the top-bottom direction. 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; // insert before one other item;
if(before) if (before) {
{ if (before->upperItem)
if(before->upperItem) before->upperItem->lowerItem = item;
before->upperItem->lowerItem = item;
item->upperItem = before->upperItem;
item->lowerItem = before;
before->upperItem = item;
if(fTopItem == before) item->upperItem = before->upperItem;
item->lowerItem = before;
before->upperItem = item;
if (fTopItem == before)
fTopItem = item; fTopItem = item;
} } else {
else
{
// insert item at the end. // insert item at the end.
item->upperItem = fBottomItem; item->upperItem = fBottomItem;
if(fBottomItem) if (fBottomItem)
fBottomItem->lowerItem = item; fBottomItem->lowerItem = item;
fBottomItem = item; fBottomItem = item;
if(!fTopItem) if (!fTopItem)
fTopItem = item; fTopItem = item;
} }
} }
//----------------------------------------------------------------------------------
void Workspace::RemoveItem(ListData *item) void
Workspace::RemoveItem(ListData *item)
{ {
if(!item) if (!item)
return; return;
if(fBottomItem == item) if (fBottomItem == item)
fBottomItem = item->upperItem; fBottomItem = item->upperItem;
else else
item->lowerItem->upperItem = item->upperItem; item->lowerItem->upperItem = item->upperItem;
if(fTopItem == item) if (fTopItem == item)
fTopItem = item->lowerItem; fTopItem = item->lowerItem;
else else
item->upperItem->lowerItem = item->lowerItem; item->upperItem->lowerItem = item->lowerItem;
@@ -1267,23 +1259,22 @@ void Workspace::RemoveItem(ListData *item)
item->upperItem = NULL; item->upperItem = NULL;
item->lowerItem = NULL; item->lowerItem = NULL;
if(fFocusItem == item) if (fFocusItem == item)
fFocusItem = NULL; fFocusItem = NULL;
if(fFrontItem == item) if (fFrontItem == item)
fFrontItem = NULL; fFrontItem = NULL;
} }
//----------------------------------------------------------------------------------
ListData *Workspace::HasItem(const ListData *item, int32 *index) const ListData*
Workspace::HasItem(const ListData *item, int32 *index) const
{ {
int32 idx = 0; int32 idx = 0;
ListData *itemX; ListData* itemX;
for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) {
{ if (item == itemX)
if(item == itemX)
break; break;
idx++; idx++;
@@ -1295,16 +1286,15 @@ ListData *Workspace::HasItem(const ListData *item, int32 *index) const
return itemX; return itemX;
} }
//----------------------------------------------------------------------------------
ListData* Workspace::HasItem(const WinBorder *layer, int32 *index) const ListData*
Workspace::HasItem(const WinBorder *layer, int32 *index) const
{ {
int32 idx = 0; int32 idx = 0;
ListData *itemX; ListData *itemX;
for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) {
{ if (layer == itemX->layerPtr)
if(layer == itemX->layerPtr)
break; break;
idx++; idx++;
@@ -1316,62 +1306,58 @@ ListData* Workspace::HasItem(const WinBorder *layer, int32 *index) const
return itemX; return itemX;
} }
//----------------------------------------------------------------------------------
/*! /*!
\brief Returns the index of the specified item starting from the back-most window. \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) if (!item)
return -1; return -1;
int32 index = 0; int32 index = 0;
for (ListData *itemX = fTopItem; itemX != NULL; itemX = itemX->lowerItem) for (ListData *itemX = fTopItem; itemX != NULL; itemX = itemX->lowerItem) {
{ if (itemX->layerPtr == item->layerPtr)
if(itemX->layerPtr == item->layerPtr)
return index; return index;
index++; index++;
} }
return -1; 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_ALL:
case B_FLOATING_APP: case B_FLOATING_APP:
{ {
int32 count = 0; int32 count = 0;
while (cursor && cursor->layerPtr->Level() == level) while (cursor && cursor->layerPtr->Level() == level) {
{
if (!cursor->layerPtr->IsHidden()) if (!cursor->layerPtr->IsHidden())
count++; count++;
cursor = cursor->upperItem; cursor = cursor->upperItem;
} }
// we're already the last floating window // we're already the last floating window
if (count == 0) if (count == 0)
return false; return false;
else else {
{ bool changeFocus = false;
bool changeFocus = false;
if (fFocusItem == newLast) if (fFocusItem == newLast)
changeFocus = true; changeFocus = true;
if (changeFocus) if (changeFocus) {
{ ListData* cursor = newLast->upperItem;
ListData *cursor = newLast->upperItem; while (cursor
while ( cursor && (cursor->layerPtr->IsHidden()
&& ( cursor->layerPtr->IsHidden() || cursor->layerPtr->WindowFlags() & B_AVOID_FOCUS)
|| cursor->layerPtr->WindowFlags() & B_AVOID_FOCUS) && cursor->layerPtr->Level() == level) {
&& cursor->layerPtr->Level() == level)
{
cursor = cursor->upperItem; cursor = cursor->upperItem;
} }
@@ -1386,24 +1372,21 @@ bool Workspace::placeToBack(ListData *newLast)
return true; return true;
} }
break;
} }
break;
case B_NORMAL: case B_NORMAL:
{ {
int32 count = 0; int32 count = 0;
int32 cursorLevel; int32 cursorLevel;
while(cursor) while (cursor) {
{
cursorLevel = cursor->layerPtr->Level(); cursorLevel = cursor->layerPtr->Level();
if (cursorLevel == B_MODAL_APP) if (cursorLevel == B_MODAL_APP)
cursorLevel = B_NORMAL; cursorLevel = B_NORMAL;
if (cursorLevel < level) if (cursorLevel < level) {
{
break; break;
} } else {
else
{
count++; count++;
cursor = cursor->upperItem; cursor = cursor->upperItem;
} }
@@ -1412,16 +1395,15 @@ bool Workspace::placeToBack(ListData *newLast)
// we're already the last normal window // we're already the last normal window
if (count == 0) if (count == 0)
return false; return false;
else else {
{
RemoveItem(newLast); RemoveItem(newLast);
InsertItem(newLast, cursor? cursor->lowerItem: fTopItem); InsertItem(newLast, cursor? cursor->lowerItem: fTopItem);
return true; return true;
} }
break;
} }
break;
} }
return false; 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. \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) if (!item)
return; return;
@@ -1483,11 +1466,10 @@ void Workspace::placeInFront(ListData *item, const bool userBusy)
} }
inline inline bool
bool Workspace::removeAndPlaceBefore(ListData *item, ListData *beforeItem) Workspace::removeAndPlaceBefore(ListData *item, ListData *beforeItem)
{ {
if (item && item != beforeItem) if (item && item != beforeItem) {
{
RemoveItem(item); RemoveItem(item);
// insert into proper place. // insert into proper place.
InsertItem(item, beforeItem); InsertItem(item, beforeItem);
@@ -1501,40 +1483,39 @@ bool Workspace::removeAndPlaceBefore(ListData *item, ListData *beforeItem)
specified WinBorder in Workspace's list an remove it. specified WinBorder in Workspace's list an remove it.
\resolution: private \resolution: private
*/ */
inline inline bool
bool Workspace::removeAndPlaceBefore(const WinBorder *wb, ListData *beforeItem) Workspace::removeAndPlaceBefore(const WinBorder *wb, ListData *beforeItem)
{ {
return removeAndPlaceBefore(HasItem(wb), 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; return NULL;
} }
inline inline WinBorder*
WinBorder* Workspace::searchFirstMainWindow(WinBorder *wb) const Workspace::searchFirstMainWindow(WinBorder *wb) const
{ {
ListData *listItem = fBottomItem; ListData* listItem = fBottomItem;
while (listItem) while (listItem) {
{
if (listItem->layerPtr->Level() == B_NORMAL && !listItem->layerPtr->IsHidden() 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)) && listItem->layerPtr->fSubWindowList.HasItem(wb))
return listItem->layerPtr; return listItem->layerPtr;
listItem = listItem->upperItem; listItem = listItem->upperItem;
} }
return NULL; return NULL;
} }