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