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