xref: /haiku/src/servers/app/AppServer.cpp (revision 79d6f0870e70cb72a2bbd7910e05cb531335e9b7)
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 	// 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 (%" B_PRId32 ").\n",
112 					userID, version);
113 			} else {
114 				desktop = _FindDesktop(userID, targetScreen);
115 				if (desktop == NULL) {
116 					// we need to create a new desktop object for this user
117 					// TODO: test if the user exists on the system
118 					// TODO: maybe have a separate AS_START_DESKTOP_SESSION for
119 					// authorizing the user
120 					desktop = _CreateDesktop(userID, targetScreen);
121 				}
122 			}
123 
124 			BMessage reply;
125 			if (desktop != NULL)
126 				reply.AddInt32("port", desktop->MessagePort());
127 			else
128 				reply.what = (uint32)B_ERROR;
129 
130 			message->SendReply(&reply);
131 			break;
132 		}
133 
134 		default:
135 			// We don't allow application scripting
136 			STRACE(("AppServer received unexpected code %" B_PRId32 "\n",
137 				message->what));
138 			break;
139 	}
140 }
141 
142 
143 bool
144 AppServer::QuitRequested()
145 {
146 #if TEST_MODE
147 	while (fDesktops.CountItems() > 0) {
148 		Desktop *desktop = fDesktops.RemoveItemAt(0);
149 
150 		thread_id thread = desktop->Thread();
151 		desktop->PostMessage(B_QUIT_REQUESTED);
152 
153 		// we just wait for the desktop to kill itself
154 		status_t status;
155 		wait_for_thread(thread, &status);
156 	}
157 
158 	delete this;
159 	exit(0);
160 
161 	return SERVER_BASE::QuitRequested();
162 #else
163 	return false;
164 #endif
165 
166 }
167 
168 
169 /*!	\brief Creates a desktop object for an authorized user
170 */
171 Desktop*
172 AppServer::_CreateDesktop(uid_t userID, const char* targetScreen)
173 {
174 	BAutolock locker(fDesktopLock);
175 	Desktop* desktop = NULL;
176 	try {
177 		desktop = new Desktop(userID, targetScreen);
178 
179 		status_t status = desktop->Init();
180 		if (status == B_OK)
181 			status = desktop->Run();
182 		if (status == B_OK && !fDesktops.AddItem(desktop))
183 			status = B_NO_MEMORY;
184 
185 		if (status != B_OK) {
186 			syslog(LOG_ERR, "Cannot initialize Desktop object: %s\n",
187 				strerror(status));
188 			delete desktop;
189 			return NULL;
190 		}
191 	} catch (...) {
192 		// there is obviously no memory left
193 		return NULL;
194 	}
195 
196 	return desktop;
197 }
198 
199 
200 /*!	\brief Finds the desktop object that belongs to a certain user
201 */
202 Desktop*
203 AppServer::_FindDesktop(uid_t userID, const char* targetScreen)
204 {
205 	BAutolock locker(fDesktopLock);
206 
207 	for (int32 i = 0; i < fDesktops.CountItems(); i++) {
208 		Desktop* desktop = fDesktops.ItemAt(i);
209 
210 		if (desktop->UserID() == userID
211 			&& ((desktop->TargetScreen() == NULL && targetScreen == NULL)
212 				|| (desktop->TargetScreen() != NULL && targetScreen != NULL
213 					&& strcmp(desktop->TargetScreen(), targetScreen) == 0))) {
214 			return desktop;
215 		}
216 	}
217 
218 	return NULL;
219 }
220 
221 
222 //	#pragma mark -
223 
224 
225 int
226 main(int argc, char** argv)
227 {
228 	srand(real_time_clock_usecs());
229 
230 	status_t status;
231 	AppServer* server = new AppServer(&status);
232 	if (status == B_OK)
233 		server->Run();
234 
235 	return status == B_OK ? EXIT_SUCCESS : EXIT_FAILURE;
236 }
237