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 <AutoDeleter.h> 18 #include <LaunchRoster.h> 19 #include <PortLink.h> 20 21 #include "BitmapManager.h" 22 #include "Desktop.h" 23 #include "FontManager.h" 24 #include "InputManager.h" 25 #include "ScreenManager.h" 26 #include "ServerProtocol.h" 27 28 29 //#define DEBUG_SERVER 30 #ifdef DEBUG_SERVER 31 # include <stdio.h> 32 # define STRACE(x) printf x 33 #else 34 # define STRACE(x) ; 35 #endif 36 37 38 // Globals 39 port_id gAppServerPort; 40 BTokenSpace gTokenSpace; 41 uint32 gAppServerSIMDFlags = 0; 42 43 44 /*! \brief Constructor 45 46 This loads the default fonts, allocates all the major global variables, 47 spawns the main housekeeping threads, loads user preferences for the UI 48 and decorator, and allocates various locks. 49 */ 50 AppServer::AppServer(status_t* status) 51 : 52 SERVER_BASE("application/x-vnd.Haiku-app_server", "picasso", -1, false, 53 status), 54 fDesktopLock("AppServerDesktopLock") 55 { 56 openlog("app_server", 0, LOG_DAEMON); 57 58 gInputManager = new InputManager(); 59 60 // Create the font server and scan the proper directories. 61 gFontManager = new FontManager; 62 if (gFontManager->InitCheck() != B_OK) 63 debugger("font manager could not be initialized!"); 64 65 gFontManager->Run(); 66 67 gScreenManager = new ScreenManager(); 68 gScreenManager->Run(); 69 70 // Create the bitmap allocator. Object declared in BitmapManager.cpp 71 gBitmapManager = new BitmapManager(); 72 73 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 74 // TODO: check the attached displays, and launch login session for them 75 BMessage data; 76 data.AddString("name", "app_server"); 77 data.AddInt32("session", 0); 78 BLaunchRoster().Target("login", data); 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 void 101 AppServer::MessageReceived(BMessage* message) 102 { 103 switch (message->what) { 104 case AS_GET_DESKTOP: 105 { 106 Desktop* desktop = NULL; 107 108 int32 userID = message->GetInt32("user", 0); 109 int32 version = message->GetInt32("version", 0); 110 const char* targetScreen = message->GetString("target"); 111 112 if (version != AS_PROTOCOL_VERSION) { 113 syslog(LOG_ERR, "Application for user %" B_PRId32 " does not " 114 "support the current server protocol (%" B_PRId32 ").\n", 115 userID, version); 116 } else { 117 desktop = _FindDesktop(userID, targetScreen); 118 if (desktop == NULL) { 119 // we need to create a new desktop object for this user 120 // TODO: test if the user exists on the system 121 // TODO: maybe have a separate AS_START_DESKTOP_SESSION for 122 // authorizing the user 123 desktop = _CreateDesktop(userID, targetScreen); 124 } 125 } 126 127 BMessage reply; 128 if (desktop != NULL) 129 reply.AddInt32("port", desktop->MessagePort()); 130 else 131 reply.what = (uint32)B_ERROR; 132 133 message->SendReply(&reply); 134 break; 135 } 136 137 default: 138 // We don't allow application scripting 139 STRACE(("AppServer received unexpected code %" B_PRId32 "\n", 140 message->what)); 141 break; 142 } 143 } 144 145 146 bool 147 AppServer::QuitRequested() 148 { 149 #if TEST_MODE 150 while (fDesktops.CountItems() > 0) { 151 Desktop *desktop = fDesktops.RemoveItemAt(0); 152 153 thread_id thread = desktop->Thread(); 154 desktop->PostMessage(B_QUIT_REQUESTED); 155 156 // we just wait for the desktop to kill itself 157 status_t status; 158 wait_for_thread(thread, &status); 159 } 160 161 delete this; 162 exit(0); 163 164 return SERVER_BASE::QuitRequested(); 165 #else 166 return false; 167 #endif 168 169 } 170 171 172 /*! \brief Creates a desktop object for an authorized user 173 */ 174 Desktop* 175 AppServer::_CreateDesktop(uid_t userID, const char* targetScreen) 176 { 177 BAutolock locker(fDesktopLock); 178 ObjectDeleter<Desktop> desktop; 179 try { 180 desktop.SetTo(new Desktop(userID, targetScreen)); 181 182 status_t status = desktop->Init(); 183 if (status == B_OK) 184 status = desktop->Run(); 185 if (status == B_OK && !fDesktops.AddItem(desktop.Get())) 186 status = B_NO_MEMORY; 187 188 if (status != B_OK) { 189 syslog(LOG_ERR, "Cannot initialize Desktop object: %s\n", 190 strerror(status)); 191 return NULL; 192 } 193 } catch (...) { 194 // there is obviously no memory left 195 return NULL; 196 } 197 198 return desktop.Detach(); 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