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