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
39port_id gAppServerPort;
40BTokenSpace gTokenSpace;
41uint32 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*/
50AppServer::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*/
89AppServer::~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
103void
104AppServer::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
149bool
150AppServer::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*/
177Desktop*
178AppServer::_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*/
207Desktop*
208AppServer::_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
230int
231main(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