1 /* 2 * Copyright 2001-2015, 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 * Christian Packmann 10 */ 11 12 13 #include "AppServer.h" 14 15 #include <syslog.h> 16 17 #include <LaunchRoster.h> 18 #include <PortLink.h> 19 20 #include "BitmapManager.h" 21 #include "Desktop.h" 22 #include "FontManager.h" 23 #include "InputManager.h" 24 #include "ScreenManager.h" 25 #include "ServerProtocol.h" 26 27 28 //#define DEBUG_SERVER 29 #ifdef DEBUG_SERVER 30 # include <stdio.h> 31 # define STRACE(x) printf x 32 #else 33 # define STRACE(x) ; 34 #endif 35 36 37 // Globals 38 port_id gAppServerPort; 39 BTokenSpace gTokenSpace; 40 uint32 gAppServerSIMDFlags = 0; 41 42 43 /*! \brief Constructor 44 45 This loads the default fonts, allocates all the major global variables, 46 spawns the main housekeeping threads, loads user preferences for the UI 47 and decorator, and allocates various locks. 48 */ 49 AppServer::AppServer(status_t* status) 50 : 51 SERVER_BASE("application/x-vnd.Haiku-app_server", "picasso", -1, false, 52 status), 53 fDesktopLock("AppServerDesktopLock") 54 { 55 openlog("app_server", 0, LOG_DAEMON); 56 57 gInputManager = new InputManager(); 58 59 // Create the font server and scan the proper directories. 60 gFontManager = new FontManager; 61 if (gFontManager->InitCheck() != B_OK) 62 debugger("font manager could not be initialized!"); 63 64 gFontManager->Run(); 65 66 gScreenManager = new ScreenManager(); 67 gScreenManager->Run(); 68 69 // Create the bitmap allocator. Object declared in BitmapManager.cpp 70 gBitmapManager = new BitmapManager(); 71 72 // TODO: check the attached displays, and launch login session for them 73 BMessage data; 74 data.AddString("name", "app_server"); 75 data.AddInt32("session", 0); 76 BLaunchRoster().Target("login", data); 77 } 78 79 80 /*! \brief Destructor 81 Reached only when the server is asked to shut down in Test mode. 82 */ 83 AppServer::~AppServer() 84 { 85 delete gBitmapManager; 86 87 gScreenManager->Lock(); 88 gScreenManager->Quit(); 89 90 gFontManager->Lock(); 91 gFontManager->Quit(); 92 93 closelog(); 94 } 95 96 97 void 98 AppServer::MessageReceived(BMessage* message) 99 { 100 switch (message->what) { 101 case AS_GET_DESKTOP: 102 { 103 Desktop* desktop = NULL; 104 105 int32 userID = message->GetInt32("user", 0); 106 int32 version = message->GetInt32("version", 0); 107 const char* targetScreen = message->GetString("target"); 108 109 if (version != AS_PROTOCOL_VERSION) { 110 syslog(LOG_ERR, "Application for user %" B_PRId32 " does not " 111 "support the current server protocol.\n", userID); 112 } else { 113 desktop = _FindDesktop(userID, targetScreen); 114 if (desktop == NULL) { 115 // we need to create a new desktop object for this user 116 // TODO: test if the user exists on the system 117 // TODO: maybe have a separate AS_START_DESKTOP_SESSION for 118 // authorizing the user 119 desktop = _CreateDesktop(userID, targetScreen); 120 } 121 } 122 123 BMessage reply; 124 if (desktop != NULL) 125 reply.AddInt32("port", desktop->MessagePort()); 126 else 127 reply.what = (uint32)B_ERROR; 128 129 message->SendReply(&reply); 130 break; 131 } 132 133 default: 134 // We don't allow application scripting 135 STRACE(("AppServer received unexpected code %" B_PRId32 "\n", 136 message->what)); 137 break; 138 } 139 } 140 141 142 bool 143 AppServer::QuitRequested() 144 { 145 #if TEST_MODE 146 while (fDesktops.CountItems() > 0) { 147 Desktop *desktop = fDesktops.RemoveItemAt(0); 148 149 thread_id thread = desktop->Thread(); 150 desktop->PostMessage(B_QUIT_REQUESTED); 151 152 // we just wait for the desktop to kill itself 153 status_t status; 154 wait_for_thread(thread, &status); 155 } 156 157 delete this; 158 exit(0); 159 160 return SERVER_BASE::QuitRequested(); 161 #else 162 return false; 163 #endif 164 165 } 166 167 168 /*! \brief Creates a desktop object for an authorized user 169 */ 170 Desktop* 171 AppServer::_CreateDesktop(uid_t userID, const char* targetScreen) 172 { 173 BAutolock locker(fDesktopLock); 174 Desktop* desktop = NULL; 175 try { 176 desktop = new Desktop(userID, targetScreen); 177 178 status_t status = desktop->Init(); 179 if (status == B_OK) { 180 if (!desktop->Run()) 181 status = B_ERROR; 182 } 183 if (status == B_OK && !fDesktops.AddItem(desktop)) 184 status = B_NO_MEMORY; 185 186 if (status != B_OK) { 187 syslog(LOG_ERR, "Cannot initialize Desktop object: %s\n", 188 strerror(status)); 189 delete desktop; 190 return NULL; 191 } 192 } catch (...) { 193 // there is obviously no memory left 194 return NULL; 195 } 196 197 return desktop; 198 } 199 200 201 /*! \brief Finds the desktop object that belongs to a certain user 202 */ 203 Desktop* 204 AppServer::_FindDesktop(uid_t userID, const char* targetScreen) 205 { 206 BAutolock locker(fDesktopLock); 207 208 for (int32 i = 0; i < fDesktops.CountItems(); i++) { 209 Desktop* desktop = fDesktops.ItemAt(i); 210 211 if (desktop->UserID() == userID 212 && ((desktop->TargetScreen() == NULL && targetScreen == NULL) 213 || (desktop->TargetScreen() != NULL && targetScreen != NULL 214 && strcmp(desktop->TargetScreen(), targetScreen) == 0))) { 215 return desktop; 216 } 217 } 218 219 return NULL; 220 } 221 222 223 // #pragma mark - 224 225 226 int 227 main(int argc, char** argv) 228 { 229 srand(real_time_clock_usecs()); 230 231 status_t status; 232 AppServer* server = new AppServer(&status); 233 if (status == B_OK) 234 server->Run(); 235 236 return status == B_OK ? EXIT_SUCCESS : EXIT_FAILURE; 237 } 238