1 /* 2 * Copyright (c) 2001-2007, 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 21 #include <PortLink.h> 22 23 #include <syslog.h> 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 openlog("app_server", 0, LOG_DAEMON); 53 54 fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, SERVER_PORT_NAME); 55 if (fMessagePort < B_OK) 56 debugger("app_server could not create message port"); 57 58 fLink.SetReceiverPort(fMessagePort); 59 60 sAppServer = this; 61 62 gInputManager = new InputManager(); 63 64 // Create the font server and scan the proper directories. 65 gFontManager = new FontManager; 66 if (gFontManager->InitCheck() != B_OK) 67 debugger("font manager could not be initialized!"); 68 69 gFontManager->Run(); 70 71 gScreenManager = new ScreenManager(); 72 gScreenManager->Run(); 73 74 // Create the bitmap allocator. Object declared in BitmapManager.cpp 75 gBitmapManager = new BitmapManager(); 76 77 #if 0 78 _LaunchCursorThread(); 79 #endif 80 } 81 82 /*! 83 \brief Destructor 84 Reached only when the server is asked to shut down in Test mode. 85 */ 86 AppServer::~AppServer() 87 { 88 delete gBitmapManager; 89 90 gScreenManager->Lock(); 91 gScreenManager->Quit(); 92 93 gFontManager->Lock(); 94 gFontManager->Quit(); 95 96 closelog(); 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 /*! 112 \brief Creates a desktop object for an authorized user 113 */ 114 Desktop * 115 AppServer::_CreateDesktop(uid_t userID) 116 { 117 BAutolock locker(fDesktopLock); 118 Desktop* desktop = NULL; 119 try { 120 desktop = new Desktop(userID); 121 122 status_t status = desktop->Init(); 123 if (status == B_OK) { 124 if (!desktop->Run()) 125 status = B_ERROR; 126 } 127 if (status == B_OK && !fDesktops.AddItem(desktop)) 128 status = B_NO_MEMORY; 129 130 if (status < B_OK) { 131 fprintf(stderr, "Cannot initialize Desktop object: %s\n", strerror(status)); 132 delete desktop; 133 return NULL; 134 } 135 } catch (...) { 136 // there is obviously no memory left 137 return NULL; 138 } 139 140 return desktop; 141 } 142 143 144 /*! 145 \brief Finds the desktop object that belongs to a certain user 146 */ 147 Desktop * 148 AppServer::_FindDesktop(uid_t userID) 149 { 150 BAutolock locker(fDesktopLock); 151 152 for (int32 i = 0; i < fDesktops.CountItems(); i++) { 153 Desktop* desktop = fDesktops.ItemAt(i); 154 155 if (desktop->UserID() == userID) 156 return desktop; 157 } 158 159 return NULL; 160 } 161 162 163 /*! 164 \brief Message handling function for all messages sent to the app_server 165 \param code ID of the message sent 166 \param buffer Attachment buffer for the message. 167 168 */ 169 void 170 AppServer::_DispatchMessage(int32 code, BPrivate::LinkReceiver& msg) 171 { 172 switch (code) { 173 case AS_GET_DESKTOP: 174 { 175 port_id replyPort; 176 if (msg.Read<port_id>(&replyPort) < B_OK) 177 break; 178 179 int32 userID; 180 msg.Read<int32>(&userID); 181 182 Desktop* desktop = _FindDesktop(userID); 183 if (desktop == NULL) { 184 // we need to create a new desktop object for this user 185 // ToDo: test if the user exists on the system 186 // ToDo: maybe have a separate AS_START_DESKTOP_SESSION for authorizing the user 187 desktop = _CreateDesktop(userID); 188 } 189 190 BPrivate::LinkSender reply(replyPort); 191 if (desktop != NULL) { 192 reply.StartMessage(B_OK); 193 reply.Attach<port_id>(desktop->MessagePort()); 194 } else 195 reply.StartMessage(B_ERROR); 196 197 reply.Flush(); 198 break; 199 } 200 201 #if TEST_MODE 202 case B_QUIT_REQUESTED: 203 { 204 // We've been asked to quit, so (for now) broadcast to all 205 // desktops to quit. This situation will occur only when the server 206 // is compiled as a regular Be application. 207 208 fQuitting = true; 209 210 while (fDesktops.CountItems() > 0) { 211 Desktop *desktop = fDesktops.RemoveItemAt(0); 212 213 thread_id thread = desktop->Thread(); 214 desktop->PostMessage(B_QUIT_REQUESTED); 215 216 // we just wait for the desktop to kill itself 217 status_t status; 218 wait_for_thread(thread, &status); 219 } 220 221 delete this; 222 223 // we are now clear to exit 224 exit(0); 225 break; 226 } 227 #endif 228 229 default: 230 STRACE(("Server::MainLoop received unexpected code %ld (offset %ld)\n", 231 code, code - SERVER_TRUE)); 232 break; 233 } 234 } 235 236 237 // #pragma mark - 238 239 240 int 241 main(int argc, char** argv) 242 { 243 // There can be only one.... 244 if (find_port(SERVER_PORT_NAME) >= B_OK) 245 return -1; 246 247 srand(real_time_clock_usecs()); 248 249 AppServer* server = new AppServer; 250 server->RunLooper(); 251 252 return 0; 253 } 254