xref: /haiku/src/servers/app/AppServer.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
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