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