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
38port_id gAppServerPort;
39BTokenSpace gTokenSpace;
40uint32 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*/
49AppServer::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*/
83AppServer::~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
97void
98AppServer::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
143bool
144AppServer::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*/
171Desktop*
172AppServer::_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*/
202Desktop*
203AppServer::_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
225int
226main(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