1 //------------------------------------------------------------------------------
2 // Copyright (c) 2001-2005, Haiku, Inc.
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
22 // File Name: AppServer.cpp
23 // Author: DarkWyrm <bpmagic@columbus.rr.com>
24 // Description: main manager object for the app_server
26 //------------------------------------------------------------------------------
27 #include "AppServer.h"
28 #include "ServerApp.h"
29 #include "ServerProtocol.h"
31 #include <Accelerant.h>
33 #include <Directory.h>
39 #include <StopWatch.h>
44 //#define DEBUG_KEYHANDLING
45 //#define DEBUG_SERVER
47 #ifdef DEBUG_KEYHANDLING
48 # define KBTRACE(x) printf x
54 # define STRACE(x) printf x
61 port_id gAppServerPort
;
63 //! Used to access the app_server from new_decorator
64 static AppServer
*sAppServer
= NULL
;
66 //! Default background color for workspaces
67 //RGBColor workspace_default_color(51,102,160);
73 This loads the default fonts, allocates all the major global variables, spawns the main housekeeping
74 threads, loads user preferences for the UI and decorator, and allocates various locks.
76 AppServer::AppServer(void)
81 fMessagePort
= create_port(200, SERVER_PORT_NAME
);
82 if (fMessagePort
== B_NO_MORE_PORTS
)
83 debugger("app_server could not create message port");
85 gAppServerPort
= fMessagePort
;
87 fAppList
= new BList();
88 fQuittingServer
= false;
90 // We need this in order for new_decorator to be able to instantiate new decorators
93 // This is necessary to mediate access between the Poller and app_server threads
94 fActiveAppLock
= create_sem(1,"app_server_active_sem");
96 // This locker is for app_server and Picasso to vy for control of the ServerApp list
97 fAppListLock
= create_sem(1,"app_server_applist_sem");
99 // Spawn our thread-monitoring thread
100 fPicassoThreadID
= spawn_thread(PicassoThread
, "picasso", B_NORMAL_PRIORITY
, this);
101 if (fPicassoThreadID
>= 0)
102 resume_thread(fPicassoThreadID
);
108 Reached only when the server is asked to shut down in Test mode. Kills all apps, shuts down the
109 desktop, kills the housekeeping threads, etc.
111 AppServer::~AppServer()
117 \brief Thread function for watching for dead apps
118 \param data Pointer to the app_server to which the thread belongs
119 \return Throwaway value - always 0
122 AppServer::PicassoThread(void *data
)
125 acquire_sem(sAppServer
->fAppListLock
);
126 for (int32 i
= 0;;) {
127 ServerApp
*app
= (ServerApp
*)sAppServer
->fAppList
->ItemAt(i
++);
133 release_sem(sAppServer
->fAppListLock
);
134 // we do this every other second so as not to suck *too* many CPU cycles
142 \brief Starts Input Server
145 AppServer::LaunchInputServer()
151 \brief Starts the Cursor Thread
154 AppServer::LaunchCursorThread()
160 \brief The call that starts it all...
167 kill_thread(fPicassoThreadID
);
172 //! Main message-monitoring loop for the regular message port - no input messages!
174 AppServer::MainLoop(void)
176 BPrivate::PortLink
pmsg(-1, fMessagePort
);
179 STRACE(("info: AppServer::MainLoop listening on port %ld.\n", fMessagePort
));
182 status_t err
= pmsg
.GetNextMessage(code
);
184 STRACE(("MainLoop:pmsg.GetNextMessage() failed\n"));
189 case B_QUIT_REQUESTED
:
193 DispatchMessage(code
, pmsg
);
197 STRACE(("Server::MainLoop received unexpected code %ld\n",
206 \brief Message handling function for all messages sent to the app_server
207 \param code ID of the message sent
208 \param buffer Attachment buffer for the message.
212 AppServer::DispatchMessage(int32 code
, BPrivate::PortLink
&msg
)
218 if (msg
.Read
<port_id
>(&replyPort
) < B_OK
)
222 msg
.Read
<int32
>(&userID
);
224 BPrivate::LinkSender
reply(replyPort
);
225 reply
.StartMessage(B_OK
);
226 reply
.Attach
<port_id
>(fMessagePort
);
233 // Create the ServerApp to node monitor a new BApplication
236 // 1) port_id - receiver port of a regular app
237 // 2) port_id - client looper port - for send messages to the client
238 // 2) team_id - app's team ID
239 // 3) int32 - handler token of the regular app
240 // 4) char * - signature of the regular app
242 // Find the necessary data
243 team_id clientTeamID
= -1;
244 port_id clientLooperPort
= -1;
245 port_id clientReplyPort
= -1;
247 char *appSignature
= NULL
;
249 msg
.Read
<port_id
>(&clientReplyPort
);
250 msg
.Read
<port_id
>(&clientLooperPort
);
251 msg
.Read
<team_id
>(&clientTeamID
);
252 msg
.Read
<int32
>(&clientToken
);
253 if (msg
.ReadString(&appSignature
) != B_OK
)
256 port_id serverListen
= create_port(DEFAULT_MONITOR_PORT_SIZE
, appSignature
);
257 if (serverListen
< B_OK
) {
258 printf("No more ports left. Time to crash. Have a nice day! :)\n");
262 // we let the application own the port, so that we get aware when it's gone
263 if (set_port_owner(serverListen
, clientTeamID
) < B_OK
) {
264 delete_port(serverListen
);
265 printf("Could not transfer port ownership to client %ld!\n", clientTeamID
);
269 // Create the ServerApp subthread for this app
270 acquire_sem(fAppListLock
);
272 ServerApp
*app
= new ServerApp(clientReplyPort
, serverListen
, clientLooperPort
,
273 clientTeamID
, clientToken
, appSignature
);
275 // add the new ServerApp to the known list of ServerApps
276 fAppList
->AddItem(app
);
278 release_sem(fAppListLock
);
280 BPrivate::PortLink
replylink(clientReplyPort
);
281 replylink
.StartMessage(B_OK
);
282 replylink
.Attach
<int32
>(serverListen
);
285 // This is necessary because BPortLink::ReadString allocates memory
291 // Delete a ServerApp. Received only from the respective ServerApp when a
292 // BApplication asks it to quit.
295 // 1) thread_id - thread ID of the ServerApp to be deleted
297 int32 i
= 0, appnum
= fAppList
->CountItems();
298 ServerApp
*srvapp
= NULL
;
299 thread_id srvapp_id
= -1;
301 if (msg
.Read
<thread_id
>(&srvapp_id
) < B_OK
)
304 acquire_sem(fAppListLock
);
306 // Run through the list of apps and nuke the proper one
307 for (i
= 0; i
< appnum
; i
++) {
308 srvapp
= (ServerApp
*)fAppList
->ItemAt(i
);
310 if (srvapp
!= NULL
&& srvapp
->MonitorThreadID() == srvapp_id
) {
311 srvapp
= (ServerApp
*)fAppList
->RemoveItem(i
);
316 break; // jump out of our for() loop
320 release_sem(fAppListLock
);
324 case B_QUIT_REQUESTED
:
328 // we should never get here.
334 \brief Send a quick (no attachments) message to all applications
336 Quite useful for notification for things like server shutdown, system
340 AppServer::Broadcast(int32 code
)
342 acquire_sem(fAppListLock
);
344 for (int32 i
= 0; i
< fAppList
->CountItems(); i
++) {
345 ServerApp
*app
= (ServerApp
*)fAppList
->ItemAt(i
);
348 { printf("PANIC in AppServer::Broadcast()\n"); continue; }
349 app
->PostMessage(code
);
352 release_sem(fAppListLock
);
356 \brief Finds the application with the given signature
357 \param sig MIME signature of the application to find
358 \return the corresponding ServerApp or NULL if not found
360 This call should be made only when necessary because it locks the app list
361 while it does its searching.
364 AppServer::FindApp(const char *sig
)
369 ServerApp
*foundapp
=NULL
;
371 acquire_sem(fAppListLock
);
373 for(int32 i
=0; i
<fAppList
->CountItems();i
++)
375 foundapp
=(ServerApp
*)fAppList
->ItemAt(i
);
376 if(foundapp
&& foundapp
->Title() == sig
)
378 release_sem(fAppListLock
);
383 release_sem(fAppListLock
);
385 // couldn't find a match
394 \brief Entry function to run the entire server
395 \param argc Number of command-line arguments present
396 \param argv String array of the command-line arguments
397 \return -1 if the app_server is already running, 0 if everything's OK.
400 main(int argc
, char** argv
)
402 // There can be only one....
403 if (find_port(SERVER_PORT_NAME
) >= B_OK
)
406 AppServer app_server
;