xref: /haiku/src/servers/app/AppServer.cpp (revision 60a6f1d5d7a8715cd3897dd0b626f2e4a64984a8)
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 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
73 	// TODO: check the attached displays, and launch login session for them
74 	BMessage data;
75 	data.AddString("name", "app_server");
76 	data.AddInt32("session", 0);
77 	BLaunchRoster().Target("login", data);
78 #endif
79 }
80 
81 
82 /*!	\brief Destructor
83 	Reached only when the server is asked to shut down in Test mode.
84 */
85 AppServer::~AppServer()
86 {
87 	delete gBitmapManager;
88 
89 	gScreenManager->Lock();
90 	gScreenManager->Quit();
91 
92 	gFontManager->Lock();
93 	gFontManager->Quit();
94 
95 	closelog();
96 }
97 
98 
99 void
100 AppServer::MessageReceived(BMessage* message)
101 {
102 	switch (message->what) {
103 		case AS_GET_DESKTOP:
104 		{
105 			Desktop* desktop = NULL;
106 
107 			int32 userID = message->GetInt32("user", 0);
108 			int32 version = message->GetInt32("version", 0);
109 			const char* targetScreen = message->GetString("target");
110 
111 			if (version != AS_PROTOCOL_VERSION) {
112 				syslog(LOG_ERR, "Application for user %" B_PRId32 " does not "
113 					"support the current server protocol (%" B_PRId32 ").\n",
114 					userID, version);
115 			} else {
116 				desktop = _FindDesktop(userID, targetScreen);
117 				if (desktop == NULL) {
118 					// we need to create a new desktop object for this user
119 					// TODO: test if the user exists on the system
120 					// TODO: maybe have a separate AS_START_DESKTOP_SESSION for
121 					// authorizing the user
122 					desktop = _CreateDesktop(userID, targetScreen);
123 				}
124 			}
125 
126 			BMessage reply;
127 			if (desktop != NULL)
128 				reply.AddInt32("port", desktop->MessagePort());
129 			else
130 				reply.what = (uint32)B_ERROR;
131 
132 			message->SendReply(&reply);
133 			break;
134 		}
135 
136 		default:
137 			// We don't allow application scripting
138 			STRACE(("AppServer received unexpected code %" B_PRId32 "\n",
139 				message->what));
140 			break;
141 	}
142 }
143 
144 
145 bool
146 AppServer::QuitRequested()
147 {
148 #if TEST_MODE
149 	while (fDesktops.CountItems() > 0) {
150 		Desktop *desktop = fDesktops.RemoveItemAt(0);
151 
152 		thread_id thread = desktop->Thread();
153 		desktop->PostMessage(B_QUIT_REQUESTED);
154 
155 		// we just wait for the desktop to kill itself
156 		status_t status;
157 		wait_for_thread(thread, &status);
158 	}
159 
160 	delete this;
161 	exit(0);
162 
163 	return SERVER_BASE::QuitRequested();
164 #else
165 	return false;
166 #endif
167 
168 }
169 
170 
171 /*!	\brief Creates a desktop object for an authorized user
172 */
173 Desktop*
174 AppServer::_CreateDesktop(uid_t userID, const char* targetScreen)
175 {
176 	BAutolock locker(fDesktopLock);
177 	Desktop* desktop = NULL;
178 	try {
179 		desktop = new Desktop(userID, targetScreen);
180 
181 		status_t status = desktop->Init();
182 		if (status == B_OK)
183 			status = desktop->Run();
184 		if (status == B_OK && !fDesktops.AddItem(desktop))
185 			status = B_NO_MEMORY;
186 
187 		if (status != B_OK) {
188 			syslog(LOG_ERR, "Cannot initialize Desktop object: %s\n",
189 				strerror(status));
190 			delete desktop;
191 			return NULL;
192 		}
193 	} catch (...) {
194 		// there is obviously no memory left
195 		return NULL;
196 	}
197 
198 	return desktop;
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