1 /* 2 * Copyright 2001-2016, 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 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 73 // TODO: check the attached displays, and launch login session for them 74 BMessage data; 75 data.AddString("name", "app_server"); 76 data.AddInt32("session", 0); 77 BLaunchRoster().Target("login", data); 78 #endif 79 } 80 81 82 /*! \brief Destructor 83 Reached only when the server is asked to shut down in Test mode. 84 */ 85 AppServer::~AppServer() 86 { 87 delete gBitmapManager; 88 89 gScreenManager->Lock(); 90 gScreenManager->Quit(); 91 92 gFontManager->Lock(); 93 gFontManager->Quit(); 94 95 closelog(); 96 } 97 98 99 void 100 AppServer::MessageReceived(BMessage* message) 101 { 102 switch (message->what) { 103 case AS_GET_DESKTOP: 104 { 105 Desktop* desktop = NULL; 106 107 int32 userID = message->GetInt32("user", 0); 108 int32 version = message->GetInt32("version", 0); 109 const char* targetScreen = message->GetString("target"); 110 111 if (version != AS_PROTOCOL_VERSION) { 112 syslog(LOG_ERR, "Application for user %" B_PRId32 " does not " 113 "support the current server protocol (%" B_PRId32 ").\n", 114 userID, version); 115 } else { 116 desktop = _FindDesktop(userID, targetScreen); 117 if (desktop == NULL) { 118 // we need to create a new desktop object for this user 119 // TODO: test if the user exists on the system 120 // TODO: maybe have a separate AS_START_DESKTOP_SESSION for 121 // authorizing the user 122 desktop = _CreateDesktop(userID, targetScreen); 123 } 124 } 125 126 BMessage reply; 127 if (desktop != NULL) 128 reply.AddInt32("port", desktop->MessagePort()); 129 else 130 reply.what = (uint32)B_ERROR; 131 132 message->SendReply(&reply); 133 break; 134 } 135 136 default: 137 // We don't allow application scripting 138 STRACE(("AppServer received unexpected code %" B_PRId32 "\n", 139 message->what)); 140 break; 141 } 142 } 143 144 145 bool 146 AppServer::QuitRequested() 147 { 148 #if TEST_MODE 149 while (fDesktops.CountItems() > 0) { 150 Desktop *desktop = fDesktops.RemoveItemAt(0); 151 152 thread_id thread = desktop->Thread(); 153 desktop->PostMessage(B_QUIT_REQUESTED); 154 155 // we just wait for the desktop to kill itself 156 status_t status; 157 wait_for_thread(thread, &status); 158 } 159 160 delete this; 161 exit(0); 162 163 return SERVER_BASE::QuitRequested(); 164 #else 165 return false; 166 #endif 167 168 } 169 170 171 /*! \brief Creates a desktop object for an authorized user 172 */ 173 Desktop* 174 AppServer::_CreateDesktop(uid_t userID, const char* targetScreen) 175 { 176 BAutolock locker(fDesktopLock); 177 Desktop* desktop = NULL; 178 try { 179 desktop = new Desktop(userID, targetScreen); 180 181 status_t status = desktop->Init(); 182 if (status == B_OK) 183 status = desktop->Run(); 184 if (status == B_OK && !fDesktops.AddItem(desktop)) 185 status = B_NO_MEMORY; 186 187 if (status != B_OK) { 188 syslog(LOG_ERR, "Cannot initialize Desktop object: %s\n", 189 strerror(status)); 190 delete desktop; 191 return NULL; 192 } 193 } catch (...) { 194 // there is obviously no memory left 195 return NULL; 196 } 197 198 return desktop; 199 } 200 201 202 /*! \brief Finds the desktop object that belongs to a certain user 203 */ 204 Desktop* 205 AppServer::_FindDesktop(uid_t userID, const char* targetScreen) 206 { 207 BAutolock locker(fDesktopLock); 208 209 for (int32 i = 0; i < fDesktops.CountItems(); i++) { 210 Desktop* desktop = fDesktops.ItemAt(i); 211 212 if (desktop->UserID() == userID 213 && ((desktop->TargetScreen() == NULL && targetScreen == NULL) 214 || (desktop->TargetScreen() != NULL && targetScreen != NULL 215 && strcmp(desktop->TargetScreen(), targetScreen) == 0))) { 216 return desktop; 217 } 218 } 219 220 return NULL; 221 } 222 223 224 // #pragma mark - 225 226 227 int 228 main(int argc, char** argv) 229 { 230 srand(real_time_clock_usecs()); 231 232 status_t status; 233 AppServer* server = new AppServer(&status); 234 if (status == B_OK) 235 server->Run(); 236 237 return status == B_OK ? EXIT_SUCCESS : EXIT_FAILURE; 238 } 239