1 /* 2 * Copyright (c) 2001-2006, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 * Axel Dörfler, axeld@pinc-software.de 8 * Stephan Aßmus <superstippi@gmx.de> 9 */ 10 11 12 #include "AppServer.h" 13 14 #include "BitmapManager.h" 15 #include "Desktop.h" 16 #include "FontManager.h" 17 #include "InputManager.h" 18 #include "ScreenManager.h" 19 #include "ServerProtocol.h" 20 #include "SystemPalette.h" 21 22 #include <PortLink.h> 23 24 25 //#define DEBUG_SERVER 26 #ifdef DEBUG_SERVER 27 # include <stdio.h> 28 # define STRACE(x) printf x 29 #else 30 # define STRACE(x) ; 31 #endif 32 33 34 // Globals 35 port_id gAppServerPort; 36 static AppServer *sAppServer; 37 BTokenSpace gTokenSpace; 38 39 40 /*! 41 \brief Constructor 42 43 This loads the default fonts, allocates all the major global variables, spawns the main housekeeping 44 threads, loads user preferences for the UI and decorator, and allocates various locks. 45 */ 46 AppServer::AppServer() 47 : MessageLooper("app_server"), 48 fMessagePort(-1), 49 fDesktops(), 50 fDesktopLock("AppServerDesktopLock") 51 { 52 fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, SERVER_PORT_NAME); 53 if (fMessagePort < B_OK) 54 debugger("app_server could not create message port"); 55 56 fLink.SetReceiverPort(fMessagePort); 57 58 sAppServer = this; 59 60 gInputManager = new InputManager(); 61 62 // Create the font server and scan the proper directories. 63 gFontManager = new FontManager; 64 if (gFontManager->InitCheck() != B_OK) 65 debugger("font manager could not be initialized!"); 66 67 gFontManager->Run(); 68 69 gScreenManager = new ScreenManager(); 70 gScreenManager->Run(); 71 72 // the system palette needs to be initialized before the desktop, 73 // since it is used there already 74 InitializeColorMap(); 75 76 // Create the bitmap allocator. Object declared in BitmapManager.cpp 77 gBitmapManager = new BitmapManager(); 78 79 #if 0 80 _LaunchCursorThread(); 81 #endif 82 } 83 84 /*! 85 \brief Destructor 86 Reached only when the server is asked to shut down in Test mode. 87 */ 88 AppServer::~AppServer() 89 { 90 delete gBitmapManager; 91 92 gScreenManager->Lock(); 93 gScreenManager->Quit(); 94 95 gFontManager->Lock(); 96 gFontManager->Quit(); 97 } 98 99 100 /*! 101 \brief The call that starts it all... 102 */ 103 void 104 AppServer::RunLooper() 105 { 106 rename_thread(find_thread(NULL), "picasso"); 107 _message_thread((void *)this); 108 } 109 110 111 #if 0 112 /*! 113 \brief Starts Input Server 114 */ 115 void 116 AppServer::_LaunchInputServer() 117 { 118 // We are supposed to start the input_server, but it's a BApplication 119 // that depends on the registrar running, which is started after app_server 120 // so we wait on roster thread to launch the input server 121 122 fISThreadID = B_ERROR; 123 124 while (!BRoster::Private().IsMessengerValid(false) && !fQuitting) { 125 snooze(250000); 126 BRoster::Private::DeleteBeRoster(); 127 BRoster::Private::InitBeRoster(); 128 } 129 130 if (fQuitting) 131 return; 132 133 // we use an area for cursor data communication with input_server 134 // area id and sem id are sent to the input_server 135 136 if (fCursorArea < B_OK) 137 fCursorArea = create_area("isCursor", (void**) &fCursorAddr, B_ANY_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA); 138 if (fCursorSem < B_OK) 139 fCursorSem = create_sem(0, "isSem"); 140 141 int32 arg_c = 1; 142 char **arg_v = (char **)malloc(sizeof(char *) * (arg_c + 1)); 143 #if TEST_MODE 144 arg_v[0] = strdup("/boot/home/svnhaiku/trunk/distro/x86.R1/beos/system/servers/input_server"); 145 #else 146 arg_v[0] = strdup("/system/servers/input_server"); 147 #endif 148 arg_v[1] = NULL; 149 fISThreadID = load_image(arg_c, (const char**)arg_v, (const char **)environ); 150 free(arg_v[0]); 151 152 int32 tmpbuf[2] = {fCursorSem, fCursorArea}; 153 int32 code = 0; 154 send_data(fISThreadID, code, (void *)tmpbuf, sizeof(tmpbuf)); 155 156 resume_thread(fISThreadID); 157 setpgid(fISThreadID, 0); 158 159 // we receive 160 161 thread_id sender; 162 code = receive_data(&sender, (void *)tmpbuf, sizeof(tmpbuf)); 163 fISASPort = tmpbuf[0]; 164 fISPort = tmpbuf[1]; 165 166 // if at any time, one of these ports is error prone, it might mean input_server is gone 167 // then relaunch input_server 168 } 169 #endif 170 171 172 /*! 173 \brief Creates a desktop object for an authorized user 174 */ 175 Desktop * 176 AppServer::_CreateDesktop(uid_t userID) 177 { 178 BAutolock locker(fDesktopLock); 179 Desktop* desktop = NULL; 180 try { 181 desktop = new Desktop(userID); 182 183 status_t status = desktop->Init(); 184 if (status == B_OK) { 185 if (!desktop->Run()) 186 status = B_ERROR; 187 } 188 if (status == B_OK && !fDesktops.AddItem(desktop)) 189 status = B_NO_MEMORY; 190 191 if (status < B_OK) { 192 fprintf(stderr, "Cannot initialize Desktop object: %s\n", strerror(status)); 193 delete desktop; 194 return NULL; 195 } 196 } catch (...) { 197 // there is obviously no memory left 198 return NULL; 199 } 200 201 return desktop; 202 } 203 204 205 /*! 206 \brief Finds the desktop object that belongs to a certain user 207 */ 208 Desktop * 209 AppServer::_FindDesktop(uid_t userID) 210 { 211 BAutolock locker(fDesktopLock); 212 213 for (int32 i = 0; i < fDesktops.CountItems(); i++) { 214 Desktop* desktop = fDesktops.ItemAt(i); 215 216 if (desktop->UserID() == userID) 217 return desktop; 218 } 219 220 return NULL; 221 } 222 223 224 /*! 225 \brief Message handling function for all messages sent to the app_server 226 \param code ID of the message sent 227 \param buffer Attachment buffer for the message. 228 229 */ 230 void 231 AppServer::_DispatchMessage(int32 code, BPrivate::LinkReceiver& msg) 232 { 233 switch (code) { 234 case AS_GET_DESKTOP: 235 { 236 port_id replyPort; 237 if (msg.Read<port_id>(&replyPort) < B_OK) 238 break; 239 240 int32 userID; 241 msg.Read<int32>(&userID); 242 243 Desktop* desktop = _FindDesktop(userID); 244 if (desktop == NULL) { 245 // we need to create a new desktop object for this user 246 // ToDo: test if the user exists on the system 247 // ToDo: maybe have a separate AS_START_DESKTOP_SESSION for authorizing the user 248 desktop = _CreateDesktop(userID); 249 } 250 251 BPrivate::LinkSender reply(replyPort); 252 reply.StartMessage(B_OK); 253 reply.Attach<port_id>(desktop->MessagePort()); 254 reply.Flush(); 255 break; 256 } 257 258 #if TEST_MODE 259 case B_QUIT_REQUESTED: 260 { 261 // We've been asked to quit, so (for now) broadcast to all 262 // desktops to quit. This situation will occur only when the server 263 // is compiled as a regular Be application. 264 265 fQuitting = true; 266 267 while (fDesktops.CountItems() > 0) { 268 Desktop *desktop = fDesktops.RemoveItemAt(0); 269 270 thread_id thread = desktop->Thread(); 271 desktop->PostMessage(B_QUIT_REQUESTED); 272 273 // we just wait for the desktop to kill itself 274 status_t status; 275 wait_for_thread(thread, &status); 276 } 277 278 delete this; 279 280 // we are now clear to exit 281 exit_thread(0); 282 break; 283 } 284 #endif 285 286 default: 287 STRACE(("Server::MainLoop received unexpected code %ld (offset %ld)\n", 288 code, code - SERVER_TRUE)); 289 break; 290 } 291 } 292 293 294 // #pragma mark - 295 296 297 /*! 298 \brief Entry function to run the entire server 299 \param argc Number of command-line arguments present 300 \param argv String array of the command-line arguments 301 \return -1 if the app_server is already running, 0 if everything's OK. 302 */ 303 int 304 main(int argc, char** argv) 305 { 306 // There can be only one.... 307 if (find_port(SERVER_PORT_NAME) >= B_OK) 308 return -1; 309 310 srand(real_time_clock_usecs()); 311 312 AppServer* server = new AppServer; 313 server->RunLooper(); 314 315 return 0; 316 } 317